KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sample > evolve > Evolution


1 package sample.evolve;
2
3 import javassist.*;
4 import java.io.IOException JavaDoc;
5
6 /**
7  * Evolution provides a set of methods for instrumenting bytecodes.
8  *
9  * For class evolution, updatable class A is renamed to B. Then an
10  * abstract class named A is produced as the super class of B. If the
11  * original class A has a public method m(), then the abstract class A
12  * has an abstract method m().
13  *
14  * abstract class A
15  * abstract m()
16  * _makeInstance()
17  * |
18  * class A --------> class B
19  * m() m()
20  *
21  * Also, all the other classes are translated so that "new A(i)"
22  * in the methods is replaced with "_makeInstance(i)". This makes
23  * it possible to change the behavior of the instantiation of
24  * the class A.
25  */

26 public class Evolution implements Translator {
27     public final static String JavaDoc handlerMethod = "_makeInstance";
28     public final static String JavaDoc latestVersionField
29                 = VersionManager.latestVersionField;
30     public final static String JavaDoc versionManagerMethod = "initialVersion";
31
32     private static CtMethod trapMethod;
33     private static final int initialVersion = 0;
34     private ClassPool pool;
35     private String JavaDoc updatableClassName = null;
36     private CtClass updatableClass = null;
37
38     public void start(ClassPool _pool) throws NotFoundException {
39     pool = _pool;
40
41     // Get the definition of Sample.make() and store it into trapMethod
42
// for later use.
43
trapMethod = _pool.getMethod("sample.evolve.Sample", "make");
44     }
45
46     public void onLoad(ClassPool _pool, String JavaDoc classname)
47     throws NotFoundException, CannotCompileException
48     {
49     onLoadUpdatable(classname);
50
51     /*
52      * Replaces all the occurrences of the new operator with a call
53      * to _makeInstance().
54      */

55     CtClass clazz = _pool.get(classname);
56     CtClass absClass = updatableClass;
57     CodeConverter converter = new CodeConverter();
58     converter.replaceNew(absClass, absClass, handlerMethod);
59     clazz.instrument(converter);
60     }
61
62     private void onLoadUpdatable(String JavaDoc classname)
63     throws NotFoundException, CannotCompileException
64     {
65     // if the class is a concrete class,
66
// classname is <updatableClassName>$<version>.
67

68     int i = classname.lastIndexOf('$');
69     if (i <= 0)
70         return;
71
72     String JavaDoc orgname = classname.substring(0, i);
73     if (!orgname.equals(updatableClassName))
74         return;
75
76     int version;
77     try {
78         version = Integer.parseInt(classname.substring(i + 1));
79     }
80     catch (NumberFormatException JavaDoc e) {
81         throw new NotFoundException(classname, e);
82     }
83
84     CtClass clazz = pool.getAndRename(orgname, classname);
85     makeConcreteClass(clazz, updatableClass, version);
86     }
87
88     /* Register an updatable class.
89      */

90     public void makeUpdatable(String JavaDoc classname)
91     throws NotFoundException, CannotCompileException
92     {
93     if (pool == null)
94         throw new RuntimeException JavaDoc(
95                "Evolution has not been linked to ClassPool.");
96
97     CtClass c = pool.get(classname);
98     updatableClassName = classname;
99     updatableClass = makeAbstractClass(c);
100     }
101
102     /**
103      * Produces an abstract class.
104      */

105     protected CtClass makeAbstractClass(CtClass clazz)
106     throws CannotCompileException, NotFoundException
107     {
108     int i;
109
110     CtClass absClass = pool.makeClass(clazz.getName());
111     absClass.setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);
112     absClass.setSuperclass(clazz.getSuperclass());
113     absClass.setInterfaces(clazz.getInterfaces());
114
115     // absClass.inheritAllConstructors();
116

117     CtField fld = new CtField(pool.get("java.lang.Class"),
118                   latestVersionField, absClass);
119     fld.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
120
121     CtField.Initializer finit
122         = CtField.Initializer.byCall(
123         pool.get("sample.evolve.VersionManager"),
124         versionManagerMethod,
125         new String JavaDoc[] { clazz.getName() });
126     absClass.addField(fld, finit);
127
128     CtField[] fs = clazz.getDeclaredFields();
129     for (i = 0; i < fs.length; ++i) {
130         CtField f = fs[i];
131         if (Modifier.isPublic(f.getModifiers()))
132         absClass.addField(new CtField(f.getType(), f.getName(),
133                           absClass));
134     }
135
136     CtConstructor[] cs = clazz.getDeclaredConstructors();
137     for (i = 0; i < cs.length; ++i) {
138         CtConstructor c = cs[i];
139         int mod = c.getModifiers();
140         if (Modifier.isPublic(mod)) {
141         CtMethod wm
142             = CtNewMethod.wrapped(absClass, handlerMethod,
143                       c.getParameterTypes(),
144                       c.getExceptionTypes(),
145                       trapMethod, null, absClass);
146         wm.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
147         absClass.addMethod(wm);
148         }
149     }
150
151     CtMethod[] ms = clazz.getDeclaredMethods();
152     for (i = 0; i < ms.length; ++i) {
153         CtMethod m = ms[i];
154         int mod = m.getModifiers();
155         if (Modifier.isPublic(mod))
156         if (Modifier.isStatic(mod))
157             throw new CannotCompileException(
158                 "static methods are not supported.");
159         else {
160             CtMethod m2
161             = CtNewMethod.abstractMethod(m.getReturnType(),
162                              m.getName(),
163                              m.getParameterTypes(),
164                              m.getExceptionTypes(),
165                              absClass);
166             absClass.addMethod(m2);
167         }
168     }
169
170     return absClass;
171     }
172
173     /**
174      * Modifies the given class file so that it is a subclass of the
175      * abstract class produced by makeAbstractClass().
176      *
177      * Note: the naming convention must be consistent with
178      * VersionManager.update().
179      */

180     protected void makeConcreteClass(CtClass clazz,
181                      CtClass abstractClass, int version)
182     throws CannotCompileException, NotFoundException
183     {
184     int i;
185     clazz.setSuperclass(abstractClass);
186     CodeConverter converter = new CodeConverter();
187     CtField[] fs = clazz.getDeclaredFields();
188     for (i = 0; i < fs.length; ++i) {
189         CtField f = fs[i];
190         if (Modifier.isPublic(f.getModifiers()))
191         converter.redirectFieldAccess(f, abstractClass, f.getName());
192     }
193
194     CtConstructor[] cs = clazz.getDeclaredConstructors();
195     for (i = 0; i < cs.length; ++i)
196         cs[i].instrument(converter);
197
198     CtMethod[] ms = clazz.getDeclaredMethods();
199     for (i = 0; i < ms.length; ++i)
200         ms[i].instrument(converter);
201     }
202 }
203
Popular Tags