Monday, September 26, 2011

Love for Badminton

To me Badminton is life. Playing it relieves me of all the stress and fills up with new energy. The downside is that you have to live with injuries all the time. Though nagging at times but the fun of the game keeps me going. Excellent sport to play actually

Wednesday, January 12, 2011

Thursday, August 6, 2009

Instrumenting a class with custom Tomcat Class loader

I have been experimenting with the idea of runtime instrumentation of java classes for quite some time.
Java 5 provides a mechanism using a java agent to intercept the classloading process but here I am going to look into creating a custom Class loader for Tomcat and changing the class bytes on the fly using the javassist library.

Create a web project using Eclipse or any IDE of your choice.
Create a context.xml file in the META-INF directory of the web app. The content will be similar to


loaderClass="com.test.SampleLoader"
useSystemClassLoaderAsParent="false"
delegate="false"/>



After doing this we need to implement the SampleLoader class
The class should be a subclass of WebappClassLoader from Tomcat. We will override the

protected Class findClassInternal(String name) throws ClassNotFoundException method.
The method can be copied from the Tomcat WebappClassLoader class.
Under the if (entry.loadedClass == null) {
method we will change the byte stream of the class using javassist something like this

byte[] b =entry.binaryContent;
String name1 ="com.sample.Test";
pool.insertClassPath(new ByteArrayClassPath(name1, b));
if(name.equals(name1))
{
CtClass cc = pool.get(name);
cc.getConstructors()[0].insertBefore("{System.out.println(\"Before Instantiaition\");}");
cc.getConstructors()[0].insertAfter("{System.out.println(\"After Instantiation\");}");
System.out.println("After classworking "+cc.toBytecode().length);
entry.binaryContent=cc.toBytecode();
}
The same can be extended to intercept any method call.
The class is defined by the classloader after the byte array stream is modified. So the modified class is loaded into the jvm by the custom classloader.

Also the classes can be loaded from an alternate source rather then the web-inf/lib and classes directory
This can be useful when we want to write interceptors to the method calls or create proxies on the fly.

The Custom classloader can be packaged and the jar needs to be placed in CATALINA_HOME/lib directory alongside the javassist libs..