/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