I have two projects: a profiler and a basic application (with JUnit tests)
The profiler uses Javassist to instrument the basic application.
When the profiler is inside the basic application, it works fine. When the profiler is outside the basic application, I have to import the basic application jar file into the build path on Eclipse to be abble to instrument my application.
I want to run my profiler on my basic application in command line as EMMA does:
java -jar profiler.jar run application.jar
But I don't know how to tell my profiler, ok, instrument this jar.
Here is my profiler main code:
public static void main(String[] args) throws Exception {
Loader loader = new Loader();
loader.addTranslator(ClassPool.getDefault(), new Profiler());
try {
loader.run("com.application.bookstore.test.Test", null);
} catch (Throwable e) {
e.printStackTrace();
}
}
I tried to do that:
final String arg = args[0];
final String[] commandArgs = new String[args.length - 1];
System.arraycopy(args, 1, commandArgs, 0, commandArgs.length-1);
loader.run(arg, commandArgs);
But when I run it, I get:
[kdelemme@pdkdelemme build]$ java -jar profiler.jar bookstore.jar
java.lang.ClassNotFoundException: bookstore.jar
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at javassist.Loader.delegateToParent(Loader.java:429)
at javassist.Loader.loadClass(Loader.java:315)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at javassist.Loader.run(Loader.java:289)
at com.modeln.Profiler.main(Profiler.java:93)
So I tried to run directly into my Main class directory:
[kdelemme@pdkdelemme test]$ ls
profiler.jar Test.class
[kdelemme@pdkdelemme test]$ java -jar profiler.jar Test
java.lang.NoClassDefFoundError: Test (wrong name: com/application/bookstore/test/Test)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
at java.lang.ClassLoader.defineClass(ClassLoader.java:480)
at javassist.Loader.findClass(Loader.java:380)
at javassist.Loader.loadClass(Loader.java:312)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at javassist.Loader.run(Loader.java:289)
at com.modeln.Profiler.main(Profiler.java:93)
So Have you any ideas to how run my profiler on an outside jar project? Thanks a lot!
Ok, here's the solution: Just pool.insertClassPath()
public static void main(String[] args) throws Exception {
Loader loader = new Loader();
loader.addTranslator(ClassPool.getDefault(), new Profiler());
try {
if (args.length < 1) {
System.out.println(TOOL_USAGE);
} else {
//Initialize profiler with config/config.properties file
initializeProfiler();
final String[] commandArgs = new String[args.length - 1];
System.arraycopy(args, 1, commandArgs, 0, commandArgs.length);
//Open a jar file, unJar it into /tmp/ then add the /tmp/ classpath to the javassist laoder
File file = new File(args[0]);
JarFile jarFile = new JarFile(args[0]);
Manifest manifest = jarFile.getManifest();
String mainClassName = null;
if (manifest != null) {
mainClassName = manifest.getMainAttributes().getValue("Main-Class");
}
jarFile.close();
mainClassName = mainClassName.replaceAll("/", ".");
//Default temp directory is Jarfilename without .jar
final File workDir = File.createTempFile(args[0].substring(0, args[0].indexOf('.')), "");
workDir.delete();
workDir.mkdirs();
//Unjar all files into WorkDir temp directory
unJar(file, workDir);
//Add all directories into classPath
createClassPath(workDir, file);
//Add the classPath with unJar files into the Javassist ClassPool
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(workDir + "/");
loader.run(mainClassName, null);
}
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("Instrumentation of " + args[0] + " finished.");
}