views:

297

answers:

1

In order to use the instrumentation features introduced in JDK 5, you can use the -javaagent flag passed to the JVM. This will inject an instance of an Instrumentation class into the static premain method. For example in a class like this:

public class MyClass {
    public static Instrumentation inst;
    public static void premain(String options, Instrumentation inst) {
        MyClass.inst = inst;
    }
}

With an appropriate manifest file, you can run this as follows:

 java -javaagent:myfiles.jar SomeClass

This calls the premain method then main from SomeClass. This approach is used in the Java.SizeOf Project to guess at the approximate size of a Java object.

OK, now in Eclipse RCP each bundle has its own classloader. This means that the static Instrumentation that we stored in our MyClass is not visible to an Eclipse application. The javaagent uses one class-loader, the Eclipse bundles get loaded with another. When we access MyClass.inst from within a plugin it is null, as that class is not the same class as the one the javaagent loaded and called premain on.

Other clues as to a possible solution are this thread on the rcp mailing list. But nothing conclusive.

Is there any way to work around this? The Eclipse-BuddyPolicy hinted at in the eclipsezone article sounds good. I tried:

Eclipse-BuddyPolicy: app

in my plugins without luck. I need something like Eclipse-BuddyPolicy: javaagent. Any ideas?

+1  A: 

I think the simplest solution is to use the global properties object. Have pre-main store the instrumentation object as a global properties and then access it from everywhere (the properties object is the same in all class loaders):

[Edit: updated]

public class MyClass {
    private static final String KEY = "my.instrumentation";
    public static void premain(String options, Instrumentation inst) {
        Properties props = System.getProperties();
        if(props.get(KEY) == null)
           props.put(KEY, INST);
    }

    public static Instrumentation getInstrumentation() { 
       return System.getProperties().get(KEY);
    }
}
Itay
It's a nice idea, but sadly it's `setProperty(String, String)` - you can't put any old Object in there.
rq
This can be easily fixed (See updated version of my answer): System.getProperties() returns a Properties() object which is a subclass of Hashtable whose API offers set(String,Object) and get(String) returning an Object.
Itay
Such a simple solution, and it works perfectly. Thanks!
rq