package it.unina.seclab.jafimon;
import it.unina.seclab.jafimon.util.JaFiMonLogger;
import java.util.Iterator;
import java.util.TreeMap;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.Translator;
/**
* Il <code>CustomTranslator</code> � il componente che viene informato del
* caricamento nella JVM di una specifica classe e su di essa effettua
* realmente le instrumentazioni di runtime se tale classe � una classe
* target. Le instrumentazioni effettuate sono quelle definite nei componenti
* {@link CustomConverter} e {@link CustomEditor} con i quali esso coopera.
* Agisce inoltre in collaborazione con {@link Monitor}.
*
* @author Mauro Iorio
* @see Monitor
* @see CustomEditor
* @see CustomConverter
*
*/
public class CustomTranslator implements Translator {
/**
* La mappa in cui sono memorizzati i <code>CustomConverter</code> di
* ciascuna classe target
*/
private TreeMap converters;
/**
* La mappa in cui sono memorizzati i <code>CustomEditor</code> di
* ciascuna classe target
*/
private TreeMap editors;
//private static final Logger logger = Logger.getRootLogger();
private static final JaFiMonLogger logger = new JaFiMonLogger();
public static final int EDITCAST = 0;
public static final int EDITCONSTRUCTOR = 1;
public static final int EDITFIELDACCESS = 2;
public static final int EDITHANDLER = 3;
public static final int EDITINSTANCEOF = 4;
public static final int EDITMETHODCALL = 5;
public static final int EDITNEWARRAY = 6;
public static final int EDITNEWEXPR = 7;
public CustomTranslator() {
converters = new TreeMap();
editors = new TreeMap();
}
/**
* Instruments all loading classes with <code>CustomConverter</code> and
* <code>CustomEditor</code> instrumentations
*/
public void onLoad(ClassPool pool, String classname) throws NotFoundException, CannotCompileException {
logger.trace("onLoad called for class " + classname);
CtClass clas = pool.get(classname);
if (existEditorForClass(classname))
clas.instrument(getEditorForClass(classname));
if (existConverterForClass(classname))
clas.instrument(getConverterForClass(classname));
// if (classname.equals("it.unina.seclab.jafimon.test.DummyTest")) {
// clas.instrument(new CustomEditor());
// }
}
/**
* Provides initialization for this <code>CustomTranslator</code>.
*/
public void start(ClassPool pool) throws NotFoundException, CannotCompileException {
logger.debug("CustomTranslator start");
Iterator i = converters.values().iterator();
while (i.hasNext()) {
CustomConverter c = (CustomConverter) i.next();
c.init(pool);
}
i = editors.values().iterator();
while (i.hasNext()) {
CustomEditor e = (CustomEditor) i.next();
e.init(pool);
}
}
/**
* Returns info about the existance of a <code>CustomConverter</code> for <code>className</code>
* @param className the class of interest
* @return true if a <code>CustomConverter</code> exists for <code>className</code>.
* false otherwise.
*/
public boolean existConverterForClass(String className) {
return converters.containsKey(className);
}
/**
* Returns info about the existance of a <code>CustomTranslator</code> for <code>className</code>
* @param className the class of interest
* @return true if a <code>CustomTranslator</code> exists for <code>className</code>.
* false otherwise.
*/
public boolean existEditorForClass(String className) {
return editors.containsKey(className);
}
/**
* Returns the <code>CustomConverter</code> for <code>className</code>, eventually
* creating one if it doesn't exist.
* @param className the class of interest
* @return a reference to the only <code>CustomConverter</code> for <code>className</code>
*/
public CustomConverter getConverterForClass(String className) {
if (existConverterForClass(className))
return (CustomConverter) converters.get(className);
else
return null;
}
/**
* Returns the <code>CustomEditor</code> for <code>className</code>, eventually
* creating one if it doesn't exist.
* @param className the class of interest
* @return a reference to the only <code>CustomEditor</code> for <code>className</code>
*/
public CustomEditor getEditorForClass(String className) {
if (existEditorForClass(className))
return (CustomEditor) editors.get(className);
else
return null;
}
/**
* Explicitly creates a new <code>CustomConverter</code> for <code>className</code>
* @param className the class of interest
* @return a reference to the new and only <code>CustomConverter</code> for <code>className</code>
*/
public CustomConverter newConverterForClass(String className) {
if (existConverterForClass(className))
return getConverterForClass(className);
else {
CustomConverter c = new CustomConverter();
converters.put(className, c);
return c;
}
}
/**
* Explicitly creates a new <code>CustomEditor</code> for <code>className</code>
* @param className the class of interest
* @return a reference to the new and only <code>CustomEditor</code> for <code>className</code>
*/
public CustomEditor newEditorForClass(String className, ClassPool pool) {
if (existEditorForClass(className))
return getEditorForClass(className);
else {
CustomEditor e = null;
try {
e = (CustomEditor) pool.get("it.unina.seclab.jafimon.CustomEditor$Impl" + className.substring(className.lastIndexOf(".") + 1)).toClass().newInstance();
} catch (InstantiationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (CannotCompileException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
editors.put(className, e);
return e;
}
}
/**
* Dynamically creates a new method and inserts it into this <code>CustomEditor</code>.
* The new method is a <i>javassist.ExprEditor.edit like</i> method. For more information
* visit Javassist documentation
*
* @param pool the javassist.ClassPool in use
* @param className the class of interest
* @param methodType the type of expression to edit
* @param body the body of the new method
* @throws CannotCompileException if the Java code is not error-free
* @throws NotFoundException the class doesn't exist in the <code>pool</code>
*/
public void instrumentEditor(ClassPool pool, String className, int methodType, String body) throws CannotCompileException, NotFoundException {
CtClass returnType;
String mname;
CtClass[] exceptions;
int modifiers;
CtClass[] parameters;
CtClass declaring;
String fullClassName = "it.unina.seclab.jafimon.CustomEditor$Impl" + className.substring(className.lastIndexOf(".") + 1);
try {
returnType = pool.get("void");
mname = "edit";
exceptions = new CtClass[] { pool.get("javassist.CannotCompileException") };
modifiers = Modifier.PUBLIC;
// Se gia' esiste la recupero
// altrimenti la creo nel pool
try {
declaring = pool.get(fullClassName);
} catch(NotFoundException e) {
declaring = pool.makeClass(fullClassName);
declaring.setSuperclass(pool.get("it.unina.seclab.jafimon.CustomEditor"));
}
switch(methodType) {
case EDITCAST:
parameters = new CtClass[] { pool.get("javassist.expr.Cast") };
break;
case EDITCONSTRUCTOR:
parameters = new CtClass[] { pool.get("javassist.expr.ConstructorCall") };
break;
case EDITFIELDACCESS:
parameters = new CtClass[] { pool.get("javassist.expr.FieldAccess") };
break;
case EDITHANDLER:
parameters = new CtClass[] { pool.get("javassist.expr.Handler") };
break;
case EDITINSTANCEOF:
parameters = new CtClass[] { pool.get("javassist.expr.Instanceof") };
break;
case EDITMETHODCALL:
parameters = new CtClass[] { pool.get("javassist.expr.MethodCall") };
break;
case EDITNEWARRAY:
parameters = new CtClass[] { pool.get("javassist.expr.NewArray") };
break;
case EDITNEWEXPR:
parameters = new CtClass[] { pool.get("javassist.expr.NewExpr") };
break;
default:
throw new CannotCompileException("");
}
CtMethod m = CtNewMethod.make(modifiers, returnType, mname, parameters, exceptions, body, declaring);
declaring.addMethod(m);
} catch (Exception e) {
throw new CannotCompileException(e);
}
}
}