1

As an Open Source Lifecycle Framework API provider, I want to try my best to hiding internal designs with an implicit manner to Provide Lifecycle API, so that will bring much more convenience to API Client.

It is expected to avoid doing configuration for both Core Java Applications and Java EE Applications, but the reality is that I am using java command -javaagent:${path}/Lifecycle.jar option to enable my own ClassFileTransformer at class load time.

After some searches, some unclear directions were found. I need some Java Guy to summarize and guide us.

  1. agentmain vs premain
  2. intergration with specified runtime environment, such as Glassfish's ByteCodePreprocessor, which has the following method to perform byte code transformation:

    public byte[] preprocess(String classname, byte[] classBytes);

My confusions about those directions:

  1. For Core Java Application, it seems that we can modify startup class' main method to adapt agentmain solution. Is there some other options?
  2. For using JavaEE Container, such as Glassfish, I can use ByteCodePreprocessor to modify class byte code, but I need to create some new classes, but I don't know where to store those new class files, or how to design or apply a new ClassLoader to load the newly created class files during preprocessing a class file.

(BTW Lifecycle API will follow a meta-driven style, which is very close with JPA without EntityManager interface, and most of them is just Annotations and CallbackContext interface and LifecycleEvent interface for now.)

Barry Zhong
  • 470
  • 3
  • 17
  • Although you've already marked an answer as solution you might have a look at [javassist](http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/) which basically provides class byte manipulation and injection of further java statements into classes, constructors and methods. To see it in action you might take a look at [a simple plugin framework](https://github.com/RovoMe/PluginApplication/blob/master/PluginFramework/PluginCore/src/main/java/at/rovo/core/classloader/InjectionLoaderStrategyDecorator.java) I've written for a university course. – Roman Vottner Dec 21 '13 at 00:04

1 Answers1

2

Well, the only other method I could think of would be using a custom class loader which you could register at run time. This is how frameworks like Powermock do their heavy lifting. However, this requires some setup as well, but it can be done programatically.

As long as your framework has well defined entry points and as long as all code is run from within your application, you could apply a custom class loader which could instrument all loaded classes.

However, this will not work for classes already loaded. (You could break the parent first patern, but this might raise ClassCastExceptions on instances from outside your framework.)

Avoiding this would require you to override the system class loader which is equally verbose. For the sake of completeness, here is an excerpt of the javadoc of ClassLoader.getSystemClassLoader:

If the system property "java.system.class.loader" is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader.

In this custom class loader, you could just always return instrumented classes.

The difference between agentmain and premain is that the former is invoked when you attach an agent to a running JVM (via the attach API) while the latter is invoked if the agent is specified on the command line at the JVM's startup. Registering an agent at runtime might actually be a solution for you. The blog entry that I linked offers a quite good description of that.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Thank you Raphw. I read your answer very carefully for several times. And I read all the links you provided. Finally I think I got your ideas for my problems. – Barry Zhong Nov 28 '13 at 14:35
  • Thank you Raphw. I read your answer very carefully for several times. And I read all the links you provided. Finally I think I got your ideas for my problems. To load agent lib dynamically I need to execute some code before application classes be loaded: for Core Java app, I can just modify main class. And for JavaEE app, I can use container's lifecycle event to load the agent jar. And to create and load new instrumented classes, I can use java.system.class.loader. Is there any other consideration while using the two methods I summarized from your answer? – Barry Zhong Nov 28 '13 at 14:41
  • That's quite what I tried to express. When you are instrumenting classes after application startup, it is nearly impossible to instrument classes that were already loaded. You can however register an agent after program startup (example: http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/), this agent allows you to interfere with any classes that are yet to be loaded. If your framework has a well-defined entry point, you can just register this agent once. (e.g. some `Framework.initialize()` method) – Rafael Winterhalter Nov 28 '13 at 15:15
  • All you can do once a class was loaded with the system class loader is to load the class once again and hide the other loaded version by implementing some sort of *child-first* class loader. I would not recommend it. If you can make the runtime agent work, this is the way to go. Alternatively, you could register a startup agent or a custom class loader. Otherwise, I don't think there is anything you can do. – Rafael Winterhalter Nov 28 '13 at 15:20
  • Thank you Raphw. The good news for me I can find the entry point you mentioned and for now I did not see classes need to be instrumented can be loaded before that. Right now I am using very silly way to store the newly created class files at the same class path locations of the class under instrument. I know there is so many uncertainty, such as network sharing folder... But I have a problem, once I create a custom class loader, do I still need to store them on disk or just use PermGen memory? I am not sure if OOME happens. – Barry Zhong Nov 28 '13 at 16:14
  • Its enough to store them in permgen, I guess. You can always reproduce the instrumentation if you needed to reload classes. – Rafael Winterhalter Nov 28 '13 at 17:43