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