package alt.jiapi.agent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.Properties;
import java.util.StringTokenizer;
import alt.jiapi.reflect.JiapiClass;
import alt.jiapi.InstrumentationDescriptor;
import alt.jiapi.InstrumentationContext;
import alt.jiapi.interceptor.*;
import java.lang.reflect.InvocationHandler;
/**
* This class is an implementation of ClassFileTransformer and
* acts as a java-agent for jdk1.5+ virtual machines.<p>
* You can enable this agent from command line by adding <i>-javaagent</i>
* switch to command line like this:<br>
*
* <blockquote>
* <b><i>java -javaagent:<path_to_jiapi.jar> HelloWorld</i></b>
* </blockquote>
*
* One can give configuration parameters in command line to this agent
* and Transformer used. Parameters are given by appending the following
* to -javaagent switch:<p>
*
* <i>'=name1=value1,name2=value2,....'</i><p>
*
* This agent regoqnises one parameter:
* <i>'transformer=<name_of_the_transformer></i>. If this parameter is given,
* It is assumed to be a fully qualified name of a class, that extends
* <i>alt.jiapi.agent.Transformer</i>. If not given,
* <i>alt.jiapi.agent.HotSpotTransformer</i> is used. <p>
*
* @see alt.jiapi.agent.Transformer
* @see alt.jiapi.agent.HotSpotTransformer
*/
public class InstrumentationAgent implements ClassFileTransformer {
private String agentArgs;
private Instrumentation instrumentation;
private Transformer transformer;
public static void premain(String agentArgs, Instrumentation i) {
Properties p = new Properties();
// Parse agentArgs. Entries are separated by ','. Each entry
// looks like 'name=value'. Like
// a=b,c=d,e=f
if (agentArgs != null) {
StringTokenizer st = new StringTokenizer(agentArgs, ",");
while(st.hasMoreTokens()) {
String nv = st.nextToken();
StringTokenizer st2 = new StringTokenizer(nv, "=");
String n = st2.nextToken();
String v = null;
if (st2.hasMoreTokens()) {
v = st2.nextToken();
}
else {
v = "";
}
p.setProperty(n, v);
}
}
try {
// Get the class name of Transformer. Default to
// HotSpotTransformer
String tr = p.getProperty("transformer",
"alt.jiapi.agent.HotSpotTransformer");
if (tr != null) {
Class c = Class.forName(tr);
Object o = c.newInstance();
Transformer tf = (Transformer)o;
tf.init(p);
// Create and register InstrumentationAgent as transformer
InstrumentationAgent jcft =
new InstrumentationAgent(agentArgs, i, tf);
i.addTransformer(jcft);
}
else {
System.out.println("Failed to create Transformer: Missing agent parameter 'transformer'");
// For testing purposes...
InstrumentationAgent jcft =
new InstrumentationAgent(agentArgs, i, null);
i.addTransformer(jcft);
}
}
catch(Exception e) {
System.out.println("Failed to create Transformer: " + e);
e.printStackTrace();
}
}
public InstrumentationAgent(String agentArgs, Instrumentation i, Transformer transformer) {
this.agentArgs = agentArgs;
this.instrumentation = i;
this.transformer = transformer;
}
public byte[] transform(ClassLoader cl, String className,
Class<?> classBeingRedefined,
ProtectionDomain pd,
byte[] classFileBuffer) {
if (transformer == null) {
return null;
}
else {
// trasform(...) API states, that we should make a
// copy of classFileBuffer
byte[] tempBuffer = new byte[classFileBuffer.length];
System.arraycopy(classFileBuffer, 0, tempBuffer, 0,
classFileBuffer.length);
try {
JiapiClass jc = JiapiClass.parseClass(tempBuffer);
if (transformer.transform(jc)) {
return jc.getByteCode();
}
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
}