169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage sample.evolve; 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Hashtable; 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.*; 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Runtime system for class evolution 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class VersionManager { 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static Hashtable versionNo = new Hashtable(); 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public final static String latestVersionField = "_version"; 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * For updating the definition of class my.X, say: 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * VersionManager.update("my.X"); 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static void update(String qualifiedClassname) 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotUpdateException { 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Class c = getUpdatedClass(qualifiedClassname); 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Field f = c.getField(latestVersionField); 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal f.set(null, c); 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (ClassNotFoundException e) { 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotUpdateException("cannot update class: " 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + qualifiedClassname); 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (Exception e) { 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotUpdateException(e); 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static Class getUpdatedClass(String qualifiedClassname) 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws ClassNotFoundException { 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int version; 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Object found = versionNo.get(qualifiedClassname); 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (found == null) 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal version = 0; 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal version = ((Integer)found).intValue() + 1; 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Class c = Class.forName(qualifiedClassname + "$$" + version); 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal versionNo.put(qualifiedClassname, new Integer(version)); 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return c; 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * initiaVersion() is used to initialize the _version field of the updatable 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * classes. 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static Class initialVersion(String[] params) { 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return getUpdatedClass(params[0]); 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (ClassNotFoundException e) { 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException("cannot initialize " + params[0]); 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * make() performs the object creation of the updatable classes. The 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * expression "new <updatable class>" is replaced with a call to this 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * method. 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static Object make(Class clazz, Object[] args) { 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Constructor[] constructors = clazz.getConstructors(); 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int n = constructors.length; 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < n; ++i) { 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return constructors[i].newInstance(args); 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (IllegalArgumentException e) { 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // try again 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (InstantiationException e) { 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCreateException(e); 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (IllegalAccessException e) { 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCreateException(e); 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (InvocationTargetException e) { 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCreateException(e); 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCreateException("no constructor matches"); 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 91