You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Evolution.java 6.7KB

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