I'm not that good in Java but I have my webApplication running on a Wildfly. I have 3 threads who just call a function that insert logs in in and the function saves the logs to a Database and after that every thread sends a time how long did it takes to do this. They send the data to another programm I wrote what has 3 threads to call one of the 3 server threads.
So now I try to do some ByteCode Manipulation every thread on the server saves the datetime call the log function waits 1 second and returns then the time they needed.
1 Thread write something in an logfile before or after they waitet 1 second. But this part where they wait a second and call the log function I want that to inject to every 3 threads with Bytecode manipulation.
public class MyTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
return transformClass(redefiningClass, bytes);
}
private byte[] transformClass(Class classToTransform, byte[] b) {
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.get("de.soptim.ws.MyApplication");
} catch (javassist.NotFoundException e) {
e.printStackTrace();
}
try {
assert cl != null;
CtMethod[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isEmpty() == false) {
changeMethod(methods[i]);
}
}
b = cl.toBytecode();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cl != null) {
cl.detach();
}
}
return b;
}
private void changeMethod(CtMethod method) throws NotFoundException, CannotCompileException {
if (method.hasAnnotation(Loggable.class)) {
method.insertBefore("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
method.insertAfter("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
}
}}
Thats my transformer class it should increase the Code my Methods need it checks what Method has an @Loggable annotation an then adds the code into it("at the moment it's just some log statments for checking if it works")
My biggest problem is now that I don't know how to call my agent ... I googled hwo to call an agent at runtime with agentmain() but I think I dind't really understood how it works.
Agent Class
public class LogAgent {
public static void agentmain(String agentArgs, Instrumentation inst) {
System.out.println("Starting the agent");
inst.addTransformer(new MyTransformer());
}}
Hope you understand My problem :) I and if you answere pleas try to stay noob friendly :D.
you don't call your agent explicitly, you should specify additional argument to your JVM :
java -javaagent:jarpath[=options]
where jarpath
is a path to jar containing your agent. JVM will invoke premain
method before main
method of java program.
And transform
method will be called before classloading by JVM (you don't call it explicitly).
Last remark : you should implement premain
method, not agentmain
.
agentmain
is used during attaching to running vm, while premain
is used when you start JVM with -javaagent
method.
And make sure that your jar have valid manifest, as described : https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html
I haven't using javaassit so I cannot say that your code is valid, but instrumenting webapp server like Wildfly is much harder than normal java app (mostly due to classloaders visibility and hierarchy).
See also :
http://www.tomsquest.com/blog/2014/01/intro-java-agent-and-bytecode-manipulation/ Tutorials about javaagents