Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

NetBeans 6: Matisse Updates

NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed.

Introduction to Groovy Part 3

In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.

Easier Custom Components with Swing Fuse

Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.

Benchmark Analysis: Guice vs Spring

Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Replies: 6 - Pages: 1  
Threads: [ Previous | Next ]
  Click to reply to this thread Reply

Instrumentation: Modify Applications with Java 5 Class File Transformations

At 11:02 PM on Jun 27, 2005, R.J. Lorimer wrote:

While I was sitting here at home envying a large majority of my fellow collegues are off having a blast at JavaOne (sigh), I was fiddling with some of the stuff that I haven't had a chance to play with until now. One of those new and nifty features is the java.lang.instrument package. This is another one of those Java 5 features that I am really surprised hasn't made more of a splash as of yet. This library finally makes it possible for tools such as a Java code profiler and optimizer to be a.) written in 100% Java code and b.) be 100% spec compliant, all at the same time , which up to this point hasn't been possible. Most of the popular tools out there for profiling are either a.) proprietary (meaning I don't know what they use) (see JProfiler , YourKit ) b.) open source and tied to the the JVMPI infrastructure from pre-Java 5 which is native in nature (see Extensible Java Profiler ), or c.) open source and implemented using a non-standard approach (see JRat ). Each has problems:

  • A. - Proprietary software can be expensive.
  • B. - Native code is always a mess to deal with, even if the worst of the work is done ahead of time for you.
  • C. - Non-Standard implementations have a tendency to not have any core tool support, and as such, aren't always as flexible.

You can see a pretty thorough list of existing open source profilers here via Carlos Perez's Manageability.org.

The new instrumentation package provides a standard library to implement 100% Java instrumentation code, and is also paired with a standard syntax for connecting an instrumentation library with any running application. Today, I want to walk through creating your first instrumentation class (the how), and hopefully get into what you can do with it (the what/why) in the near future.

The instrumentation package is intended to be used by special Java libraries called Java agents. A Java agent is a pluggable library that runs embedded in a JVM and intercepts the classloading process. What this allows then, is to have the agent a.) monitor the classloading process and b.) instrument (or engineer) the bytecode of the classes to provide informational callbacks into the agent's libraries. Notice I said that it *allows* the agent to instrument/engineer the bytecode - the core Java packages don't have support for programmatic manipulation of bytecode, they leave that up to the developer. Thankfully we have a mass of open-source support already ( BCEL , Javassist , and ASM to name a few).

Implementing an agent is quite easy. First, you need a special premain bootstrap class. Like the main method you put in a bootstrap class for a regular Java application, agents have a premain method that takes different arguments specialized for writing an instrumentation agent. Here is the signature of a premain method:

public static void premain(String agentArguments, Instrumentation instrumentation) {	
	// ...
}

The two arguments are:

  1. A String representing the arguments to the agent (we'll get to how you pass them momentarily). Note that it is *not* a string array. The agent hook expects you to do any argument parsing/tokenizing yourself. Pipes, commas, spaces, semi-colons, it is up to you.
  2. The Instrumentation instance. This class is the hook into the active instrumentation library that is running for your agent. This class is where you will pass in any class transformers or redefined classes that you have manipulated.

The java.lang.instrument.Instrumentation object passed into the premain gives you access to do two primary ways to manipulate classes - class file transformations via a java.lang.instrument.ClassFileTransformer instance, and class file redefinitions via the java.lang.instrument.Instrumentation#redefineClasses(ClassDefinition[]) method. The main difference between the two is that the redefine method is used to redefine already loaded classes, and as such can be used to alter classes in the active JVM that even the agent may be dependent on (such as java.lang.Object ) where-as the transformer will only see classes loaded after it has been registered, and only classes that the transformer itself is not dependent on. For today I will simply show how to write a ClassFileTransformer .

Instances of ClassFileTransformer are meant to perform modifications to the bytecode of existing classes for a variety of reasons. What I mention here is the primary intention of the library (instrumentation), but creativity may prevail - here is a link to someone who wrote an agent to engineer out Log4J logging calls from an application by using an agent (in otherwords, without changing the application distribution itself).

Writing a ClassFileTransformer is deceptively easy - the interface only has one method. The trick is what you do with the parameters and return-value of the method. Here is a simple example that simply prints to the console every time a class is loaded in the JVM.

package com.javalobby.tnt.instrument;
 
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
 
public class SimpleTransformer implements ClassFileTransformer {
 
	public SimpleTransformer() {
		super();
	}
 
	public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
		System.out.println("Transformer to Transform Class: " + className);
		return bytes;
	}
}

Obviously, printing to the console is not the same as doing bytecode transformations. That process is complicated enough, however, that I feel I owe a separate article to that alone.

For our simple agent, I created a very simple premain class that simply adds our transformer. Here is the source:

package com.javalobby.tnt.instrument;
 
import java.lang.instrument.Instrumentation;
 
public class SimpleMain {
	public static void premain(String agentArguments, Instrumentation instrumentation) {	
		instrumentation.addTransformer(new SimpleTransformer());
	}	
}

The last component we need then, is to figure out how to package our agent up so we can execute it with our applications. The java.lang.instrument package summary describes the manifest format in good detail - for our simple example, here is what I have:

Manifest-Version: 1.0 
Premain-Class: com.javalobby.tnt.instrument.SimpleMain

