de.engehausen.kongcurrent.cglib
Class MonitorCglib

java.lang.Object
  extended by de.engehausen.kongcurrent.cglib.MonitorCglib

public class MonitorCglib
extends Object

Experimental helper to monitor parallel method invocations for exceptions on actual classes (versus interfaces as described in Monitor). The proxy can track invocations of the objects' methods and can report on potential concurrent access on the object. This can be used to help find out code paths that concurrently access the object.

This monitor uses cglib to build a proxied (actually subclassed) version of the object. The cglib library and its dependencies must be on the classpath. For proxying to work a new object of the class must either be constructable using the default constructor or using a constructor with arguments. Classes with constructors that use arguments need to be described using the ConstructorInformation in DescriptionCglib.

Here is a simple example code snippet that will be adapted to use the monitor:

MyClass myImpl = new MyClass("default");
processing(myList);
Now you want to know what happens to the object when it is used in the processing(MyClass) method. Instead of the original object you simply pass the monitored version to the processing method:
 final MyClass myImpl = new MyClass("default");
 //constructor takes String as argument, value supplied by myImpl instance
 ConstructorInformation<MyClass> ctorInfo = new ConstructorInformation<MyClass>(String.class) {
     public Object[] getArgValues() {
         return new Object[] { myImpl.getSetting() }; // getSetting() would return value set in CTOR
     }
 };
 // description for MyClass, with constructor information
 DescriptionCglib<MyClass> description = new DescriptionCglib<MyClass>(MyClass.class, ctorInfo);
 // creates a monitored instance that was created with the same
 // constructor as the original instance
 MyClass monitored = MonitorCglib.monitor(myImpl, description, new DefaultExceptionHandler());
 
 processing(monitored);
This code will create a monitored instance based on the description of the original class; the default logger passed in will output to System.out. The DefaultExceptionHandler will record the stack traces of all callers and output these in case an exception occurs during method invocation of a monitored method. Important: Keeping track of this information is costly. The methods of the monitored instance can be considerably slowed down; this can directly affect the situation you try to analyze, up to the point where the situation you try to understand does not happen any more. Please keep this in mind.

In case of a problem, e.g. a IllegalStateException the logger would output something similar to this:

exception occurred:
Thread[Thread-1,5,main] - java.lang.IllegalStateException: object state changed while processing
        at de.engehausen.kongcurrent.testhelper.Demo3Impl.determineMax(Demo3Impl.java:35)
        at de.engehausen.kongcurrent.testhelper.Demo3Impl$$EnhancerByCGLIB$$cfa20a97.CGLIB$determineMax$2()
...
        at de.engehausen.kongcurrent.cglib.ComplexTest$Executor.run(ComplexTest.java:68)
        at java.lang.Thread.run(Unknown Source)

the following threads were recently operating on the object:
Thread[Thread-1,5,main] - java.lang.Exception: caller...
        at de.engehausen.kongcurrent.testhelper.Demo3Impl$$EnhancerByCGLIB$$cfa20a97.determineMax()
        at de.engehausen.kongcurrent.cglib.ComplexTest$Executor.doit(ComplexTest.java:79)
        at de.engehausen.kongcurrent.cglib.ComplexTest$Executor.run(ComplexTest.java:68)
        at java.lang.Thread.run(Unknown Source)
Thread[Thread-0,5,main] - java.lang.Exception: caller...
        at de.engehausen.kongcurrent.testhelper.Demo3Impl$$EnhancerByCGLIB$$cfa20a97.determineMax()
        at de.engehausen.kongcurrent.cglib.ComplexTest$Executor.doit(ComplexTest.java:79)
        at de.engehausen.kongcurrent.cglib.ComplexTest$Executor.doit(ComplexTest.java:77)
        at de.engehausen.kongcurrent.cglib.ComplexTest$Executor.doit(ComplexTest.java:77)
        at de.engehausen.kongcurrent.cglib.ComplexTest$Executor.run(ComplexTest.java:68)
        at java.lang.Thread.run(Unknown Source)
The output informs you that an IllegalStateException occurred in thread "Thread-1,5,main" while working on determineMax(). It also shows you the stack traces of "recent" calls to the object. In there you find another thread which added worked on the monitored object (thread "Thread-0,5,main").

All this can be adapted to your needs. You need to provide a DescriptionCglib for the object to monitor, and likely information on how to construct an equivalent object using the ConstructorInformation. In case the monitored object returns further objects that somehow depend on the originally monitored object (think e.g. iterator of a list) then monitoring these is possible as well by adding them as "dependant" objects to the description via the appropriate method description. If the return value of the method returning a "dependant" you can also specify a plain Description, in this case the dynamic proxying approach would kick in.


Method Summary
static
<T> T
monitor(T target, DescriptionCglib<T> description, ExceptionHandler handler)
          Creates a monitored version of the given target.
protected static
<T> T
monitorGeneric(T target, DescriptionCglib description, ExceptionHandler handler)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Method Detail

monitor

public static <T> T monitor(T target,
                            DescriptionCglib<T> description,
                            ExceptionHandler handler)
Creates a monitored version of the given target.

Type Parameters:
T - the type of object to monitor
Parameters:
target - the instance to monitor, must not be null.
description - a description of the class or interface, must not be null. If the description is for an interface, then the proxying will be delegated to Monitor.
handler - an exception handler that keeps track of invocations on the proxied object; a single exception handler instance should be used per monitored instance, or the handler must be capable of tracking different objects at the same time.
Returns:
a monitored version of the object to monitor, never null.

monitorGeneric

protected static <T> T monitorGeneric(T target,
                                      DescriptionCglib description,
                                      ExceptionHandler handler)


Copyright © 2013. All Rights Reserved.