KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > proxy > compiler > IIOPStubCompiler


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.proxy.compiler; // IIOPStubCompiler is in this package
23
// because it calls some ProxyAssembler
24
// methods that currently are package
25
// accessible
26

27 import java.lang.reflect.Method JavaDoc;
28 import java.lang.reflect.Modifier JavaDoc;
29 import java.rmi.RemoteException JavaDoc;
30
31 import org.jboss.iiop.rmi.AttributeAnalysis;
32 import org.jboss.iiop.rmi.ExceptionAnalysis;
33 import org.jboss.iiop.rmi.InterfaceAnalysis;
34 import org.jboss.iiop.rmi.OperationAnalysis;
35 import org.jboss.iiop.rmi.RMIIIOPViolationException;
36 import org.jboss.iiop.rmi.marshal.CDRStream;
37 import org.jboss.iiop.rmi.marshal.strategy.StubStrategy;
38 import org.jboss.proxy.ejb.DynamicIIOPStub;
39
40 /**
41  * Utility class responsible for the dynamic generation of bytecodes of
42  * IIOP stub classes.
43  *
44  * @author Unknown
45  * @author <a HREF="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
46  * @version $Revision: 37459 $
47  */

48 public class IIOPStubCompiler
49 {
50    // Constants --------------------------------------------------------------
51

52    /**
53     * Parameter type array for <code>StubStrategy.forMethod()</code>
54     * invocations.
55     */

56    private static final Class JavaDoc[] stubStrategyParams = {
57       String JavaDoc[].class, String JavaDoc[].class, String JavaDoc[].class, String JavaDoc.class,
58       ClassLoader JavaDoc.class
59    };
60    
61    /**
62     * Parameter type array for <code>DynamicIIOPStub.invoke()</code>
63     * invocations.
64     */

65    private static final Class JavaDoc[] invokeParams = {
66       String JavaDoc.class, StubStrategy.class, Object JavaDoc[].class
67    };
68
69    /**
70     * Parameter type array for
71     * <code>org.omg.CORBA.ORB.object_to_string()</code> invocations.
72     */

73    private static final Class JavaDoc[] corbaObjectParam = {
74       org.omg.CORBA.Object JavaDoc.class
75    };
76    
77    /**
78     * Parameter type array for a method that takes a single string parameter.
79     */

80    private static final Class JavaDoc[] stringParam = {
81       String JavaDoc.class
82    };
83
84    /**
85     * Parameter type array for a method that takes no parameters.
86     */

87    private static final Class JavaDoc[] noParams = { };
88
89    // Private methods --------------------------------------------------------
90

91    /**
92     * Returns the name of the stub strategy field associated with the method
93     * whose index is <code>methodIndex</code>.
94     */

95    private static String JavaDoc strategy(int methodIndex) {
96       return "$s" + methodIndex;
97    }
98    
99    /**
100     * Returns the name of static initializer method associated with the method
101     * whose index is <code>methodIndex</code>.
102     */

103    private static String JavaDoc init(int methodIndex) {
104       return "$i" + methodIndex;
105    }
106
107    /**
108     * Generates the code of a given method within a stub class.
109     *
110     * @param asm the <code>ProxyAssembler</code> used to assemble
111     * the method code
112     * @param superclass the superclass of the stub class within which the
113     * method will be generated
114     * @param m a <code>Method</code> instance describing the
115     * method declaration by an RMI/IDL interface
116     * @param idlName a string with the method name mapped to IDL
117     * @param strategyField a string with the name of the strategy field that
118     * will be associated with the generated method
119     * @param initMethod a string with the name of the static initialization
120     * method that will be associated with the generated
121     * method.
122     */

123    private static void generateMethodCode(ProxyAssembler asm,
124                                           Class JavaDoc superclass,
125                                           Method JavaDoc m,
126                                           String JavaDoc idlName,
127                                           String JavaDoc strategyField,
128                                           String JavaDoc initMethod)
129    {
130       String JavaDoc methodName = m.getName();
131       Class JavaDoc returnType = m.getReturnType();
132       Class JavaDoc[] paramTypes = m.getParameterTypes();
133       Class JavaDoc[] exceptions = m.getExceptionTypes();
134
135       // Generate a static field with the StubStrategy for the method
136
asm.addMember(Modifier.PRIVATE + Modifier.STATIC,
137                     StubStrategy.class, null, strategyField);
138
139       // Generate the method code
140
asm.addMember(Modifier.PUBLIC + Modifier.FINAL,
141                     returnType, methodName, paramTypes, exceptions);
142       {
143          // The method code issues a call
144
// super.invoke*(idlName, strategyField, args)
145
asm.pushLocal(0); // super (this)
146
asm.pushConstant(idlName);
147          asm.pushField(asm, strategyField);
148          // Push args
149
if (paramTypes.length == 0) {
150             asm.pushField(Util.class, "NOARGS");
151          } else {
152             asm.pushConstant(paramTypes.length);
153             asm.pushNewArray(Object JavaDoc.class);
154             for (int j = 0; j < paramTypes.length; j++) {
155                Class JavaDoc t = paramTypes[j];
156                asm.dup();
157                asm.pushConstant(j);
158                asm.pushLocal(1 + j);
159                if (t.isPrimitive()) {
160                   asm.invoke(Util.class, "wrap", new Class JavaDoc[]{ t });
161                }
162                asm.setElement(Object JavaDoc.class);
163             }
164          }
165          // Generate the call to a invoke* method ot the superclass
166
String JavaDoc invoke = "invoke";
167          if (returnType.isPrimitive() && returnType != Void.TYPE) {
168             String JavaDoc typeName = returnType.getName();
169             invoke += (Character.toUpperCase(typeName.charAt(0))
170                        + typeName.substring(1));
171          }
172          asm.invoke(superclass, invoke, invokeParams);
173          if (!returnType.isPrimitive() && returnType != Object JavaDoc.class) {
174             asm.checkCast(returnType);
175          }
176          asm.ret();
177       }
178
179       // Generate a static method that initializes the method's strategy field
180
asm.addMember(Modifier.PRIVATE + Modifier.STATIC,
181                     Void.TYPE, initMethod, noParams, null);
182       {
183          int i;
184          int len;
185
186          // Push first argument for StubStrategy constructor:
187
// array with abbreviated names of the param marshallers
188
len = paramTypes.length;
189          asm.pushConstant(len);
190          asm.pushNewArray(String JavaDoc.class);
191          for (i = 0; i < len; i++) {
192             asm.dup();
193             asm.pushConstant(i);
194             asm.pushConstant(CDRStream.abbrevFor(paramTypes[i]));
195             asm.setElement(String JavaDoc.class);
196          }
197
198          // Push second argument for StubStrategy constructor:
199
// array with exception repository ids
200
len = exceptions.length;
201          int n = 0;
202          for (i = 0; i < len; i++) {
203             if (!RemoteException JavaDoc.class.isAssignableFrom(exceptions[i])) {
204                n++;
205             }
206          }
207          asm.pushConstant(n);
208          asm.pushNewArray(String JavaDoc.class);
209          try {
210             int j = 0;
211             for (i = 0; i < len; i++) {
212                if (!RemoteException JavaDoc.class.isAssignableFrom(exceptions[i])) {
213                   asm.dup();
214                   asm.pushConstant(j);
215                   asm.pushConstant(
216                         ExceptionAnalysis.getExceptionAnalysis(exceptions[i])
217                                          .getExceptionRepositoryId());
218                   asm.setElement(String JavaDoc.class);
219                   j++;
220                }
221             }
222          }
223          catch (RMIIIOPViolationException e) {
224             throw new RuntimeException JavaDoc("Cannot obtain "
225                                        + "exception repository id for "
226                                        + exceptions[i].getName() + ":\n" + e);
227          }
228
229          // Push third argument for StubStrategy constructor:
230
// array with exception class names
231
asm.pushConstant(n);
232          asm.pushNewArray(String JavaDoc.class);
233          int j = 0;
234          for (i = 0; i < len; i++) {
235             if (!RemoteException JavaDoc.class.isAssignableFrom(exceptions[i])) {
236                asm.dup();
237                asm.pushConstant(j);
238                asm.pushConstant(exceptions[i].getName());
239                asm.setElement(String JavaDoc.class);
240                j++;
241             }
242          }
243
244          // Push fourth argument for StubStrategy constructor:
245
// abbreviated name of the return value marshaller
246
asm.pushConstant(CDRStream.abbrevFor(returnType));
247
248          // Push fifth argument for StubStrategy constructor:
249
// null (no ClassLoader specified)
250
asm.pushField(Util.class, "NULLCL");
251
252          // Constructs the StubStrategy
253
asm.invoke(StubStrategy.class, "forMethod", stubStrategyParams);
254
255          // Set the strategy field of this stub class
256
asm.setField(asm, strategyField);
257
258          asm.ret();
259       }
260    }
261
262    /**
263     * Generates the bytecodes of a stub class for a given interface.
264     *
265     * @param intfaceAnalysis an <code>InterfaceAnalysis</code> instance
266     * describing the RMI/IIOP interface to be
267     * implemented by the stub class
268     * @param superclass the superclass of the stub class
269     * @param stubClassName the name of the stub class
270     * @return a byte array with the generated bytecodes.
271     */

272    private static byte[] generateCode(InterfaceAnalysis interfaceAnalysis,
273                                       Class JavaDoc superclass, String JavaDoc stubClassName)
274    {
275       ProxyAssembler asm =
276          new ProxyAssembler(stubClassName,
277                             Modifier.PUBLIC | Modifier.FINAL,
278                             superclass,
279                             new Class JavaDoc[] { interfaceAnalysis.getCls() });
280
281       int methodIndex = 0;
282       
283       AttributeAnalysis[] attrs = interfaceAnalysis.getAttributes();
284       for (int i = 0; i < attrs.length; i++) {
285          OperationAnalysis op = attrs[i].getAccessorAnalysis();
286          generateMethodCode(asm, superclass, op.getMethod(), op.getIDLName(),
287                             strategy(methodIndex), init(methodIndex));
288          methodIndex++;
289          op = attrs[i].getMutatorAnalysis();
290          if (op != null) {
291             generateMethodCode(asm, superclass,
292                                op.getMethod(), op.getIDLName(),
293                                strategy(methodIndex), init(methodIndex));
294             methodIndex++;
295          }
296       }
297       
298       OperationAnalysis[] ops = interfaceAnalysis.getOperations();
299       for (int i = 0; i < ops.length; i++) {
300          generateMethodCode(asm, superclass,
301                             ops[i].getMethod(), ops[i].getIDLName(),
302                             strategy(methodIndex), init(methodIndex));
303          methodIndex++;
304       }
305
306       // Generate the constructor
307
asm.addMember(Modifier.PUBLIC, Void.TYPE, "<init>", noParams, null);
308       {
309          asm.pushLocal(0);
310          asm.invoke(superclass, "<init>", noParams);
311          asm.ret();
312       }
313
314       // Generate the toString() method
315
asm.addMember(Modifier.PUBLIC, String JavaDoc.class, "toString", noParams, null);
316       {
317          {
318             asm.pushConstant("JBossDynStub["
319                              + interfaceAnalysis.getCls().getName() + ", ");
320             {
321                {
322                   asm.pushLocal(0);
323                   asm.invoke(superclass, "_orb", noParams);
324                }
325                asm.pushLocal(0);
326                asm.invoke(org.omg.CORBA.ORB JavaDoc.class,
327                           "object_to_string", corbaObjectParam);
328             }
329             asm.invoke(String JavaDoc.class, "concat", stringParam);
330          }
331          asm.pushConstant("]");
332          asm.invoke(String JavaDoc.class, "concat", stringParam);
333          asm.ret();
334       }
335
336       // Generate the method _ids(), declared as abstract in ObjectImpl
337
String JavaDoc[] ids = interfaceAnalysis.getAllTypeIds();
338       asm.addMember(Modifier.PRIVATE + Modifier.STATIC, String JavaDoc[].class,
339                     null, "$ids");
340       asm.addMember(Modifier.PUBLIC + Modifier.FINAL,
341                     String JavaDoc[].class, "_ids", noParams, null);
342       {
343          asm.pushField(asm, "$ids");
344          asm.ret();
345       }
346
347       // Generate the static initializer
348
asm.addMember(Modifier.STATIC, Void.TYPE, "<clinit>", noParams, null);
349       {
350          //asm.pushField(System.class, "err");
351
//asm.pushConstant("ENTERING CLASS INITIALIZER !!!!!!!!!!!!!!!!!!!!");
352
//asm.invoke(java.io.PrintStream.class, "println", stringParam);
353

354          asm.pushConstant(ids.length);
355          asm.pushNewArray(String JavaDoc.class);
356          for (int i = 0; i < ids.length; i++) {
357             asm.dup();
358             asm.pushConstant(i);
359             asm.pushConstant(ids[i]);
360             asm.setElement(String JavaDoc.class);
361          }
362          asm.setField(asm, "$ids");
363          
364          int n = methodIndex; // last methodIndex + 1
365
for (methodIndex = 0; methodIndex < n; methodIndex++) {
366             asm.invoke(asm, init(methodIndex), noParams);
367          }
368
369          //asm.pushField(System.class, "err");
370
//asm.pushConstant("LEAVING CLASS INITIALIZER !!!!!!!!!!!!!!!!!!!!!");
371
//asm.invoke(java.io.PrintStream.class, "println", stringParam);
372

373          asm.ret();
374       }
375
376       return asm.getCode();
377    }
378
379    /**
380     * Generates the bytecodes of a stub class for a given interface.
381     *
382     * @param intfaceAnalysis an <code>InterfaceAnalysis</code> instance
383     * describing the RMI/IIOP interface to be
384     * implemented by the stub class
385     * @param superclass the superclass of the stub class
386     * @param stubClassName the name of the stub class
387     * @return a byte array with the generated bytecodes.
388     */

389    private static byte[] makeCode(InterfaceAnalysis interfaceAnalysis,
390                                   Class JavaDoc superclass, String JavaDoc stubClassName)
391    {
392       
393       byte code[] = generateCode(interfaceAnalysis, superclass, stubClassName);
394       //try {
395
// String fname = stubClassName;
396
// fname = fname.substring(1 + fname.lastIndexOf('.')) + ".class";
397
// fname = "/tmp/" + fname;
398
// java.io.OutputStream cf = new java.io.FileOutputStream(fname);
399
// cf.write(code);
400
// cf.close();
401
// System.err.println("wrote " + fname);
402
//}
403
//catch(java.io.IOException ee) {
404
//}
405
return code;
406    }
407    
408    // Public method ----------------------------------------------------------
409

410    /**
411     * Generates the bytecodes of a stub class for a given interface.
412     *
413     * @param intf RMI/IIOP interface to be implemented by the
414     * stub class
415     * @param stubClassName the name of the stub class
416     * @return a byte array with the generated bytecodes;
417     */

418    public static byte[] compile(Class JavaDoc intf, String JavaDoc stubClassName)
419    {
420       InterfaceAnalysis interfaceAnalysis = null;
421       
422       try {
423          interfaceAnalysis = InterfaceAnalysis.getInterfaceAnalysis(intf);
424       }
425       catch (RMIIIOPViolationException e) {
426          throw new RuntimeException JavaDoc("RMI/IIOP Violation:\n" + e);
427       }
428       return makeCode(interfaceAnalysis, DynamicIIOPStub.class, stubClassName);
429    }
430
431 }
432
Popular Tags