package sample.evolve;\r
\r
import javassist.*;\r
-import java.io.IOException;\r
\r
/**\r
* Evolution provides a set of methods for instrumenting bytecodes.\r
- *\r
- * For class evolution, updatable class A is renamed to B. Then an\r
- * abstract class named A is produced as the super class of B. If the\r
- * original class A has a public method m(), then the abstract class A\r
- * has an abstract method m().\r
- *\r
- * abstract class A\r
- * abstract m()\r
- * _makeInstance()\r
- * |\r
- * class A --------> class B\r
- * m() m()\r
- *\r
- * Also, all the other classes are translated so that "new A(i)"\r
- * in the methods is replaced with "_makeInstance(i)". This makes\r
- * it possible to change the behavior of the instantiation of\r
- * the class A.\r
+ * \r
+ * For class evolution, updatable class A is renamed to B. Then an abstract\r
+ * class named A is produced as the super class of B. If the original class A\r
+ * has a public method m(), then the abstract class A has an abstract method\r
+ * m().\r
+ * \r
+ * abstract class A abstract m() _makeInstance() | class A --------> class B m()\r
+ * m()\r
+ * \r
+ * Also, all the other classes are translated so that "new A(i)" in the methods\r
+ * is replaced with "_makeInstance(i)". This makes it possible to change the\r
+ * behavior of the instantiation of the class A.\r
*/\r
public class Evolution implements Translator {\r
public final static String handlerMethod = "_makeInstance";\r
- public final static String latestVersionField\r
- = VersionManager.latestVersionField;\r
+\r
+ public final static String latestVersionField = VersionManager.latestVersionField;\r
+\r
public final static String versionManagerMethod = "initialVersion";\r
\r
private static CtMethod trapMethod;\r
+\r
private static final int initialVersion = 0;\r
+\r
private ClassPool pool;\r
+\r
private String updatableClassName = null;\r
+\r
private CtClass updatableClass = null;\r
\r
public void start(ClassPool _pool) throws NotFoundException {\r
- pool = _pool;\r
+ pool = _pool;\r
\r
- // Get the definition of Sample.make() and store it into trapMethod\r
- // for later use.\r
- trapMethod = _pool.getMethod("sample.evolve.Sample", "make");\r
+ // Get the definition of Sample.make() and store it into trapMethod\r
+ // for later use.\r
+ trapMethod = _pool.getMethod("sample.evolve.Sample", "make");\r
}\r
\r
public void onLoad(ClassPool _pool, String classname)\r
- throws NotFoundException, CannotCompileException\r
- {\r
- onLoadUpdatable(classname);\r
-\r
- /*\r
- * Replaces all the occurrences of the new operator with a call\r
- * to _makeInstance().\r
- */\r
- CtClass clazz = _pool.get(classname);\r
- CtClass absClass = updatableClass;\r
- CodeConverter converter = new CodeConverter();\r
- converter.replaceNew(absClass, absClass, handlerMethod);\r
- clazz.instrument(converter);\r
+ throws NotFoundException, CannotCompileException {\r
+ onLoadUpdatable(classname);\r
+\r
+ /*\r
+ * Replaces all the occurrences of the new operator with a call to\r
+ * _makeInstance().\r
+ */\r
+ CtClass clazz = _pool.get(classname);\r
+ CtClass absClass = updatableClass;\r
+ CodeConverter converter = new CodeConverter();\r
+ converter.replaceNew(absClass, absClass, handlerMethod);\r
+ clazz.instrument(converter);\r
}\r
\r
- private void onLoadUpdatable(String classname)\r
- throws NotFoundException, CannotCompileException\r
- {\r
- // if the class is a concrete class,\r
- // classname is <updatableClassName>$<version>.\r
-\r
- int i = classname.lastIndexOf('$');\r
- if (i <= 0)\r
- return;\r
-\r
- String orgname = classname.substring(0, i);\r
- if (!orgname.equals(updatableClassName))\r
- return;\r
-\r
- int version;\r
- try {\r
- version = Integer.parseInt(classname.substring(i + 1));\r
- }\r
- catch (NumberFormatException e) {\r
- throw new NotFoundException(classname, e);\r
- }\r
-\r
- CtClass clazz = pool.getAndRename(orgname, classname);\r
- makeConcreteClass(clazz, updatableClass, version);\r
+ private void onLoadUpdatable(String classname) throws NotFoundException,\r
+ CannotCompileException {\r
+ // if the class is a concrete class,\r
+ // classname is <updatableClassName>$<version>.\r
+\r
+ int i = classname.lastIndexOf('$');\r
+ if (i <= 0)\r
+ return;\r
+\r
+ String orgname = classname.substring(0, i);\r
+ if (!orgname.equals(updatableClassName))\r
+ return;\r
+\r
+ int version;\r
+ try {\r
+ version = Integer.parseInt(classname.substring(i + 1));\r
+ }\r
+ catch (NumberFormatException e) {\r
+ throw new NotFoundException(classname, e);\r
+ }\r
+\r
+ CtClass clazz = pool.getAndRename(orgname, classname);\r
+ makeConcreteClass(clazz, updatableClass, version);\r
}\r
\r
- /* Register an updatable class.\r
+ /*\r
+ * Register an updatable class.\r
*/\r
- public void makeUpdatable(String classname)\r
- throws NotFoundException, CannotCompileException\r
- {\r
- if (pool == null)\r
- throw new RuntimeException(\r
- "Evolution has not been linked to ClassPool.");\r
-\r
- CtClass c = pool.get(classname);\r
- updatableClassName = classname;\r
- updatableClass = makeAbstractClass(c);\r
+ public void makeUpdatable(String classname) throws NotFoundException,\r
+ CannotCompileException {\r
+ if (pool == null)\r
+ throw new RuntimeException(\r
+ "Evolution has not been linked to ClassPool.");\r
+\r
+ CtClass c = pool.get(classname);\r
+ updatableClassName = classname;\r
+ updatableClass = makeAbstractClass(c);\r
}\r
\r
/**\r
* Produces an abstract class.\r
*/\r
protected CtClass makeAbstractClass(CtClass clazz)\r
- throws CannotCompileException, NotFoundException\r
- {\r
- int i;\r
-\r
- CtClass absClass = pool.makeClass(clazz.getName());\r
- absClass.setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);\r
- absClass.setSuperclass(clazz.getSuperclass());\r
- absClass.setInterfaces(clazz.getInterfaces());\r
-\r
- // absClass.inheritAllConstructors();\r
-\r
- CtField fld = new CtField(pool.get("java.lang.Class"),\r
- latestVersionField, absClass);\r
- fld.setModifiers(Modifier.PUBLIC | Modifier.STATIC);\r
-\r
- CtField.Initializer finit\r
- = CtField.Initializer.byCall(\r
- pool.get("sample.evolve.VersionManager"),\r
- versionManagerMethod,\r
- new String[] { clazz.getName() });\r
- absClass.addField(fld, finit);\r
-\r
- CtField[] fs = clazz.getDeclaredFields();\r
- for (i = 0; i < fs.length; ++i) {\r
- CtField f = fs[i];\r
- if (Modifier.isPublic(f.getModifiers()))\r
- absClass.addField(new CtField(f.getType(), f.getName(),\r
- absClass));\r
- }\r
-\r
- CtConstructor[] cs = clazz.getDeclaredConstructors();\r
- for (i = 0; i < cs.length; ++i) {\r
- CtConstructor c = cs[i];\r
- int mod = c.getModifiers();\r
- if (Modifier.isPublic(mod)) {\r
- CtMethod wm\r
- = CtNewMethod.wrapped(absClass, handlerMethod,\r
- c.getParameterTypes(),\r
- c.getExceptionTypes(),\r
- trapMethod, null, absClass);\r
- wm.setModifiers(Modifier.PUBLIC | Modifier.STATIC);\r
- absClass.addMethod(wm);\r
- }\r
- }\r
-\r
- CtMethod[] ms = clazz.getDeclaredMethods();\r
- for (i = 0; i < ms.length; ++i) {\r
- CtMethod m = ms[i];\r
- int mod = m.getModifiers();\r
- if (Modifier.isPublic(mod))\r
- if (Modifier.isStatic(mod))\r
- throw new CannotCompileException(\r
- "static methods are not supported.");\r
- else {\r
- CtMethod m2\r
- = CtNewMethod.abstractMethod(m.getReturnType(),\r
- m.getName(),\r
- m.getParameterTypes(),\r
- m.getExceptionTypes(),\r
- absClass);\r
- absClass.addMethod(m2);\r
- }\r
- }\r
-\r
- return absClass;\r
+ throws CannotCompileException, NotFoundException {\r
+ int i;\r
+\r
+ CtClass absClass = pool.makeClass(clazz.getName());\r
+ absClass.setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);\r
+ absClass.setSuperclass(clazz.getSuperclass());\r
+ absClass.setInterfaces(clazz.getInterfaces());\r
+\r
+ // absClass.inheritAllConstructors();\r
+\r
+ CtField fld = new CtField(pool.get("java.lang.Class"),\r
+ latestVersionField, absClass);\r
+ fld.setModifiers(Modifier.PUBLIC | Modifier.STATIC);\r
+\r
+ CtField.Initializer finit = CtField.Initializer.byCall(pool\r
+ .get("sample.evolve.VersionManager"), versionManagerMethod,\r
+ new String[] { clazz.getName() });\r
+ absClass.addField(fld, finit);\r
+\r
+ CtField[] fs = clazz.getDeclaredFields();\r
+ for (i = 0; i < fs.length; ++i) {\r
+ CtField f = fs[i];\r
+ if (Modifier.isPublic(f.getModifiers()))\r
+ absClass.addField(new CtField(f.getType(), f.getName(),\r
+ absClass));\r
+ }\r
+\r
+ CtConstructor[] cs = clazz.getDeclaredConstructors();\r
+ for (i = 0; i < cs.length; ++i) {\r
+ CtConstructor c = cs[i];\r
+ int mod = c.getModifiers();\r
+ if (Modifier.isPublic(mod)) {\r
+ CtMethod wm = CtNewMethod.wrapped(absClass, handlerMethod, c\r
+ .getParameterTypes(), c.getExceptionTypes(),\r
+ trapMethod, null, absClass);\r
+ wm.setModifiers(Modifier.PUBLIC | Modifier.STATIC);\r
+ absClass.addMethod(wm);\r
+ }\r
+ }\r
+\r
+ CtMethod[] ms = clazz.getDeclaredMethods();\r
+ for (i = 0; i < ms.length; ++i) {\r
+ CtMethod m = ms[i];\r
+ int mod = m.getModifiers();\r
+ if (Modifier.isPublic(mod))\r
+ if (Modifier.isStatic(mod))\r
+ throw new CannotCompileException(\r
+ "static methods are not supported.");\r
+ else {\r
+ CtMethod m2 = CtNewMethod.abstractMethod(m.getReturnType(),\r
+ m.getName(), m.getParameterTypes(), m\r
+ .getExceptionTypes(), absClass);\r
+ absClass.addMethod(m2);\r
+ }\r
+ }\r
+\r
+ return absClass;\r
}\r
\r
/**\r
- * Modifies the given class file so that it is a subclass of the\r
- * abstract class produced by makeAbstractClass().\r
- *\r
+ * Modifies the given class file so that it is a subclass of the abstract\r
+ * class produced by makeAbstractClass().\r
+ * \r
* Note: the naming convention must be consistent with\r
* VersionManager.update().\r
*/\r
- protected void makeConcreteClass(CtClass clazz,\r
- CtClass abstractClass, int version)\r
- throws CannotCompileException, NotFoundException\r
- {\r
- int i;\r
- clazz.setSuperclass(abstractClass);\r
- CodeConverter converter = new CodeConverter();\r
- CtField[] fs = clazz.getDeclaredFields();\r
- for (i = 0; i < fs.length; ++i) {\r
- CtField f = fs[i];\r
- if (Modifier.isPublic(f.getModifiers()))\r
- converter.redirectFieldAccess(f, abstractClass, f.getName());\r
- }\r
-\r
- CtConstructor[] cs = clazz.getDeclaredConstructors();\r
- for (i = 0; i < cs.length; ++i)\r
- cs[i].instrument(converter);\r
-\r
- CtMethod[] ms = clazz.getDeclaredMethods();\r
- for (i = 0; i < ms.length; ++i)\r
- ms[i].instrument(converter);\r
+ protected void makeConcreteClass(CtClass clazz, CtClass abstractClass,\r
+ int version) throws CannotCompileException, NotFoundException {\r
+ int i;\r
+ clazz.setSuperclass(abstractClass);\r
+ CodeConverter converter = new CodeConverter();\r
+ CtField[] fs = clazz.getDeclaredFields();\r
+ for (i = 0; i < fs.length; ++i) {\r
+ CtField f = fs[i];\r
+ if (Modifier.isPublic(f.getModifiers()))\r
+ converter.redirectFieldAccess(f, abstractClass, f.getName());\r
+ }\r
+\r
+ CtConstructor[] cs = clazz.getDeclaredConstructors();\r
+ for (i = 0; i < cs.length; ++i)\r
+ cs[i].instrument(converter);\r
+\r
+ CtMethod[] ms = clazz.getDeclaredMethods();\r
+ for (i = 0; i < ms.length; ++i)\r
+ ms[i].instrument(converter);\r
}\r
}\r
\r
import java.util.Hashtable;\r
import java.lang.reflect.*;\r
-import javassist.CtClass;\r
\r
/**\r
* Runtime system for class evolution\r
*/\r
public class VersionManager {\r
private static Hashtable versionNo = new Hashtable();\r
+\r
public final static String latestVersionField = "_version";\r
\r
/**\r
* For updating the definition of class my.X, say:\r
- *\r
+ * \r
* VersionManager.update("my.X");\r
*/\r
public static void update(String qualifiedClassname)\r
- throws CannotUpdateException\r
- {\r
- try {\r
- Class c = getUpdatedClass(qualifiedClassname);\r
- Field f = c.getField(latestVersionField);\r
- f.set(null, c);\r
- }\r
- catch (ClassNotFoundException e) {\r
- throw new CannotUpdateException("cannot update class: "\r
- + qualifiedClassname);\r
- }\r
- catch (Exception e) {\r
- throw new CannotUpdateException(e);\r
- }\r
+ throws CannotUpdateException {\r
+ try {\r
+ Class c = getUpdatedClass(qualifiedClassname);\r
+ Field f = c.getField(latestVersionField);\r
+ f.set(null, c);\r
+ }\r
+ catch (ClassNotFoundException e) {\r
+ throw new CannotUpdateException("cannot update class: "\r
+ + qualifiedClassname);\r
+ }\r
+ catch (Exception e) {\r
+ throw new CannotUpdateException(e);\r
+ }\r
}\r
\r
private static Class getUpdatedClass(String qualifiedClassname)\r
- throws ClassNotFoundException\r
- {\r
- int version;\r
- Object found = versionNo.get(qualifiedClassname);\r
- if (found == null)\r
- version = 0;\r
- else\r
- version = ((Integer)found).intValue() + 1;\r
+ throws ClassNotFoundException {\r
+ int version;\r
+ Object found = versionNo.get(qualifiedClassname);\r
+ if (found == null)\r
+ version = 0;\r
+ else\r
+ version = ((Integer)found).intValue() + 1;\r
\r
- Class c = Class.forName(qualifiedClassname + '$' + version);\r
- versionNo.put(qualifiedClassname, new Integer(version));\r
- return c;\r
+ Class c = Class.forName(qualifiedClassname + '$' + version);\r
+ versionNo.put(qualifiedClassname, new Integer(version));\r
+ return c;\r
}\r
\r
- /* initiaVersion() is used to initialize the _version field of\r
- * the updatable classes.\r
+ /*\r
+ * initiaVersion() is used to initialize the _version field of the updatable\r
+ * classes.\r
*/\r
public static Class initialVersion(String[] params) {\r
- try {\r
- return getUpdatedClass(params[0]);\r
- }\r
- catch (ClassNotFoundException e) {\r
- throw new RuntimeException("cannot initialize " + params[0]);\r
- }\r
+ try {\r
+ return getUpdatedClass(params[0]);\r
+ }\r
+ catch (ClassNotFoundException e) {\r
+ throw new RuntimeException("cannot initialize " + params[0]);\r
+ }\r
}\r
\r
- /** make() performs the object creation of the updatable classes.\r
- * The expression "new <updatable class>" is replaced with a call\r
- * to this method.\r
+ /**\r
+ * make() performs the object creation of the updatable classes. The\r
+ * expression "new <updatable class>" is replaced with a call to this\r
+ * method.\r
*/\r
public static Object make(Class clazz, Object[] args) {\r
- Constructor[] constructors = clazz.getConstructors();\r
- int n = constructors.length;\r
- for (int i = 0; i < n; ++i) {\r
- try {\r
- return constructors[i].newInstance(args);\r
- }\r
- catch (IllegalArgumentException e) {\r
- // try again\r
- }\r
- catch (InstantiationException e) {\r
- throw new CannotCreateException(e);\r
- }\r
- catch (IllegalAccessException e) {\r
- throw new CannotCreateException(e);\r
- }\r
- catch (InvocationTargetException e) {\r
- throw new CannotCreateException(e);\r
- }\r
- }\r
+ Constructor[] constructors = clazz.getConstructors();\r
+ int n = constructors.length;\r
+ for (int i = 0; i < n; ++i) {\r
+ try {\r
+ return constructors[i].newInstance(args);\r
+ }\r
+ catch (IllegalArgumentException e) {\r
+ // try again\r
+ }\r
+ catch (InstantiationException e) {\r
+ throw new CannotCreateException(e);\r
+ }\r
+ catch (IllegalAccessException e) {\r
+ throw new CannotCreateException(e);\r
+ }\r
+ catch (InvocationTargetException e) {\r
+ throw new CannotCreateException(e);\r
+ }\r
+ }\r
\r
- throw new CannotCreateException("no constructor matches");\r
+ throw new CannotCreateException("no constructor matches");\r
}\r
}\r