001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.proxy.compiler; // IIOPStubCompiler is in this package
023:
024: // because it calls some ProxyAssembler
025: // methods that currently are package
026: // accessible
027:
028: import java.lang.reflect.Method;
029: import java.lang.reflect.Modifier;
030: import java.rmi.RemoteException;
031:
032: import org.jboss.iiop.rmi.AttributeAnalysis;
033: import org.jboss.iiop.rmi.ExceptionAnalysis;
034: import org.jboss.iiop.rmi.InterfaceAnalysis;
035: import org.jboss.iiop.rmi.OperationAnalysis;
036: import org.jboss.iiop.rmi.RMIIIOPViolationException;
037: import org.jboss.iiop.rmi.marshal.CDRStream;
038: import org.jboss.iiop.rmi.marshal.strategy.StubStrategy;
039: import org.jboss.proxy.ejb.DynamicIIOPStub;
040:
041: /**
042: * Utility class responsible for the dynamic generation of bytecodes of
043: * IIOP stub classes.
044: *
045: * @author Unknown
046: * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
047: * @version $Revision: 57194 $
048: */
049: public class IIOPStubCompiler {
050: // Constants --------------------------------------------------------------
051:
052: /**
053: * Parameter type array for <code>StubStrategy.forMethod()</code>
054: * invocations.
055: */
056: private static final Class[] stubStrategyParams = { String[].class,
057: String[].class, String[].class, String.class,
058: ClassLoader.class };
059:
060: /**
061: * Parameter type array for <code>DynamicIIOPStub.invoke()</code>
062: * invocations.
063: */
064: private static final Class[] invokeParams = { String.class,
065: StubStrategy.class, Object[].class };
066:
067: /**
068: * Parameter type array for
069: * <code>org.omg.CORBA.ORB.object_to_string()</code> invocations.
070: */
071: private static final Class[] corbaObjectParam = { org.omg.CORBA.Object.class };
072:
073: /**
074: * Parameter type array for a method that takes a single string parameter.
075: */
076: private static final Class[] stringParam = { String.class };
077:
078: /**
079: * Parameter type array for a method that takes no parameters.
080: */
081: private static final Class[] noParams = {};
082:
083: // Private methods --------------------------------------------------------
084:
085: /**
086: * Returns the name of the stub strategy field associated with the method
087: * whose index is <code>methodIndex</code>.
088: */
089: private static String strategy(int methodIndex) {
090: return "$s" + methodIndex;
091: }
092:
093: /**
094: * Returns the name of static initializer method associated with the method
095: * whose index is <code>methodIndex</code>.
096: */
097: private static String init(int methodIndex) {
098: return "$i" + methodIndex;
099: }
100:
101: /**
102: * Generates the code of a given method within a stub class.
103: *
104: * @param asm the <code>ProxyAssembler</code> used to assemble
105: * the method code
106: * @param superclass the superclass of the stub class within which the
107: * method will be generated
108: * @param m a <code>Method</code> instance describing the
109: * method declaration by an RMI/IDL interface
110: * @param idlName a string with the method name mapped to IDL
111: * @param strategyField a string with the name of the strategy field that
112: * will be associated with the generated method
113: * @param initMethod a string with the name of the static initialization
114: * method that will be associated with the generated
115: * method.
116: */
117: private static void generateMethodCode(ProxyAssembler asm,
118: Class super class, Method m, String idlName,
119: String strategyField, String initMethod) {
120: String methodName = m.getName();
121: Class returnType = m.getReturnType();
122: Class[] paramTypes = m.getParameterTypes();
123: Class[] exceptions = m.getExceptionTypes();
124:
125: // Generate a static field with the StubStrategy for the method
126: asm.addMember(Modifier.PRIVATE + Modifier.STATIC,
127: StubStrategy.class, null, strategyField);
128:
129: // Generate the method code
130: asm.addMember(Modifier.PUBLIC + Modifier.FINAL, returnType,
131: methodName, paramTypes, exceptions);
132: {
133: // The method code issues a call
134: // super.invoke*(idlName, strategyField, args)
135: asm.pushLocal(0); // super (this)
136: asm.pushConstant(idlName);
137: asm.pushField(asm, strategyField);
138: // Push args
139: if (paramTypes.length == 0) {
140: asm.pushField(Util.class, "NOARGS");
141: } else {
142: asm.pushConstant(paramTypes.length);
143: asm.pushNewArray(Object.class);
144: for (int j = 0; j < paramTypes.length; j++) {
145: Class t = paramTypes[j];
146: asm.dup();
147: asm.pushConstant(j);
148: asm.pushLocal(1 + j);
149: if (t.isPrimitive()) {
150: asm.invoke(Util.class, "wrap",
151: new Class[] { t });
152: }
153: asm.setElement(Object.class);
154: }
155: }
156: // Generate the call to a invoke* method ot the superclass
157: String invoke = "invoke";
158: if (returnType.isPrimitive() && returnType != Void.TYPE) {
159: String typeName = returnType.getName();
160: invoke += (Character.toUpperCase(typeName.charAt(0)) + typeName
161: .substring(1));
162: }
163: asm.invoke(super class, invoke, invokeParams);
164: if (!returnType.isPrimitive() && returnType != Object.class) {
165: asm.checkCast(returnType);
166: }
167: asm.ret();
168: }
169:
170: // Generate a static method that initializes the method's strategy field
171: asm.addMember(Modifier.PRIVATE + Modifier.STATIC, Void.TYPE,
172: initMethod, noParams, null);
173: {
174: int i;
175: int len;
176:
177: // Push first argument for StubStrategy constructor:
178: // array with abbreviated names of the param marshallers
179: len = paramTypes.length;
180: asm.pushConstant(len);
181: asm.pushNewArray(String.class);
182: for (i = 0; i < len; i++) {
183: asm.dup();
184: asm.pushConstant(i);
185: asm.pushConstant(CDRStream.abbrevFor(paramTypes[i]));
186: asm.setElement(String.class);
187: }
188:
189: // Push second argument for StubStrategy constructor:
190: // array with exception repository ids
191: len = exceptions.length;
192: int n = 0;
193: for (i = 0; i < len; i++) {
194: if (!RemoteException.class
195: .isAssignableFrom(exceptions[i])) {
196: n++;
197: }
198: }
199: asm.pushConstant(n);
200: asm.pushNewArray(String.class);
201: try {
202: int j = 0;
203: for (i = 0; i < len; i++) {
204: if (!RemoteException.class
205: .isAssignableFrom(exceptions[i])) {
206: asm.dup();
207: asm.pushConstant(j);
208: asm.pushConstant(ExceptionAnalysis
209: .getExceptionAnalysis(exceptions[i])
210: .getExceptionRepositoryId());
211: asm.setElement(String.class);
212: j++;
213: }
214: }
215: } catch (RMIIIOPViolationException e) {
216: throw new RuntimeException("Cannot obtain "
217: + "exception repository id for "
218: + exceptions[i].getName() + ":\n" + e);
219: }
220:
221: // Push third argument for StubStrategy constructor:
222: // array with exception class names
223: asm.pushConstant(n);
224: asm.pushNewArray(String.class);
225: int j = 0;
226: for (i = 0; i < len; i++) {
227: if (!RemoteException.class
228: .isAssignableFrom(exceptions[i])) {
229: asm.dup();
230: asm.pushConstant(j);
231: asm.pushConstant(exceptions[i].getName());
232: asm.setElement(String.class);
233: j++;
234: }
235: }
236:
237: // Push fourth argument for StubStrategy constructor:
238: // abbreviated name of the return value marshaller
239: asm.pushConstant(CDRStream.abbrevFor(returnType));
240:
241: // Push fifth argument for StubStrategy constructor:
242: // null (no ClassLoader specified)
243: asm.pushField(Util.class, "NULLCL");
244:
245: // Constructs the StubStrategy
246: asm.invoke(StubStrategy.class, "forMethod",
247: stubStrategyParams);
248:
249: // Set the strategy field of this stub class
250: asm.setField(asm, strategyField);
251:
252: asm.ret();
253: }
254: }
255:
256: /**
257: * Generates the bytecodes of a stub class for a given interface.
258: *
259: * @param intfaceAnalysis an <code>InterfaceAnalysis</code> instance
260: * describing the RMI/IIOP interface to be
261: * implemented by the stub class
262: * @param superclass the superclass of the stub class
263: * @param stubClassName the name of the stub class
264: * @return a byte array with the generated bytecodes.
265: */
266: private static byte[] generateCode(
267: InterfaceAnalysis interfaceAnalysis, Class super class,
268: String stubClassName) {
269: ProxyAssembler asm = new ProxyAssembler(stubClassName,
270: Modifier.PUBLIC | Modifier.FINAL, super class,
271: new Class[] { interfaceAnalysis.getCls() });
272:
273: int methodIndex = 0;
274:
275: AttributeAnalysis[] attrs = interfaceAnalysis.getAttributes();
276: for (int i = 0; i < attrs.length; i++) {
277: OperationAnalysis op = attrs[i].getAccessorAnalysis();
278: generateMethodCode(asm, super class, op.getMethod(), op
279: .getIDLName(), strategy(methodIndex),
280: init(methodIndex));
281: methodIndex++;
282: op = attrs[i].getMutatorAnalysis();
283: if (op != null) {
284: generateMethodCode(asm, super class, op.getMethod(), op
285: .getIDLName(), strategy(methodIndex),
286: init(methodIndex));
287: methodIndex++;
288: }
289: }
290:
291: OperationAnalysis[] ops = interfaceAnalysis.getOperations();
292: for (int i = 0; i < ops.length; i++) {
293: generateMethodCode(asm, super class, ops[i].getMethod(),
294: ops[i].getIDLName(), strategy(methodIndex),
295: init(methodIndex));
296: methodIndex++;
297: }
298:
299: // Generate the constructor
300: asm.addMember(Modifier.PUBLIC, Void.TYPE, "<init>", noParams,
301: null);
302: {
303: asm.pushLocal(0);
304: asm.invoke(super class, "<init>", noParams);
305: asm.ret();
306: }
307:
308: // Generate the toString() method
309: asm.addMember(Modifier.PUBLIC, String.class, "toString",
310: noParams, null);
311: {
312: {
313: asm.pushConstant("JBossDynStub["
314: + interfaceAnalysis.getCls().getName() + ", ");
315: {
316: {
317: asm.pushLocal(0);
318: asm.invoke(super class, "_orb", noParams);
319: }
320: asm.pushLocal(0);
321: asm.invoke(org.omg.CORBA.ORB.class,
322: "object_to_string", corbaObjectParam);
323: }
324: asm.invoke(String.class, "concat", stringParam);
325: }
326: asm.pushConstant("]");
327: asm.invoke(String.class, "concat", stringParam);
328: asm.ret();
329: }
330:
331: // Generate the method _ids(), declared as abstract in ObjectImpl
332: String[] ids = interfaceAnalysis.getAllTypeIds();
333: asm.addMember(Modifier.PRIVATE + Modifier.STATIC,
334: String[].class, null, "$ids");
335: asm.addMember(Modifier.PUBLIC + Modifier.FINAL, String[].class,
336: "_ids", noParams, null);
337: {
338: asm.pushField(asm, "$ids");
339: asm.ret();
340: }
341:
342: // Generate the static initializer
343: asm.addMember(Modifier.STATIC, Void.TYPE, "<clinit>", noParams,
344: null);
345: {
346: //asm.pushField(System.class, "err");
347: //asm.pushConstant("ENTERING CLASS INITIALIZER !!!!!!!!!!!!!!!!!!!!");
348: //asm.invoke(java.io.PrintStream.class, "println", stringParam);
349:
350: asm.pushConstant(ids.length);
351: asm.pushNewArray(String.class);
352: for (int i = 0; i < ids.length; i++) {
353: asm.dup();
354: asm.pushConstant(i);
355: asm.pushConstant(ids[i]);
356: asm.setElement(String.class);
357: }
358: asm.setField(asm, "$ids");
359:
360: int n = methodIndex; // last methodIndex + 1
361: for (methodIndex = 0; methodIndex < n; methodIndex++) {
362: asm.invoke(asm, init(methodIndex), noParams);
363: }
364:
365: //asm.pushField(System.class, "err");
366: //asm.pushConstant("LEAVING CLASS INITIALIZER !!!!!!!!!!!!!!!!!!!!!");
367: //asm.invoke(java.io.PrintStream.class, "println", stringParam);
368:
369: asm.ret();
370: }
371:
372: return asm.getCode();
373: }
374:
375: /**
376: * Generates the bytecodes of a stub class for a given interface.
377: *
378: * @param intfaceAnalysis an <code>InterfaceAnalysis</code> instance
379: * describing the RMI/IIOP interface to be
380: * implemented by the stub class
381: * @param superclass the superclass of the stub class
382: * @param stubClassName the name of the stub class
383: * @return a byte array with the generated bytecodes.
384: */
385: private static byte[] makeCode(InterfaceAnalysis interfaceAnalysis,
386: Class super class, String stubClassName) {
387:
388: byte code[] = generateCode(interfaceAnalysis, super class,
389: stubClassName);
390: //try {
391: // String fname = stubClassName;
392: // fname = fname.substring(1 + fname.lastIndexOf('.')) + ".class";
393: // fname = "/tmp/" + fname;
394: // java.io.OutputStream cf = new java.io.FileOutputStream(fname);
395: // cf.write(code);
396: // cf.close();
397: // System.err.println("wrote " + fname);
398: //}
399: //catch(java.io.IOException ee) {
400: //}
401: return code;
402: }
403:
404: // Public method ----------------------------------------------------------
405:
406: /**
407: * Generates the bytecodes of a stub class for a given interface.
408: *
409: * @param intf RMI/IIOP interface to be implemented by the
410: * stub class
411: * @param stubClassName the name of the stub class
412: * @return a byte array with the generated bytecodes;
413: */
414: public static byte[] compile(Class intf, String stubClassName) {
415: InterfaceAnalysis interfaceAnalysis = null;
416:
417: try {
418: interfaceAnalysis = InterfaceAnalysis
419: .getInterfaceAnalysis(intf);
420: } catch (RMIIIOPViolationException e) {
421: throw new RuntimeException("RMI/IIOP Violation:\n" + e);
422: }
423: return makeCode(interfaceAnalysis, DynamicIIOPStub.class,
424: stubClassName);
425: }
426:
427: }
|