1*f1fbf3c2SXin Li package sample.evolve; 2*f1fbf3c2SXin Li 3*f1fbf3c2SXin Li import javassist.*; 4*f1fbf3c2SXin Li 5*f1fbf3c2SXin Li /** 6*f1fbf3c2SXin Li * Evolution provides a set of methods for instrumenting bytecodes. 7*f1fbf3c2SXin Li * 8*f1fbf3c2SXin Li * For class evolution, updatable class A is renamed to B. Then an abstract 9*f1fbf3c2SXin Li * class named A is produced as the super class of B. If the original class A 10*f1fbf3c2SXin Li * has a public method m(), then the abstract class A has an abstract method 11*f1fbf3c2SXin Li * m(). 12*f1fbf3c2SXin Li * 13*f1fbf3c2SXin Li * abstract class A abstract m() _makeInstance() | class A --------> class B m() 14*f1fbf3c2SXin Li * m() 15*f1fbf3c2SXin Li * 16*f1fbf3c2SXin Li * Also, all the other classes are translated so that "new A(i)" in the methods 17*f1fbf3c2SXin Li * is replaced with "_makeInstance(i)". This makes it possible to change the 18*f1fbf3c2SXin Li * behavior of the instantiation of the class A. 19*f1fbf3c2SXin Li */ 20*f1fbf3c2SXin Li public class Evolution implements Translator { 21*f1fbf3c2SXin Li public final static String handlerMethod = "_makeInstance"; 22*f1fbf3c2SXin Li 23*f1fbf3c2SXin Li public final static String latestVersionField = VersionManager.latestVersionField; 24*f1fbf3c2SXin Li 25*f1fbf3c2SXin Li public final static String versionManagerMethod = "initialVersion"; 26*f1fbf3c2SXin Li 27*f1fbf3c2SXin Li private static CtMethod trapMethod; 28*f1fbf3c2SXin Li 29*f1fbf3c2SXin Li private static final int initialVersion = 0; 30*f1fbf3c2SXin Li 31*f1fbf3c2SXin Li private ClassPool pool; 32*f1fbf3c2SXin Li 33*f1fbf3c2SXin Li private String updatableClassName = null; 34*f1fbf3c2SXin Li 35*f1fbf3c2SXin Li private CtClass updatableClass = null; 36*f1fbf3c2SXin Li start(ClassPool _pool)37*f1fbf3c2SXin Li public void start(ClassPool _pool) throws NotFoundException { 38*f1fbf3c2SXin Li pool = _pool; 39*f1fbf3c2SXin Li 40*f1fbf3c2SXin Li // Get the definition of Sample.make() and store it into trapMethod 41*f1fbf3c2SXin Li // for later use. 42*f1fbf3c2SXin Li trapMethod = _pool.getMethod("sample.evolve.Sample", "make"); 43*f1fbf3c2SXin Li } 44*f1fbf3c2SXin Li onLoad(ClassPool _pool, String classname)45*f1fbf3c2SXin Li public void onLoad(ClassPool _pool, String classname) 46*f1fbf3c2SXin Li throws NotFoundException, CannotCompileException { 47*f1fbf3c2SXin Li onLoadUpdatable(classname); 48*f1fbf3c2SXin Li 49*f1fbf3c2SXin Li /* 50*f1fbf3c2SXin Li * Replaces all the occurrences of the new operator with a call to 51*f1fbf3c2SXin Li * _makeInstance(). 52*f1fbf3c2SXin Li */ 53*f1fbf3c2SXin Li CtClass clazz = _pool.get(classname); 54*f1fbf3c2SXin Li CtClass absClass = updatableClass; 55*f1fbf3c2SXin Li CodeConverter converter = new CodeConverter(); 56*f1fbf3c2SXin Li converter.replaceNew(absClass, absClass, handlerMethod); 57*f1fbf3c2SXin Li clazz.instrument(converter); 58*f1fbf3c2SXin Li } 59*f1fbf3c2SXin Li onLoadUpdatable(String classname)60*f1fbf3c2SXin Li private void onLoadUpdatable(String classname) throws NotFoundException, 61*f1fbf3c2SXin Li CannotCompileException { 62*f1fbf3c2SXin Li // if the class is a concrete class, 63*f1fbf3c2SXin Li // classname is <updatableClassName>$$<version>. 64*f1fbf3c2SXin Li 65*f1fbf3c2SXin Li int i = classname.lastIndexOf("$$"); 66*f1fbf3c2SXin Li if (i <= 0) 67*f1fbf3c2SXin Li return; 68*f1fbf3c2SXin Li 69*f1fbf3c2SXin Li String orgname = classname.substring(0, i); 70*f1fbf3c2SXin Li if (!orgname.equals(updatableClassName)) 71*f1fbf3c2SXin Li return; 72*f1fbf3c2SXin Li 73*f1fbf3c2SXin Li int version; 74*f1fbf3c2SXin Li try { 75*f1fbf3c2SXin Li version = Integer.parseInt(classname.substring(i + 2)); 76*f1fbf3c2SXin Li } 77*f1fbf3c2SXin Li catch (NumberFormatException e) { 78*f1fbf3c2SXin Li throw new NotFoundException(classname, e); 79*f1fbf3c2SXin Li } 80*f1fbf3c2SXin Li 81*f1fbf3c2SXin Li CtClass clazz = pool.getAndRename(orgname, classname); 82*f1fbf3c2SXin Li makeConcreteClass(clazz, updatableClass, version); 83*f1fbf3c2SXin Li } 84*f1fbf3c2SXin Li 85*f1fbf3c2SXin Li /* 86*f1fbf3c2SXin Li * Register an updatable class. 87*f1fbf3c2SXin Li */ makeUpdatable(String classname)88*f1fbf3c2SXin Li public void makeUpdatable(String classname) throws NotFoundException, 89*f1fbf3c2SXin Li CannotCompileException { 90*f1fbf3c2SXin Li if (pool == null) 91*f1fbf3c2SXin Li throw new RuntimeException( 92*f1fbf3c2SXin Li "Evolution has not been linked to ClassPool."); 93*f1fbf3c2SXin Li 94*f1fbf3c2SXin Li CtClass c = pool.get(classname); 95*f1fbf3c2SXin Li updatableClassName = classname; 96*f1fbf3c2SXin Li updatableClass = makeAbstractClass(c); 97*f1fbf3c2SXin Li } 98*f1fbf3c2SXin Li 99*f1fbf3c2SXin Li /** 100*f1fbf3c2SXin Li * Produces an abstract class. 101*f1fbf3c2SXin Li */ makeAbstractClass(CtClass clazz)102*f1fbf3c2SXin Li protected CtClass makeAbstractClass(CtClass clazz) 103*f1fbf3c2SXin Li throws CannotCompileException, NotFoundException { 104*f1fbf3c2SXin Li int i; 105*f1fbf3c2SXin Li 106*f1fbf3c2SXin Li CtClass absClass = pool.makeClass(clazz.getName()); 107*f1fbf3c2SXin Li absClass.setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT); 108*f1fbf3c2SXin Li absClass.setSuperclass(clazz.getSuperclass()); 109*f1fbf3c2SXin Li absClass.setInterfaces(clazz.getInterfaces()); 110*f1fbf3c2SXin Li 111*f1fbf3c2SXin Li // absClass.inheritAllConstructors(); 112*f1fbf3c2SXin Li 113*f1fbf3c2SXin Li CtField fld = new CtField(pool.get("java.lang.Class"), 114*f1fbf3c2SXin Li latestVersionField, absClass); 115*f1fbf3c2SXin Li fld.setModifiers(Modifier.PUBLIC | Modifier.STATIC); 116*f1fbf3c2SXin Li 117*f1fbf3c2SXin Li CtField.Initializer finit = CtField.Initializer.byCall(pool 118*f1fbf3c2SXin Li .get("sample.evolve.VersionManager"), versionManagerMethod, 119*f1fbf3c2SXin Li new String[] { clazz.getName() }); 120*f1fbf3c2SXin Li absClass.addField(fld, finit); 121*f1fbf3c2SXin Li 122*f1fbf3c2SXin Li CtField[] fs = clazz.getDeclaredFields(); 123*f1fbf3c2SXin Li for (i = 0; i < fs.length; ++i) { 124*f1fbf3c2SXin Li CtField f = fs[i]; 125*f1fbf3c2SXin Li if (Modifier.isPublic(f.getModifiers())) 126*f1fbf3c2SXin Li absClass.addField(new CtField(f.getType(), f.getName(), 127*f1fbf3c2SXin Li absClass)); 128*f1fbf3c2SXin Li } 129*f1fbf3c2SXin Li 130*f1fbf3c2SXin Li CtConstructor[] cs = clazz.getDeclaredConstructors(); 131*f1fbf3c2SXin Li for (i = 0; i < cs.length; ++i) { 132*f1fbf3c2SXin Li CtConstructor c = cs[i]; 133*f1fbf3c2SXin Li int mod = c.getModifiers(); 134*f1fbf3c2SXin Li if (Modifier.isPublic(mod)) { 135*f1fbf3c2SXin Li CtMethod wm = CtNewMethod.wrapped(absClass, handlerMethod, c 136*f1fbf3c2SXin Li .getParameterTypes(), c.getExceptionTypes(), 137*f1fbf3c2SXin Li trapMethod, null, absClass); 138*f1fbf3c2SXin Li wm.setModifiers(Modifier.PUBLIC | Modifier.STATIC); 139*f1fbf3c2SXin Li absClass.addMethod(wm); 140*f1fbf3c2SXin Li } 141*f1fbf3c2SXin Li } 142*f1fbf3c2SXin Li 143*f1fbf3c2SXin Li CtMethod[] ms = clazz.getDeclaredMethods(); 144*f1fbf3c2SXin Li for (i = 0; i < ms.length; ++i) { 145*f1fbf3c2SXin Li CtMethod m = ms[i]; 146*f1fbf3c2SXin Li int mod = m.getModifiers(); 147*f1fbf3c2SXin Li if (Modifier.isPublic(mod)) 148*f1fbf3c2SXin Li if (Modifier.isStatic(mod)) 149*f1fbf3c2SXin Li throw new CannotCompileException( 150*f1fbf3c2SXin Li "static methods are not supported."); 151*f1fbf3c2SXin Li else { 152*f1fbf3c2SXin Li CtMethod m2 = CtNewMethod.abstractMethod(m.getReturnType(), 153*f1fbf3c2SXin Li m.getName(), m.getParameterTypes(), m 154*f1fbf3c2SXin Li .getExceptionTypes(), absClass); 155*f1fbf3c2SXin Li absClass.addMethod(m2); 156*f1fbf3c2SXin Li } 157*f1fbf3c2SXin Li } 158*f1fbf3c2SXin Li 159*f1fbf3c2SXin Li return absClass; 160*f1fbf3c2SXin Li } 161*f1fbf3c2SXin Li 162*f1fbf3c2SXin Li /** 163*f1fbf3c2SXin Li * Modifies the given class file so that it is a subclass of the abstract 164*f1fbf3c2SXin Li * class produced by makeAbstractClass(). 165*f1fbf3c2SXin Li * 166*f1fbf3c2SXin Li * Note: the naming convention must be consistent with 167*f1fbf3c2SXin Li * VersionManager.update(). 168*f1fbf3c2SXin Li */ makeConcreteClass(CtClass clazz, CtClass abstractClass, int version)169*f1fbf3c2SXin Li protected void makeConcreteClass(CtClass clazz, CtClass abstractClass, 170*f1fbf3c2SXin Li int version) throws CannotCompileException, NotFoundException { 171*f1fbf3c2SXin Li int i; 172*f1fbf3c2SXin Li clazz.setSuperclass(abstractClass); 173*f1fbf3c2SXin Li CodeConverter converter = new CodeConverter(); 174*f1fbf3c2SXin Li CtField[] fs = clazz.getDeclaredFields(); 175*f1fbf3c2SXin Li for (i = 0; i < fs.length; ++i) { 176*f1fbf3c2SXin Li CtField f = fs[i]; 177*f1fbf3c2SXin Li if (Modifier.isPublic(f.getModifiers())) 178*f1fbf3c2SXin Li converter.redirectFieldAccess(f, abstractClass, f.getName()); 179*f1fbf3c2SXin Li } 180*f1fbf3c2SXin Li 181*f1fbf3c2SXin Li CtConstructor[] cs = clazz.getDeclaredConstructors(); 182*f1fbf3c2SXin Li for (i = 0; i < cs.length; ++i) 183*f1fbf3c2SXin Li cs[i].instrument(converter); 184*f1fbf3c2SXin Li 185*f1fbf3c2SXin Li CtMethod[] ms = clazz.getDeclaredMethods(); 186*f1fbf3c2SXin Li for (i = 0; i < ms.length; ++i) 187*f1fbf3c2SXin Li ms[i].instrument(converter); 188*f1fbf3c2SXin Li } 189*f1fbf3c2SXin Li } 190