/Users/lyon/j4p/src/javassist/rmi/StubGenerator.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16 package javassist.rmi;
17
18 import javassist.*;
19 import javassist.CtMethod.ConstParameter;
20
21 import java.lang.reflect.Method;
22 import java.util.Hashtable;
23
24 /**
25 * A stub-code generator. It is used for producing a proxy class.
26 *
27 * <p>The proxy class for class A is as follows:
28 *
29 * <ul><pre>public class A implements Proxy, Serializable {
30 * private ObjectImporter importer;
31 * private int objectId;
32 * public int _getObjectId() { return objectId; }
33 * public A(ObjectImporter oi, int id) {
34 * importer = oi; objectId = id;
35 * }
36 *
37 * ... the same methods that the original class A declares ...
38 * }</pre></ul>
39 *
40 * <p>Instances of the proxy class are created by an
41 * <code>ObjectImporter</code> object.
42 */
43 public class StubGenerator implements Translator {
44 private static final String fieldImporter = "importer";
45 private static final String fieldObjectId = "objectId";
46 private static final String accessorObjectId = "_getObjectId";
47 private static final String sampleClass = "javassist.rmi.Sample";
48
49 private ClassPool classPool;
50 private Hashtable proxyClasses;
51 private CtMethod forwardMethod;
52 private CtMethod forwardStaticMethod;
53
54 private CtClass[] proxyConstructorParamTypes;
55 private CtClass[] interfacesForProxy;
56 private CtClass[] exceptionForProxy;
57
58 /**
59 * Constructs a stub-code generator.
60 */
61 public StubGenerator() {
62 proxyClasses = new Hashtable();
63 }
64
65 /**
66 * Is a method declared in javassist.Translator.
67 *
68 * @see javassist.Translator#start(ClassPool)
69 */
70 public void start(ClassPool pool) throws NotFoundException {
71 classPool = pool;
72 CtClass c = pool.get(sampleClass);
73 forwardMethod = c.getDeclaredMethod("forward");
74 forwardStaticMethod = c.getDeclaredMethod("forwardStatic");
75
76 proxyConstructorParamTypes
77 = pool.get(new String[]{"javassist.rmi.ObjectImporter",
78 "int"});
79 interfacesForProxy
80 = pool.get(new String[]{"java.io.Serializable",
81 "javassist.rmi.Proxy"});
82 exceptionForProxy
83 = new CtClass[]{pool.get("javassist.rmi.RemoteException")};
84 }
85
86 public void onWrite(ClassPool pool, String classname) {
87 }
88
89 /**
90 * Returns <code>true</code> if the specified class is a proxy class
91 * recorded by <code>makeProxyClass()</code>.
92 *
93 * @param name a fully-qualified class name
94 */
95 public boolean isProxyClass(String name) {
96 return proxyClasses.get(name) != null;
97 }
98
99 /**
100 * Makes a proxy class. The produced class is substituted
101 * for the original class.
102 *
103 * @param clazz the class referenced
104 * through the proxy class.
105 * @return <code>false</code> if the proxy class
106 * has been already produced.
107 */
108 public synchronized boolean makeProxyClass(Class clazz)
109 throws CannotCompileException, NotFoundException {
110 String classname = clazz.getName();
111 if (proxyClasses.get(classname) != null)
112 return false;
113 else {
114 CtClass ctclazz = produceProxyClass(classPool.get(classname),
115 clazz);
116 proxyClasses.put(classname, ctclazz);
117 modifySuperclass(ctclazz);
118 return true;
119 }
120 }
121
122 private CtClass produceProxyClass(CtClass orgclass, Class orgRtClass)
123 throws CannotCompileException, NotFoundException {
124 int modify = orgclass.getModifiers();
125 if (Modifier.isAbstract(modify) || Modifier.isNative(modify)
126 || !Modifier.isPublic(modify))
127 throw new CannotCompileException(orgclass.getName()
128 + " must be public, non-native, and non-abstract.");
129
130 CtClass proxy;
131 proxy = (CtClass) classPool.makeClass(orgclass.getName(),
132 orgclass.getSuperclass());
133
134 proxy.setInterfaces(interfacesForProxy);
135
136 CtField f
137 = new CtField(classPool.get("javassist.rmi.ObjectImporter"),
138 fieldImporter, proxy);
139 f.setModifiers(Modifier.PRIVATE);
140 proxy.addField(f, CtField.Initializer.byParameter(0));
141
142 f = new CtField(CtClass.intType, fieldObjectId, proxy);
143 f.setModifiers(Modifier.PRIVATE);
144 proxy.addField(f, CtField.Initializer.byParameter(1));
145
146 proxy.addMethod(CtNewMethod.getter(accessorObjectId, f));
147
148 proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy));
149 CtConstructor cons
150 = CtNewConstructor.skeleton(proxyConstructorParamTypes,
151 null, proxy);
152 proxy.addConstructor(cons);
153
154 try {
155 addMethods(proxy, orgRtClass.getMethods());
156 return proxy;
157 } catch (SecurityException e) {
158 throw new CannotCompileException(e);
159 }
160 }
161
162 private CtClass toCtClass(Class rtclass) throws NotFoundException {
163 String name;
164 if (!rtclass.isArray())
165 name = rtclass.getName();
166 else {
167 StringBuffer sbuf = new StringBuffer();
168 do {
169 sbuf.append("[]");
170 rtclass = rtclass.getComponentType();
171 } while (rtclass.isArray());
172 sbuf.insert(0, rtclass.getName());
173 name = sbuf.toString();
174 }
175
176 return classPool.get(name);
177 }
178
179 private CtClass[] toCtClass(Class[] rtclasses) throws NotFoundException {
180 int n = rtclasses.length;
181 CtClass[] ctclasses = new CtClass[n];
182 for (int i = 0; i < n; ++i)
183 ctclasses[i] = toCtClass(rtclasses[i]);
184
185 return ctclasses;
186 }
187
188 /* ms must not be an array of CtMethod. To invoke a method ms[i]
189 * on a server, a client must send i to the server.
190 */
191 private void addMethods(CtClass proxy, Method[] ms)
192 throws CannotCompileException, NotFoundException {
193 CtMethod wmethod;
194 for (int i = 0; i < ms.length; ++i) {
195 Method m = ms[i];
196 int mod = m.getModifiers();
197 if (m.getDeclaringClass() != Object.class
198 && !Modifier.isFinal(mod))
199 if (Modifier.isPublic(mod)) {
200 CtMethod body;
201 if (Modifier.isStatic(mod))
202 body = forwardStaticMethod;
203 else
204 body = forwardMethod;
205
206 wmethod
207 = CtNewMethod.wrapped(toCtClass(m.getReturnType()),
208 m.getName(),
209 toCtClass(m.getParameterTypes()),
210 exceptionForProxy,
211 body,
212 ConstParameter.integer(i),
213 proxy);
214 wmethod.setModifiers(mod);
215 proxy.addMethod(wmethod);
216 } else if (!Modifier.isProtected(mod)
217 && !Modifier.isPrivate(mod))
218 // if package method
219 throw new CannotCompileException(
220 "the methods must be public, protected, or private.");
221 }
222 }
223
224 /**
225 * Adds a default constructor to the super classes.
226 */
227 private void modifySuperclass(CtClass orgclass)
228 throws CannotCompileException, NotFoundException {
229 CtClass superclazz;
230 for (; ; orgclass = superclazz) {
231 superclazz = orgclass.getSuperclass();
232 if (superclazz == null)
233 break;
234 try {
235 superclazz.getDeclaredConstructor(null);
236 break; // the constructor with no arguments is found.
237 } catch (NotFoundException e) {
238 }
239
240 superclazz.addConstructor(
241 CtNewConstructor.defaultConstructor(superclazz));
242 }
243 }
244 }
245