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. (sponsored)
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.
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.
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.
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:
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.
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.
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:
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:
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:
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.
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.
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
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?
Instrumentation: Modify Applications with Java 5 Class File Transformations
At 11:02 PM on Jun 27, 2005, R.J. Lorimer wrote:
Fresh Jobs for Developers Post a job opportunity
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.instrumentpackage. 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: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
premainbootstrap class. Like themainmethod you put in a bootstrap class for a regular Java application, agents have apremainmethod that takes different arguments specialized for writing an instrumentation agent. Here is the signature of apremainmethod:public static void premain(String agentArguments, Instrumentation instrumentation) { // ... }The two arguments are:
The
java.lang.instrument.Instrumentationobject passed into thepremaingives you access to do two primary ways to manipulate classes - class file transformations via ajava.lang.instrument.ClassFileTransformerinstance, and class file redefinitions via thejava.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 asjava.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 aClassFileTransformer.Instances of
ClassFileTransformerare 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
ClassFileTransformeris 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
premainclass 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:
Please be very careful about the
Premain-Classline - 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 failedThis 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.classFinally, we just need to execute it. The java.lang.instrument package summary comes to the rescue again - this time showing us the execution syntax:
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:
Executing this on a simple main method that just loaded a class to do some fibonacci calculations returned these results in the console:
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
6 replies so far (
Post your own)
Re: Instrumentation: Modify Applications with Java 5 Class File Transformat
Hido 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
Re: Instrumentation: Modify Applications with Java 5 Class File Transformat
Are there any tools out there that use these new capabilities?Thanks,
Guy
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
Re: Instrumentation: Modify Applications with Java 5 Class File Transformat
Rory Winston's reply is the better one.Re: Instrumentation: Modify Applications with Java 5 Class File Transformat
Hi all,I tried to make a java agent with this codepublic 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 ...
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?