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;
023:
024: import org.apache.bcel.Constants;
025: import org.apache.bcel.classfile.Field;
026: import org.apache.bcel.classfile.Method;
027:
028: import org.apache.bcel.generic.ArrayType;
029: import org.apache.bcel.generic.BasicType;
030: import org.apache.bcel.generic.ConstantPoolGen;
031: import org.apache.bcel.generic.ClassGen;
032: import org.apache.bcel.generic.FieldGen;
033: import org.apache.bcel.generic.Instruction;
034: import org.apache.bcel.generic.InstructionFactory;
035: import org.apache.bcel.generic.InstructionList;
036: import org.apache.bcel.generic.MethodGen;
037: import org.apache.bcel.generic.ObjectType;
038: import org.apache.bcel.generic.PUSH;
039: import org.apache.bcel.generic.ReferenceType;
040: import org.apache.bcel.generic.Type;
041:
042: /**
043: * Factory to create the bytecode implementation of various methods
044: * required by the ProxyCompiler.
045: *
046: * @version <tt>$Revision: 57209 $</tt>
047: * @author <a href="mailto:neale@isismanor.co.uk">Neale Swinnerton</a>
048: * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
049: */
050: public class ProxyImplementationFactory {
051: // Class Names
052: private final static String RUNTIME_CN = Runtime.class.getName();
053: private final static String INVOCATION_HANDLER_CN = InvocationHandler.class
054: .getName();
055: private final static String STRING_BUFFER_CN = StringBuffer.class
056: .getName();
057:
058: // Types
059: private final static ObjectType RUNTIME_T = (ObjectType) Utility
060: .getType(Runtime.class);
061: private final static ObjectType INVOCATION_HANDLER_T = (ObjectType) Utility
062: .getType(InvocationHandler.class);
063: private final static ArrayType ARRAY_OF_CLASS_T = new ArrayType(
064: "java.lang.Class", 1);
065: private final static ObjectType OBJECT_T = new ObjectType(
066: "java.lang.Object");
067: private final static ArrayType ARRAY_OF_OBJECT_T = new ArrayType(
068: "java.lang.Object", 1);
069: private final static ObjectType STRING_T = new ObjectType(
070: "java.lang.String");
071: private final static ObjectType STRING_BUFFER_T = new ObjectType(
072: "java.lang.StringBuffer");
073: private final static ObjectType PROXY_TARGET_T = new ObjectType(
074: Proxies.ProxyTarget.class.getName());
075: private final static Type[] INVOKE_ARGS = { INVOCATION_HANDLER_T,
076: Type.INT, ARRAY_OF_OBJECT_T };
077: // Method Names
078: private final static String GET_INVOCATION_HANDLER_MN = "getInvocationHandler";
079: private final static String GET_TARGET_TYPES_MN = "getTargetTypes";
080: private final static String TO_STRING_MN = "toString";
081: private final static String APPEND_MN = "append";
082: private final static String CTOR_MN = "<init>";
083:
084: // Field Names
085: private final static String INVOCATION_HANDLER_FN = "invocationHandler";
086:
087: /** The proxy class type (assigned in the ctor) */
088: private static Type PROXY_CLASS_T;
089:
090: private InstructionList il = new InstructionList();
091: private String proxyClassName;
092: private String super ClassName;
093: private ConstantPoolGen constPool;
094: private InstructionFactory iFactory;
095:
096: /**
097: * Creates a new <code>ProxyImplementationFactory</code> instance.
098: *
099: * @param superClassName a <code>String</code> value
100: * @param proxyClassName a <code>String</code> value
101: * @param cg a <code>ClassGen</code> value
102: */
103: public ProxyImplementationFactory(final String super ClassName,
104: final String proxyClassName, final ClassGen cg) {
105: this .super ClassName = super ClassName;
106: this .proxyClassName = proxyClassName;
107:
108: PROXY_CLASS_T = new ObjectType(proxyClassName);
109: constPool = cg.getConstantPool();
110: iFactory = new InstructionFactory(cg, constPool);
111: }
112:
113: /**
114: * generate an implementation of
115: * <pre>
116: *
117: * <code>
118: * public InvocationHandler getInvocationHandler() {
119: * return this.invocationHandler;
120: * }
121: * </code>
122: *
123: * </pre>
124: */
125: public Method createGetInvocationHandler() {
126: MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
127: INVOCATION_HANDLER_T, Type.NO_ARGS, null,
128: GET_INVOCATION_HANDLER_MN, proxyClassName, il,
129: constPool);
130:
131: il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
132: il.append(iFactory.createGetField(proxyClassName,
133: INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
134: il.append(iFactory.createReturn(INVOCATION_HANDLER_T));
135:
136: mg.stripAttributes(true);
137: mg.setMaxStack();
138: mg.setMaxLocals();
139:
140: return getMethodAndTidyup(mg);
141: }
142:
143: /**
144: * generate an implementation of
145: * <pre>
146: *
147: * <code>
148: * public Class[] getTargetTypes {
149: * return this.invocationHandler.copyTargetTypes();
150: * }
151: * </code>
152: *
153: * </pre>
154: *
155: * @return the method
156: *
157: */
158: public Method createGetTargetTypes() {
159: MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
160: ARRAY_OF_CLASS_T, Type.NO_ARGS, null,
161: GET_TARGET_TYPES_MN, proxyClassName, il, constPool);
162:
163: il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
164: il.append(iFactory.createGetField(proxyClassName,
165: Runtime.RUNTIME_FN, RUNTIME_T));
166: il.append(iFactory
167: .createInvoke(RUNTIME_CN, "copyTargetTypes",
168: ARRAY_OF_CLASS_T, Type.NO_ARGS,
169: Constants.INVOKEVIRTUAL));
170:
171: il.append(iFactory.createReturn(ARRAY_OF_CLASS_T));
172:
173: mg.stripAttributes(true);
174: mg.setMaxStack(1);
175: mg.setMaxLocals();
176:
177: return getMethodAndTidyup(mg);
178: }
179:
180: /**
181: * generate an implementation of
182: * <pre>
183: *
184: * <code>
185: * public String toString() {
186: * return "ProxyTarget[" + invocationHandler + "]";
187: * }
188: * </code>
189: *
190: * </pre>
191: *
192: * @return the method
193: *
194: */
195: public Method createToString() {
196: MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, STRING_T,
197: Type.NO_ARGS, null, TO_STRING_MN, proxyClassName, il,
198: constPool);
199:
200: il.append(iFactory.createNew(STRING_BUFFER_T));
201: il.append(iFactory.createDup(1));
202: il.append(iFactory.createInvoke(STRING_BUFFER_CN, CTOR_MN,
203: Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
204: il.append(new PUSH(constPool, "ProxyTarget["));
205: il.append(iFactory.createInvoke(STRING_BUFFER_CN, APPEND_MN,
206: STRING_BUFFER_T, new Type[] { STRING_T },
207: Constants.INVOKEVIRTUAL));
208: il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
209: il.append(iFactory.createGetField(proxyClassName,
210: INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
211: il.append(iFactory.createInvoke(STRING_BUFFER_CN, APPEND_MN,
212: STRING_BUFFER_T, new Type[] { OBJECT_T },
213: Constants.INVOKEVIRTUAL));
214: il.append(new PUSH(constPool, "]"));
215: il.append(iFactory.createInvoke(STRING_BUFFER_CN, APPEND_MN,
216: STRING_BUFFER_T, new Type[] { STRING_T },
217: Constants.INVOKEVIRTUAL));
218: il.append(iFactory.createInvoke(STRING_BUFFER_CN, TO_STRING_MN,
219: STRING_T, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
220: il.append(iFactory.createReturn(STRING_T));
221:
222: mg.stripAttributes(true);
223: mg.setMaxStack();
224: mg.setMaxLocals();
225:
226: return getMethodAndTidyup(mg);
227: }
228:
229: /**
230: * generate an implementation of
231: * <pre>
232: *
233: * <xmp>
234: * public <proxyClassName> (InvocationHandler h) {
235: * this.invocationHandler = h;
236: * }
237: * </xmp>
238: *
239: * </pre>
240: *
241: * @return the method
242: *
243: */
244: public Method createConstructor() {
245: MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
246: new Type[] { INVOCATION_HANDLER_T }, null, CTOR_MN,
247: proxyClassName, il, constPool);
248:
249: il.append(iFactory.createLoad(INVOCATION_HANDLER_T, 0));
250: il.append(iFactory.createInvoke(super ClassName, CTOR_MN,
251: Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
252: il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
253: il.append(iFactory.createLoad(INVOCATION_HANDLER_T, 1));
254: il.append(iFactory.createPutField(proxyClassName,
255: INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
256: il.append(iFactory.createReturn(Type.VOID));
257:
258: mg.stripAttributes(true);
259: mg.setMaxStack();
260: mg.setMaxLocals();
261:
262: return getMethodAndTidyup(mg);
263: }
264:
265: /**
266: * generate an implementation of...
267: * <pre>
268: *
269: * <xmp>
270: * public <return type> <method name>(<p0 type> p0, <p1 type> p1, ...)
271: * throws e0, e1 ...
272: * {
273: * return runtme.invoke(invocatioHandler, <method index>,
274: * new Object[]{boxed p0, boxed p1, ...)};
275: * }
276: * </xmp>
277: *
278: * </pre>
279: *
280: * @return the method
281: */
282: public Method createProxyMethod(String name, int methodNum,
283: Type rType, Type[] pTypes, String[] exceptionNames) {
284: MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, rType,
285: pTypes, null, // argNames
286: name, proxyClassName, il, constPool);
287:
288: for (int j = 0; j < exceptionNames.length; j++) {
289: mg.addException(exceptionNames[j]);
290: }
291:
292: // implementation of this.invocationHandler.invoke<Type>(InvocationHandler, i, new Object[]{ ... })
293: il.append(iFactory.createGetStatic(proxyClassName,
294: Runtime.RUNTIME_FN, RUNTIME_T));
295: il.append(iFactory.createLoad(RUNTIME_T, 0));
296:
297: // load the first method param (the ih)
298: il.append(iFactory.createGetField(proxyClassName,
299: INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
300:
301: // load the second method param (the method id)
302: il.append(new PUSH(constPool, methodNum));
303:
304: // create a new array to hold param values
305: il.append(new PUSH(constPool, pTypes.length));
306: il.append((Instruction) iFactory.createNewArray(OBJECT_T,
307: (short) 1));
308:
309: if (pTypes.length > 0) {
310: // the register index
311: int i = 1; // register 0 loaded with runtime ?
312:
313: for (int j = 0; j < pTypes.length; j++) {
314: Type t = pTypes[j];
315:
316: // not sure what this does
317: il.append(iFactory.createDup(1));
318:
319: // load the index of the array element
320: il.append(new PUSH(constPool, j));
321:
322: // box basic types into wrapped versions
323: if (t instanceof BasicType) {
324: // do a e.g new Boolean(b)
325: String wrappedClassName = Utility
326: .getObjectEquivalentClassName((BasicType) t);
327: ObjectType wrappedType = new ObjectType(
328: wrappedClassName);
329: il.append(iFactory.createNew(wrappedType));
330:
331: // again, what does this do?
332: il.append(iFactory.createDup(1));
333:
334: // load the parameter value from the register index
335: il.append(iFactory.createLoad(t, i));
336: il.append(iFactory.createInvoke(wrappedClassName,
337: CTOR_MN, Type.VOID, new Type[] { t },
338: Constants.INVOKESPECIAL));
339:
340: // increment register index for long & double
341: switch (t.getType()) {
342: case Constants.T_DOUBLE: // 7
343: case Constants.T_LONG: // 11
344: i++;
345: }
346:
347: // type is now wrapped type
348: t = wrappedType;
349: } else {
350: // just load the value in to the register slot
351: il.append(iFactory.createLoad(t, i));
352: }
353:
354: // increment register index for everything
355: // (makes += 2 for long & double) with above ++
356: i++;
357:
358: // store the value into the array
359: il.append(iFactory.createArrayStore(t));
360: }
361: }
362:
363: il.append(iFactory.createInvoke(RUNTIME_CN, "invoke",
364: Type.OBJECT, INVOKE_ARGS, Constants.INVOKEVIRTUAL));
365:
366: // handle the return value
367: if (rType instanceof ReferenceType) {
368: il.append(iFactory.createCheckCast((ReferenceType) rType));
369: } else if (rType instanceof BasicType) {
370: if (rType == Type.VOID) {
371: // Chuck away returned value if it's void
372: il.append(iFactory.createPop(1));
373: } else {
374: // unbox the return value of a primitive wrapper...
375: // we've got an Object and need the equivalent primitive
376: // do a e.g. (Boolean)obj.booleanValue();
377: String wrappedClassName = Utility
378: .getObjectEquivalentClassName((BasicType) rType);
379: ObjectType wrappedType = new ObjectType(
380: wrappedClassName);
381: il.append(iFactory
382: .createCheckCast((ReferenceType) wrappedType));
383:
384: String methodName = Utility.signatureToString(rType
385: .getSignature())
386: + "Value";
387:
388: il.append(iFactory.createInvoke(wrappedClassName,
389: methodName, rType, Type.NO_ARGS,
390: Constants.INVOKEVIRTUAL));
391: }
392: }
393:
394: il.append(iFactory.createReturn(rType));
395:
396: mg.stripAttributes(true);
397: mg.setMaxStack();
398: mg.setMaxLocals();
399:
400: return getMethodAndTidyup(mg);
401: }
402:
403: /**
404: * generate a field declaration of the form...
405: * <pre>
406: *
407: * <code>
408: * private InvocationHandler invocationHandler;
409: * </code>
410: *
411: * </pre>
412: *
413: * @return the method
414: *
415: */
416: public Field createInvocationHandlerField() {
417: FieldGen fg = new FieldGen(Constants.ACC_PRIVATE,
418: INVOCATION_HANDLER_T, INVOCATION_HANDLER_FN, constPool);
419: return fg.getField();
420: }
421:
422: /**
423: * generate a field declaration of the form...
424: * <pre>
425: *
426: * <code>
427: * public static Runtime runtime;
428: * </code>
429: *
430: * </pre>
431: *
432: * @return the method
433: *
434: */
435: public Field createRuntimeField() {
436: FieldGen fg = new FieldGen(Constants.ACC_PUBLIC
437: | Constants.ACC_STATIC, RUNTIME_T, Runtime.RUNTIME_FN,
438: constPool);
439: return fg.getField();
440: }
441:
442: /**
443: * A helper to return the method from MethodGen and clean up the
444: * instruction list.
445: */
446: private Method getMethodAndTidyup(final MethodGen mg) {
447: Method m = mg.getMethod();
448: il.dispose();
449:
450: return m;
451: }
452: }
|