1*f1fbf3c2SXin Li package sample.evolve; 2*f1fbf3c2SXin Li 3*f1fbf3c2SXin Li import java.util.Hashtable; 4*f1fbf3c2SXin Li import java.lang.reflect.*; 5*f1fbf3c2SXin Li 6*f1fbf3c2SXin Li /** 7*f1fbf3c2SXin Li * Runtime system for class evolution 8*f1fbf3c2SXin Li */ 9*f1fbf3c2SXin Li public class VersionManager { 10*f1fbf3c2SXin Li private static Hashtable versionNo = new Hashtable(); 11*f1fbf3c2SXin Li 12*f1fbf3c2SXin Li public final static String latestVersionField = "_version"; 13*f1fbf3c2SXin Li 14*f1fbf3c2SXin Li /** 15*f1fbf3c2SXin Li * For updating the definition of class my.X, say: 16*f1fbf3c2SXin Li * 17*f1fbf3c2SXin Li * VersionManager.update("my.X"); 18*f1fbf3c2SXin Li */ update(String qualifiedClassname)19*f1fbf3c2SXin Li public static void update(String qualifiedClassname) 20*f1fbf3c2SXin Li throws CannotUpdateException { 21*f1fbf3c2SXin Li try { 22*f1fbf3c2SXin Li Class c = getUpdatedClass(qualifiedClassname); 23*f1fbf3c2SXin Li Field f = c.getField(latestVersionField); 24*f1fbf3c2SXin Li f.set(null, c); 25*f1fbf3c2SXin Li } 26*f1fbf3c2SXin Li catch (ClassNotFoundException e) { 27*f1fbf3c2SXin Li throw new CannotUpdateException("cannot update class: " 28*f1fbf3c2SXin Li + qualifiedClassname); 29*f1fbf3c2SXin Li } 30*f1fbf3c2SXin Li catch (Exception e) { 31*f1fbf3c2SXin Li throw new CannotUpdateException(e); 32*f1fbf3c2SXin Li } 33*f1fbf3c2SXin Li } 34*f1fbf3c2SXin Li getUpdatedClass(String qualifiedClassname)35*f1fbf3c2SXin Li private static Class getUpdatedClass(String qualifiedClassname) 36*f1fbf3c2SXin Li throws ClassNotFoundException { 37*f1fbf3c2SXin Li int version; 38*f1fbf3c2SXin Li Object found = versionNo.get(qualifiedClassname); 39*f1fbf3c2SXin Li if (found == null) 40*f1fbf3c2SXin Li version = 0; 41*f1fbf3c2SXin Li else 42*f1fbf3c2SXin Li version = ((Integer)found).intValue() + 1; 43*f1fbf3c2SXin Li 44*f1fbf3c2SXin Li Class c = Class.forName(qualifiedClassname + "$$" + version); 45*f1fbf3c2SXin Li versionNo.put(qualifiedClassname, new Integer(version)); 46*f1fbf3c2SXin Li return c; 47*f1fbf3c2SXin Li } 48*f1fbf3c2SXin Li 49*f1fbf3c2SXin Li /* 50*f1fbf3c2SXin Li * initiaVersion() is used to initialize the _version field of the updatable 51*f1fbf3c2SXin Li * classes. 52*f1fbf3c2SXin Li */ initialVersion(String[] params)53*f1fbf3c2SXin Li public static Class initialVersion(String[] params) { 54*f1fbf3c2SXin Li try { 55*f1fbf3c2SXin Li return getUpdatedClass(params[0]); 56*f1fbf3c2SXin Li } 57*f1fbf3c2SXin Li catch (ClassNotFoundException e) { 58*f1fbf3c2SXin Li throw new RuntimeException("cannot initialize " + params[0]); 59*f1fbf3c2SXin Li } 60*f1fbf3c2SXin Li } 61*f1fbf3c2SXin Li 62*f1fbf3c2SXin Li /** 63*f1fbf3c2SXin Li * make() performs the object creation of the updatable classes. The 64*f1fbf3c2SXin Li * expression "new <updatable class>" is replaced with a call to this 65*f1fbf3c2SXin Li * method. 66*f1fbf3c2SXin Li */ make(Class clazz, Object[] args)67*f1fbf3c2SXin Li public static Object make(Class clazz, Object[] args) { 68*f1fbf3c2SXin Li Constructor[] constructors = clazz.getConstructors(); 69*f1fbf3c2SXin Li int n = constructors.length; 70*f1fbf3c2SXin Li for (int i = 0; i < n; ++i) { 71*f1fbf3c2SXin Li try { 72*f1fbf3c2SXin Li return constructors[i].newInstance(args); 73*f1fbf3c2SXin Li } 74*f1fbf3c2SXin Li catch (IllegalArgumentException e) { 75*f1fbf3c2SXin Li // try again 76*f1fbf3c2SXin Li } 77*f1fbf3c2SXin Li catch (InstantiationException e) { 78*f1fbf3c2SXin Li throw new CannotCreateException(e); 79*f1fbf3c2SXin Li } 80*f1fbf3c2SXin Li catch (IllegalAccessException e) { 81*f1fbf3c2SXin Li throw new CannotCreateException(e); 82*f1fbf3c2SXin Li } 83*f1fbf3c2SXin Li catch (InvocationTargetException e) { 84*f1fbf3c2SXin Li throw new CannotCreateException(e); 85*f1fbf3c2SXin Li } 86*f1fbf3c2SXin Li } 87*f1fbf3c2SXin Li 88*f1fbf3c2SXin Li throw new CannotCreateException("no constructor matches"); 89*f1fbf3c2SXin Li } 90*f1fbf3c2SXin Li } 91