All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jamonapi.proxy.MonProxyFactoryImp Maven / Gradle / Ivy

There is a newer version: 2.82
Show newest version
package com.jamonapi.proxy;


import com.jamonapi.JAMonBufferListener;
import com.jamonapi.JAMonListener;
import com.jamonapi.Monitor;
import com.jamonapi.MonitorFactory;

import java.lang.reflect.Proxy;
import java.sql.*;
import java.util.*;

/**
 * MonProxyFactory allows developers to monitor ANY interface by simply passing the Object implementing
 * the interface to the monitor method.  (note the object passed MUST implement an interface or it will
 * be a runtime error).  A great use of this is to monitor jdbc interfaces and to aid in this there are
 * overloaded methods that take Connections, Statements, PreparedStatements, CallableStatements, and
 * ResultSets.  These overloaded methods take advantage of knowledege of SQL and track additional statistics.
 * The following capabilities can be acquired by using MonProxyFactory.  All can individually be enabled/disabled.
 * 
 * 

This is a nonstatic version and is the primary implementation. The static version MonProxyFactory simply calls this version

*
    *
  1. Overall monitoring can be enabled/disabled by calling MonProxyFactory.enable(...). This will enable/disable monitors. * You can start out by enabling all monitors and disabling the ones you wish or vice versa. * *
  2. All methods of a given interface will have a jamon rows. Any jamon row will have the label (in this * case the method signature), hits, avg/min/max execution time, active/avg active/max active, last value and * more. By default interface monitoring is on. It can be enabled/disabled by calling MonProxyFactory.enableInterfaceM(...). * JDBC classes such as Connections, Statements, PreparedStatemetns, CallableStatements, and ResultsSets * will also automatically be monitored if the class returning them was monitored. If you don't wish this * to occur then you can use the monitor method that takes an Object. * *
  3. ResultSet interfaces can be monitored however methods like getObject and next are called so much and * typically don't cause performance problems, so there is a seperate enable/disable capability for them. Note for * ResultSet monitoring to occur interface monitoring must also be enabled. * However it can be enabled if interface monitoring is enabled and MonProxyFactory.enabledResultSets(true) is called. * ResultSet's are by default not monitored. * *
  4. SQLSummary will add a jamon row for all sql text issued against a PreparedStatement, CallableStatement, * or Statement. Argument values are replaced with ? for Statements to ensure the logical queries are matched. * PreparedStatements need not be changed to do this, but Statements may look a little different * For example: select * from table where name='jeff beck' would become select * from table where name=? * This is a powerful monitor as it allows you to see hits, avg/min/max query times for all queries in your * application. This is enabled/disabled by calling MonProxyFactory.enableSQLSummary(...). * *
  5. SQLDetail puts the last N (configurable) queries that have been run into a rolling buffer. The SQL buffer * will have the actual query in the case of a Statement and the version with ? for PreparedStatements. In addition * other stats will be in this buffer such as how long the query took to execute, how many times has the PreparedStatement * been reused, the jdbc method that executed the sql, and the exception stack trace if it occured. This can be enabled/disabled * by calling MonProxyFactory.enableSQLDetail(...) * *
  6. Exception Summary will add several jamon rows when an exception occurs. Note the Exception buffer is used for any kind of Exception * including SQLExceptions. The exceptions added are 1. One containing the method that through the exception as well as the exception. * 2. One indicating how many exceptions total have been thrown through proxies, 3) One containing the exception type that was thrown. * This can be enabled/disabled by calling MonProxyFactory.enableExceptionSummary(...) * *
  7. ExceptionDetail puts the last N (configurable) exceptions that have occured to any interface that is being monitored into a buffer. * The stack trace is in the row as well as when it was thrown and what method threw it. This can be enabled/disabled by calling * MonProxyFactory.enableExceptionDetail(...). * *
* *

Sample code:

*
{@code
 *   ResultSet rs= MonProxyFactory.monitor(resultSet);
 *   Connection conn=MonProxyFactory.monitor(connection);
 *   MyInterface my=(MyInterface) MonProxyFactory.monitor(myObject);//myObject implements MyInterface
 *   YourInterface your=(YourInterface) MonProxyFactory.monitor(yourObject);//myObject implements MyInterface
 *   }
* * */ public class MonProxyFactoryImp { private static final String EXCEPTION = "Exception"; private final Class[] CLASS_ARRAY=new Class[0]; private Params params=new Params(); private MonProxyLabelerInt labelFactory=new MonProxyLabeler(); /** This class will be called when creating the jamon labels for both standard summary as well as * exceptions. * * @param factory */ public void setLabelFactory(MonProxyLabelerInt factory) { labelFactory=factory; } public MonProxyLabelerInt getLabelFactory() { return labelFactory; } /** Returns the MonProxy invocation handler should you need access to its methods like setLabeler(...) etc. * Note if the handler is not a MonProxy handler than a class cast exception will be thrown. This is possible as * the method takes a generic Proxy as an argument. being as the monitor methods return an Object, ResultSet etc. these * must be cast to a Proxy before calling this method. For example. * *
{@code
     * ResultSet rsc=MonProxyFactory.monitor(resultSet);
     * MonProxy monProxy=MonProxyFactory.getMonProxy((Proxy)rsc);
     * }
* * @param proxy * @return MonProxy */ public MonProxy getMonProxy(Proxy proxy) { return (MonProxy) Proxy.getInvocationHandler(proxy); } /** By passing any interface to the monitor method, all public method calls and exceptions * will be monitored. It will be a runtime error if the Object passed does not implement an interface. Note that * only interfaces implemented directly by the passed in Object are monitored. Should you want to cast to an interface * implemented by a base class to the passed in Object you should call one of the more explicit monitor(..) methods * *

Sample call:

* MyInterface myProxyObject=(MyInterface) MonProxyFactory.monitor(myObject); */ public Object monitor(Object object) { if (!isEnabled() || object==null) // if not enabled return the original object unchanged, not the proxy return object; else return monitorNoCheck (object, getInterfaces(object.getClass()));// proxy will implement ALL interfaces of this class } /** By passing any interface to the monitor method, and an array of interfaces to implement then all public method calls and exceptions * will be monitored. It will be a runtime error if the Object passed does not implement an interface. * *

Sample call:

* MyInterface myProxyObject=(MyInterface) MonProxyFactory.monitor(myObject, ineterfaces); */ public Object monitor(Object object, Class[] interfaces) { if (!isEnabled() || object==null) // if not enabled return the original object unchanged, not the proxy return object; else return monitorNoCheck(object, interfaces); } // no check means it creates monitored object without seeing if object is null or service is enabled. This is a private method so that // is ok private Object monitorNoCheck(Object object, Class[] interfaces) { MonProxy monProxy=new MonProxy(object, params, (MonProxyLabelerInt) labelFactory.clone()); return Proxy.newProxyInstance( object.getClass().getClassLoader(), interfaces,// proxy will implement ALL interfaces in array monProxy ); } /** By passing any interface to the monitor method, and an interface to implement then all public method calls and exceptions * will be monitored. It will be a runtime error if the Object passed does not implement an interface. * *

Sample call:

* MyInterface myProxyObject=(MyInterface) MonProxyFactory.monitor(myObject, com.mypackage.MyInterface.class); */ public Object monitor(Object object, Class iface) { return monitor (object, new Class[] {iface}); } /** Note if a connection object is monitored any Statements, PreparedStatements, CallableStatements, and * optionally ResultSets that it creates will automatically be monitored. So for jdbc interfaces usually it will be sufficient * to simply monitor the connection. You could also call MonProxyFactory.monitor((Object)conn); * and the connection would be monitored however other child objects wouldn't be and recently executed sql would not be put * in a buffer. The same applies to the other overloaded sql monitor(...) method calls below. For sql monitored objects * to be monitored both the overall monitoring must be enabled. Monitoring rules apply as discussed in the top of this document. * */ public Connection monitor(Connection conn) { return (Connection) monitorJDBC(conn); } /** Monitor a resultSets methods. Note the version that takes an explicit class is used for when the class is a proxy*/ public ResultSet monitor(ResultSet rs) { return (ResultSet) monitorJDBC(rs); } /** Monitor a Statements methods, as well as any ResultSets it returns (assuming the proper monitoring options are enabled) */ public Statement monitor(Statement statement) { return (Statement) monitorJDBC(statement); } /** Monitor a PreparedStatements methods, as well as any ResultSets it returns (assuming the proper monitoring options are enabled) */ public PreparedStatement monitor(PreparedStatement statement) { return (PreparedStatement) monitorJDBC(statement); } /** Monitor a CallableStatements methods, as well as any ResultSets it returns (assuming the proper monitoring options are enabled) */ public CallableStatement monitor(CallableStatement statement) { return (CallableStatement) monitorJDBC(statement); } Object monitorJDBC(Object object) { // if monitoring is not enabled, sql monitoring is not enabled, the object is a null or already an instance of a proxy then return // the original object unchanged. (it would have to be a proxy object with a JDBCMonProxy invocation handler if (!params.isEnabled || (!params.isSQLSummaryEnabled && !params.isSQLDetailEnabled) || object==null || (object instanceof Proxy && Proxy.getInvocationHandler(object) instanceof JDBCMonProxy)) // if not enabled return the original object unchanged, not the proxy return object; else { MonProxy monProxy=new JDBCMonProxy(object, params, (MonProxyLabelerInt) labelFactory.clone()); return Proxy.newProxyInstance( object.getClass().getClassLoader(), getInterfaces(object.getClass()),// proxy will implement passed in interfaces monProxy ); } } /** For every class in the Object/Interface heirarchy find its implemented interfaces. All interfaces this class * implements are returned. Either the Class of an Object or interfaces Class may be passed to * this method. The difference between this method and the method 'Class.getInterfaces()' is * that this one returns ALL implemented interfaces whereas that one only returns interfaces that * are directly implemented by the Class. */ public Class[] getInterfaces(Class cls) { if (cls==null) return null; Set interfaceHeirarchy=new HashSet(); // Get class heirarchy and loop through it and its interfaces adding each interface to the passed // in Set. Class[] objTree=getClassHeirarchy(cls); for (int i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy