de.mcs.jmeasurement.proxy.ProxyMonitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of JMeasurement Show documentation
Show all versions of JMeasurement Show documentation
JMeasurement profiling programs in production enviroment
/*
* MCS Media Computer Software Copyright (c) 2006 by MCS
* -------------------------------------- Created on 26.07.2006 by W.Klaas
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.mcs.jmeasurement.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashSet;
import java.util.Iterator;
import de.mcs.jmeasurement.MeasureFactory;
import de.mcs.jmeasurement.Monitor;
import de.mcs.utils.StringFormat;
/**
* This is my monitor class for monitoring interface methodes automatically. The
* name of the measurepoints will be automatically generated as
*
*
* [fullclassname]#[methodename]
*
*
* @since 0.64
* @author W.Klaas
*
*/
public class ProxyMonitor implements InvocationHandler {
/** the interface under invocation monitoring. */
private Object testObject;
/** classname as string for direct performant access. */
private String className;
/** exceptions should be stored. */
private boolean storeExceptions;
/** full exceptions with stacktraces. */
private boolean fullExceptions;
/** set with all method names. */
private HashSet methodNames;
/** using the default exception handling. */
private boolean defaultExceptionHandling;
private boolean pointNameWithParameter;
private class MethodName {
private boolean bParameterExtension;
private String name;
private int[] indexes;
/**
* @param aName
*/
public MethodName(final String aName) {
bParameterExtension = false;
this.name = aName;
if (aName.indexOf(".") > 0) {
bParameterExtension = true;
String argument = aName.substring(aName.indexOf(".") + 1);
String[] arguments = argument.split("\\.");
indexes = new int[arguments.length];
for (int i = 0; i < arguments.length; i++) {
String indexStr = arguments[i].substring(3);
indexes[i] = Integer.parseInt(indexStr);
}
this.name = aName.substring(0, aName.indexOf("."));
}
}
/**
* @return the bParameterExtension
*/
public boolean isParameterExtension() {
return bParameterExtension;
}
/**
* @return the name
*/
public String getName() {
return name;
}
public String getParameterPart(final Object[] arguments) {
StringBuilder part = new StringBuilder();
for (int i = 0; i < indexes.length; i++) {
part.append(arguments[indexes[i]]);
part.append(".");
}
return part.substring(0, part.length() - 1);
}
}
/**
* constructor for this proxy. Using default exception handling.
*
* @param aTestObject
* object under test.
* @param aMethodNames
* list with all methodnames that should be monitored. If this
* parameter is null all methods will be monitored.
*/
public ProxyMonitor(final Object aTestObject, final String[] aMethodNames) {
super();
this.pointNameWithParameter = false;
this.testObject = aTestObject;
className = testObject.getClass().getName() + '#';
methodNames = new HashSet();
this.defaultExceptionHandling = true;
if (aMethodNames != null) {
for (int i = 0; i < aMethodNames.length; i++) {
MethodName methodName = new MethodName(aMethodNames[i]);
methodNames.add(methodName);
}
}
}
/**
* constructor for this proxy.
*
* @param aTestObject
* object under test.
* @param aStoreExceptions
* if exceptions should be stored.
* @param aFullExceptions
* full exceptions with stacktraces
* @param aMethodNames
* list with all methodnames that should be monitored. If this
* parameter is null all methods will be monitored.
*/
public ProxyMonitor(final Object aTestObject, final boolean aStoreExceptions, final boolean aFullExceptions,
final String[] aMethodNames) {
this(aTestObject, aMethodNames);
this.defaultExceptionHandling = false;
this.storeExceptions = aStoreExceptions;
this.fullExceptions = aFullExceptions;
}
/**
* constructor for this proxy.
*
* @param aTestObject
* object under test.
* @param aStoreExceptions
* if exceptions should be stored.
* @param aFullExceptions
* full exceptions with stacktraces
* @param aMethodNames
* list with all methodnames that should be monitored. If this
* parameter is null all methods will be monitored.
*/
public ProxyMonitor(final Object aTestObject, final boolean aStoreExceptions, final boolean aFullExceptions,
final boolean pointnameWithParameter, final String[] aMethodNames) {
this(aTestObject, aMethodNames);
this.pointNameWithParameter = pointnameWithParameter;
this.defaultExceptionHandling = false;
this.storeExceptions = aStoreExceptions;
this.fullExceptions = aFullExceptions;
}
/**
* This is the methode that will alway be inveked on every methode
* invocation of the object under test. Processes a method invocation on a
* proxy instance and returns the result. This method will be invoked on an
* invocation handler when a method is invoked on a proxy instance that it
* is associated with.
*
* @param proxy
* the proxy instance that the method was invoked on
*
* @param method
* the Method
instance corresponding to the
* interface method invoked on the proxy instance. The declaring
* class of the Method
object will be the interface
* that the method was declared in, which may be a superinterface
* of the proxy interface that the proxy class inherits the
* method through.
*
* @param args
* an array of objects containing the values of the arguments
* passed in the method invocation on the proxy instance, or
* null
if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* java.lang.Integer
or
* java.lang.Boolean
.
*
* @return the value to return from the method invocation on the proxy
* instance. If the declared return type of the interface method is
* a primitive type, then the value returned by this method must be
* an instance of the corresponding primitive wrapper class;
* otherwise, it must be a type assignable to the declared return
* type. If the value returned by this method is null
* and the interface method's return type is primitive, then a
* NullPointerException
will be thrown by the method
* invocation on the proxy instance. If the value returned by this
* method is otherwise not compatible with the interface method's
* declared return type as described above, a
* ClassCastException
will be thrown by the method
* invocation on the proxy instance.
*
* @throws Throwable
* the exception to throw from the method invocation on the
* proxy instance. The exception's type must be assignable
* either to any of the exception types declared in the
* throws
clause of the interface method or to the
* unchecked exception types
* java.lang.RuntimeException
or
* java.lang.Error
. If a checked exception is
* thrown by this method that is not assignable to any of the
* exception types declared in the throws
clause of
* the interface method, then an
* {@link UndeclaredThrowableException} containing the exception
* that was thrown by this method will be thrown by the method
* invocation on the proxy instance.
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
public final Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
Object result = null;
MethodName methodName = getMethodName(method.getName());
if (methodNames.isEmpty() || (methodName != null)) {
StringBuilder classMethodName = new StringBuilder();
classMethodName.append(className);
classMethodName.append(method.getName());
if ((methodName != null) && methodName.isParameterExtension()) {
classMethodName.append('.');
classMethodName.append(methodName.getParameterPart(args));
} else if (pointNameWithParameter) {
appendParameters(classMethodName, args);
}
Monitor monitor = MeasureFactory.start(classMethodName.toString());
try {
result = method.invoke(testObject, args);
monitor.stop();
} catch (InvocationTargetException e) {
String stackTrace = "";
if (!defaultExceptionHandling) {
if (storeExceptions) {
if (fullExceptions) {
stackTrace = StringFormat.getStackTrace(e.getCause());
} else {
stackTrace = e.getCause().toString();
}
}
monitor.setException(stackTrace);
} else {
monitor.setException(e.getCause());
}
throw e.getCause();
}
} else {
// if this methode should not be monitored
try {
result = method.invoke(testObject, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
return result;
}
private void appendParameters(StringBuilder classMethodName, Object[] args) {
for (int i = 0; i < args.length; i++) {
Object object = args[i];
classMethodName.append('.');
if (object != null) {
classMethodName.append(object.toString());
}
}
}
/**
* @param name
* @return
*/
private MethodName getMethodName(String name) {
for (Iterator iter = methodNames.iterator(); iter.hasNext();) {
MethodName methodName = iter.next();
if (methodName.getName().equals(name)) {
return methodName;
}
}
return null;
}
}