package sample.evolve; import java.util.Hashtable; import java.lang.reflect.*; /** * Runtime system for class evolution */ public class VersionManager { private static Hashtable versionNo = new Hashtable(); public final static String latestVersionField = "_version"; /** * For updating the definition of class my.X, say: * * VersionManager.update("my.X"); */ public static void update(String qualifiedClassname) throws CannotUpdateException { try { Class c = getUpdatedClass(qualifiedClassname); Field f = c.getField(latestVersionField); f.set(null, c); } catch (ClassNotFoundException e) { throw new CannotUpdateException("cannot update class: " + qualifiedClassname); } catch (Exception e) { throw new CannotUpdateException(e); } } private static Class getUpdatedClass(String qualifiedClassname) throws ClassNotFoundException { int version; Object found = versionNo.get(qualifiedClassname); if (found == null) version = 0; else version = ((Integer)found).intValue() + 1; Class c = Class.forName(qualifiedClassname + '$' + version); versionNo.put(qualifiedClassname, new Integer(version)); return c; } /* * initiaVersion() is used to initialize the _version field of the updatable * classes. */ public static Class initialVersion(String[] params) { try { return getUpdatedClass(params[0]); } catch (ClassNotFoundException e) { throw new RuntimeException("cannot initialize " + params[0]); } } /** * make() performs the object creation of the updatable classes. The * expression "new " is replaced with a call to this * method. */ public static Object make(Class clazz, Object[] args) { Constructor[] constructors = clazz.getConstructors(); int n = constructors.length; for (int i = 0; i < n; ++i) { try { return constructors[i].newInstance(args); } catch (IllegalArgumentException e) { // try again } catch (InstantiationException e) { throw new CannotCreateException(e); } catch (IllegalAccessException e) { throw new CannotCreateException(e); } catch (InvocationTargetException e) { throw new CannotCreateException(e); } } throw new CannotCreateException("no constructor matches"); } }