Please be very careful about the Premain-Class line - the agent library is not very good at parsing the manifest file, and spaces that are actually allowed by the manifest specification are not trimmed off of the class name, and it will say something like this when you try to start:

Exception in thread "main" java.lang.ClassNotFoundException: com.javalobby.tnt.instrument.SimpleMain
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(Unknown Source)
FATAL ERROR in native method: processing of -javaagent failed

This sure looks like a classpath problem (and boy did I think it was for a *long* time working on this article) before I found this bug: Bug 6274276 about the problem i just described. You *must* have the mandatory one space before the class name, and *no* spaces after the classname - only a carriage return. Also, remember that the manifest should end in a blank line (hence why the manifest above has extra blank space below it).

Ok, then we just compile and package our code (like this) in the JAR:

test.jar
|
+--- META-INF
|    |
|    +--- MANIFEST.MF (we just worked on this one)
|
+--- com
     |
     +--- javalobby
          |
          +--- tnt
               |
               +--- instrument
                    |
                    +--- SimpleMain.class
                    |
                    +--- SimpleTransformer.class

Finally, we just need to execute it. The java.lang.instrument package summary comes to the rescue again - this time showing us the execution syntax:

java(w) -javaagent:jarpath[=options] 

Executing this agent is about as easy as it gets - we have no options, and we have no classpath dependencies. Presuming a program called 'MyProgram', our startup command may look something like this:

java -javaagent:test.jar com.javalobby.tnt.MyProgram

Executing this on a simple main method that just loaded a class to do some fibonacci calculations returned these results in the console:

~>java -javaagent:test.jar com.javalobby.tnt.instrument.example.ExampleMain
Transformer to Transform Class: sun/misc/URLClassPath$FileLoader$1
Transformer to Transform Class: com/javalobby/tnt/instrument/example/ExampleMain
Transformer to Transform Class: com/javalobby/tnt/instrument/example/ExampleClass
Transformer to Transform Class: java/lang/Shutdown
Transformer to Transform Class: java/lang/Shutdown$Lock

Try this new instrumentation out on Java applications you have; I have attached the completed JAR file for giggles - it should be able to run with anything you throw at it. Stay tuned as I'll cover how to actually engineer our classes, and what can be done with the results.

Until next time,

R.J. Lorimer
rj -at- javalobby.org
http://www.coffee-bytes.com

1 . At 12:24 PM on Aug 17, 2006, nikoloas wrote:
  Click to reply to this thread Reply

Re: Instrumentation: Modify Applications with Java 5 Class File Transformat

Hi

do you know if an agent can have extra methods than can be called from inside premain method?
or if an agent class is allowed to extend another class?

I just created an agent and It worked correctly but when It extends another class and contains extra methods, it sends error messages

thanks for your help
2 . At 6:27 AM on Sep 2, 2006, Guy Korland wrote:
  Click to reply to this thread Reply

Re: Instrumentation: Modify Applications with Java 5 Class File Transformat

Are there any tools out there that use these new capabilities?

Thanks,
Guy
3 . At 8:10 AM on Sep 14, 2006, Rory Winston wrote:
  Click to reply to this thread Reply

Re: Instrumentation: Modify Applications with Java 5 Class File Transformat

I think the AspectJ aspect weaving tools use this....I remember AspctWerkz used to use this mechanism, anyways.
--------------------------------------
Rory Winston
http://www.researchkitchen.co.uk/blog
http://people.apache.org/~rwinston
4 . At 7:43 AM on Mar 19, 2007, Israr Ahmed wrote:
  Click to reply to this thread Reply

Re: Instrumentation: Modify Applications with Java 5 Class File Transformat

Rory Winston's reply is the better one.
There certainly have been performance issues with Java. We've been working really hard on them. The primary way we've attacked the problem is with advanced virtual machines. The performance has been getting very nice. --James Gosling, 1999.
5 . At 8:32 AM on Jul 17, 2007, Sofien wrote:
  Click to reply to this thread Reply

Re: Instrumentation: Modify Applications with Java 5 Class File Transformat

Hi all,I tried to make a java agent with this code
public static void premain(String agentArgs, Instrumentation inst) {
PropertyConfigurator.configure("config/log4j.properties");
String agentName = ConfigInitiator.getConfiguration().getString("jvmstat_agent.name");
JvmThread jvmstatThread = new JvmThread(0, agentName);
logger.info("Starting JVM Stats Collector...");
Thread thread = new Thread(jvmstatThread);
thread.start();
}
And it gives me this exception

Exception in thread "main" java.lang.NoSuchMethodError: main
I launch it throw a ".bat" file using this line

java -cp %APEF_JVMSTATCOLLECTOR_CP% -javaagent:%APEF_DIST%\JVMSTAT1.5.0.AgentExtension.jar com.adhocpes.apef.perf.pecollector.jvmstat.exec.JvmStatAgent

%APEF_JVMSTATCOLLECTOR_CP% is a variable which already difined in the .bat file ...
I don't know the error causes ...
6 . At 12:36 AM on Dec 26, 2007, Vimil wrote:
  Click to reply to this thread Reply

Re: Instrumentation: Modify Applications with Java 5 Class File Transformations

I tried to instrument FileInputStream and FileOutputStream classes to monitor open files and check if the application closes all files after opening them. The problem is when I try to access a class defined by me from the close method of FileInputStream I get a ClassNotFound Exception, I am however able to access the class from the premain method. Any idea what the problem could be?

thread.rss_message