KickJava   Java API By Example, From Geeks To Geeks.

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


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;
23
24 import org.apache.bcel.Constants;
25 import org.apache.bcel.classfile.Field;
26 import org.apache.bcel.classfile.Method;
27
28 import org.apache.bcel.generic.ArrayType;
29 import org.apache.bcel.generic.BasicType;
30 import org.apache.bcel.generic.ConstantPoolGen;
31 import org.apache.bcel.generic.ClassGen;
32 import org.apache.bcel.generic.FieldGen;
33 import org.apache.bcel.generic.Instruction;
34 import org.apache.bcel.generic.InstructionFactory;
35 import org.apache.bcel.generic.InstructionList;
36 import org.apache.bcel.generic.MethodGen;
37 import org.apache.bcel.generic.ObjectType;
38 import org.apache.bcel.generic.PUSH;
39 import org.apache.bcel.generic.ReferenceType;
40 import org.apache.bcel.generic.Type;
41
42 /**
43  * Factory to create the bytecode implementation of various methods
44  * required by the ProxyCompiler.
45  *
46  * @version <tt>$Revision: 37459 $</tt>
47  * @author <a HREF="mailto:neale@isismanor.co.uk">Neale Swinnerton</a>
48  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
49  */

50 public class ProxyImplementationFactory
51 {
52    // Class Names
53
private final static String JavaDoc RUNTIME_CN = Runtime JavaDoc.class.getName();
54    private final static String JavaDoc INVOCATION_HANDLER_CN = InvocationHandler.class.getName();
55    private final static String JavaDoc STRING_BUFFER_CN = StringBuffer JavaDoc.class.getName();
56
57    // Types
58
private final static ObjectType RUNTIME_T = (ObjectType)Utility.getType(Runtime JavaDoc.class);
59    private final static ObjectType INVOCATION_HANDLER_T = (ObjectType)Utility.getType(InvocationHandler.class);
60    private final static ArrayType ARRAY_OF_CLASS_T = new ArrayType("java.lang.Class", 1);
61    private final static ObjectType OBJECT_T = new ObjectType("java.lang.Object");
62    private final static ArrayType ARRAY_OF_OBJECT_T = new ArrayType("java.lang.Object", 1);
63    private final static ObjectType STRING_T = new ObjectType("java.lang.String");
64    private final static ObjectType STRING_BUFFER_T = new ObjectType("java.lang.StringBuffer");
65    private final static ObjectType PROXY_TARGET_T = new ObjectType(Proxies.ProxyTarget.class.getName());
66    private final static Type[] INVOKE_ARGS = { INVOCATION_HANDLER_T,
67                                                              Type.INT,
68                                                              ARRAY_OF_OBJECT_T };
69    // Method Names
70
private final static String JavaDoc GET_INVOCATION_HANDLER_MN = "getInvocationHandler";
71    private final static String JavaDoc GET_TARGET_TYPES_MN = "getTargetTypes";
72    private final static String JavaDoc TO_STRING_MN = "toString";
73    private final static String JavaDoc APPEND_MN = "append";
74    private final static String JavaDoc CTOR_MN = "<init>";
75
76    // Field Names
77
private final static String JavaDoc INVOCATION_HANDLER_FN = "invocationHandler";
78
79    /** The proxy class type (assigned in the ctor) */
80    private static Type PROXY_CLASS_T;
81    
82    private InstructionList il = new InstructionList();
83    private String JavaDoc proxyClassName;
84    private String JavaDoc superClassName;
85    private ConstantPoolGen constPool;
86    private InstructionFactory iFactory;
87
88    /**
89     * Creates a new <code>ProxyImplementationFactory</code> instance.
90     *
91     * @param superClassName a <code>String</code> value
92     * @param proxyClassName a <code>String</code> value
93     * @param cg a <code>ClassGen</code> value
94     */

95    public ProxyImplementationFactory(final String JavaDoc superClassName,
96                                      final String JavaDoc proxyClassName,
97                                      final ClassGen cg)
98    {
99       this.superClassName = superClassName;
100       this.proxyClassName = proxyClassName;
101
102       PROXY_CLASS_T = new ObjectType(proxyClassName);
103       constPool = cg.getConstantPool();
104       iFactory = new InstructionFactory(cg, constPool);
105    }
106    
107    /**
108     * generate an implementation of
109     * <pre>
110     *
111     * <code>
112     * public InvocationHandler getInvocationHandler() {
113     * return this.invocationHandler;
114     * }
115     * </code>
116     *
117     * </pre>
118     */

119    public Method createGetInvocationHandler()
120    {
121       MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
122                                    INVOCATION_HANDLER_T,
123                                    Type.NO_ARGS,
124                                    null, GET_INVOCATION_HANDLER_MN, proxyClassName, il, constPool);
125       
126       il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
127       il.append(iFactory.createGetField(proxyClassName, INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
128       il.append(iFactory.createReturn(INVOCATION_HANDLER_T));
129
130       mg.stripAttributes(true);
131       mg.setMaxStack();
132       mg.setMaxLocals();
133       
134       return getMethodAndTidyup(mg);
135    }
136
137    /**
138     * generate an implementation of
139     * <pre>
140     *
141     * <code>
142     * public Class[] getTargetTypes {
143     * return this.invocationHandler.copyTargetTypes();
144     * }
145     * </code>
146     *
147     * </pre>
148     *
149     * @return the method
150     *
151     */

152    public Method createGetTargetTypes()
153    {
154       MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
155                                    ARRAY_OF_CLASS_T,
156                                    Type.NO_ARGS,
157                                    null,
158                                    GET_TARGET_TYPES_MN,
159                                    proxyClassName,
160                                    il,
161                                    constPool);
162       
163       il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
164       il.append(iFactory.createGetField(proxyClassName, Runtime.RUNTIME_FN, RUNTIME_T));
165       il.append(iFactory.createInvoke(RUNTIME_CN,
166                                       "copyTargetTypes",
167                                       ARRAY_OF_CLASS_T,
168                                       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    {
197       MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, STRING_T,
198                                    Type.NO_ARGS,
199                                    null, TO_STRING_MN, proxyClassName, il, constPool);
200
201       il.append(iFactory.createNew(STRING_BUFFER_T));
202       il.append(iFactory.createDup(1));
203       il.append(iFactory.createInvoke(STRING_BUFFER_CN,
204                                       CTOR_MN,
205                                       Type.VOID,
206                                       Type.NO_ARGS,
207                                       Constants.INVOKESPECIAL));
208       il.append(new PUSH(constPool, "ProxyTarget["));
209       il.append(iFactory.createInvoke(STRING_BUFFER_CN,
210                                       APPEND_MN,
211                                       STRING_BUFFER_T,
212                                       new Type[]{STRING_T},
213                                       Constants.INVOKEVIRTUAL));
214       il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
215       il.append(iFactory.createGetField(proxyClassName, INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
216       il.append(iFactory.createInvoke(STRING_BUFFER_CN,
217                                       APPEND_MN,
218                                       STRING_BUFFER_T,
219                                       new Type[]{OBJECT_T},
220                                       Constants.INVOKEVIRTUAL));
221       il.append(new PUSH(constPool, "]"));
222       il.append(iFactory.createInvoke(STRING_BUFFER_CN,
223                                       APPEND_MN,
224                                       STRING_BUFFER_T,
225                                       new Type[]{STRING_T},
226                                       Constants.INVOKEVIRTUAL));
227       il.append(iFactory.createInvoke(STRING_BUFFER_CN,
228                                       TO_STRING_MN,
229                                       STRING_T,
230                                       Type.NO_ARGS,
231                                       Constants.INVOKEVIRTUAL));
232       il.append(iFactory.createReturn(STRING_T));
233
234       mg.stripAttributes(true);
235       mg.setMaxStack();
236       mg.setMaxLocals();
237
238       return getMethodAndTidyup(mg);
239    }
240    
241    /**
242     * generate an implementation of
243     * <pre>
244     *
245     * <xmp>
246     * public <proxyClassName> (InvocationHandler h) {
247     * this.invocationHandler = h;
248     * }
249     * </xmp>
250     *
251     * </pre>
252     *
253     * @return the method
254     *
255     */

256    public Method createConstructor()
257    {
258       MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
259                                    Type.VOID,
260                                    new Type[]{INVOCATION_HANDLER_T},
261                                    null,
262                                    CTOR_MN,
263                                    proxyClassName,
264                                    il,
265                                    constPool);
266
267       il.append(iFactory.createLoad(INVOCATION_HANDLER_T, 0));
268       il.append(iFactory.createInvoke(superClassName,
269                                       CTOR_MN,
270                                       Type.VOID,
271                                       Type.NO_ARGS,
272                                       Constants.INVOKESPECIAL));
273       il.append(iFactory.createLoad(PROXY_CLASS_T, 0));
274       il.append(iFactory.createLoad(INVOCATION_HANDLER_T, 1));
275       il.append(iFactory.createPutField(proxyClassName, INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
276       il.append(iFactory.createReturn(Type.VOID));
277       
278       mg.stripAttributes(true);
279       mg.setMaxStack();
280       mg.setMaxLocals();
281
282       return getMethodAndTidyup(mg);
283    }
284
285    /**
286     * generate an implementation of...
287     * <pre>
288     *
289     * <xmp>
290     * public <return type> <method name>(<p0 type> p0, <p1 type> p1, ...)
291     * throws e0, e1 ...
292     * {
293     * return runtme.invoke(invocatioHandler, <method index>,
294     * new Object[]{boxed p0, boxed p1, ...)};
295     * }
296     * </xmp>
297     *
298     * </pre>
299     *
300     * @return the method
301     */

302    public Method createProxyMethod(String JavaDoc name,
303                                    int methodNum,
304                                    Type rType,
305                                    Type[] pTypes,
306                                    String JavaDoc[] exceptionNames)
307    {
308       MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
309                                    rType,
310                                    pTypes,
311                                    null, // argNames
312
name,
313                                    proxyClassName,
314                                    il,
315                                    constPool);
316       
317       for (int j = 0; j < exceptionNames.length; j++) {
318          mg.addException(exceptionNames[j]);
319       }
320
321       // implementation of this.invocationHandler.invoke<Type>(InvocationHandler, i, new Object[]{ ... })
322
il.append(iFactory.createGetStatic(proxyClassName, Runtime.RUNTIME_FN, RUNTIME_T));
323       il.append(iFactory.createLoad(RUNTIME_T, 0));
324
325       // load the first method param (the ih)
326
il.append(iFactory.createGetField(proxyClassName, INVOCATION_HANDLER_FN, INVOCATION_HANDLER_T));
327          
328       // load the second method param (the method id)
329
il.append(new PUSH(constPool, methodNum));
330
331       // create a new array to hold param values
332
il.append(new PUSH(constPool, pTypes.length));
333       il.append((Instruction)iFactory.createNewArray(OBJECT_T, (short)1));
334       
335       if (pTypes.length > 0) {
336          // the register index
337
int i = 1; // register 0 loaded with runtime ?
338

339          for (int j = 0; j < pTypes.length; j++) {
340             Type t = pTypes[j];
341             
342             // not sure what this does
343
il.append(iFactory.createDup(1));
344
345             // load the index of the array element
346
il.append(new PUSH(constPool, j));
347
348             // box basic types into wrapped versions
349
if (t instanceof BasicType) {
350                // do a e.g new Boolean(b)
351
String JavaDoc wrappedClassName = Utility.getObjectEquivalentClassName((BasicType)t);
352                ObjectType wrappedType = new ObjectType(wrappedClassName);
353                il.append(iFactory.createNew(wrappedType));
354
355                // again, what does this do?
356
il.append(iFactory.createDup(1));
357
358                // load the parameter value from the register index
359
il.append(iFactory.createLoad(t, i));
360                il.append(iFactory.createInvoke(wrappedClassName,
361                                                CTOR_MN,
362                                                Type.VOID,
363                                                new Type[] { t },
364                                                Constants.INVOKESPECIAL));
365
366                // increment register index for long & double
367
switch (t.getType()) {
368                case Constants.T_DOUBLE: // 7
369
case Constants.T_LONG: // 11
370
i++;
371                }
372
373                // type is now wrapped type
374
t = wrappedType;
375             }
376             else {
377                // just load the value in to the register slot
378
il.append(iFactory.createLoad(t, i));
379             }
380                
381             // increment register index for everything
382
// (makes += 2 for long & double) with above ++
383
i++;
384
385             // store the value into the array
386
il.append(iFactory.createArrayStore(t));
387          }
388       }
389             
390       il.append(iFactory.createInvoke(RUNTIME_CN,
391                                       "invoke",
392                                       Type.OBJECT,
393                                       INVOKE_ARGS,
394                                       Constants.INVOKEVIRTUAL));
395       
396       // handle the return value
397
if (rType instanceof ReferenceType) {
398          il.append(iFactory.createCheckCast((ReferenceType)rType));
399       }
400       else if (rType instanceof BasicType) {
401          if (rType == Type.VOID) {
402             // Chuck away returned value if it's void
403
il.append(iFactory.createPop(1));
404          }
405          else {
406             // unbox the return value of a primitive wrapper...
407
// we've got an Object and need the equivalent primitive
408
// do a e.g. (Boolean)obj.booleanValue();
409
String JavaDoc wrappedClassName = Utility.getObjectEquivalentClassName((BasicType)rType);
410             ObjectType wrappedType = new ObjectType(wrappedClassName);
411             il.append(iFactory.createCheckCast((ReferenceType)wrappedType));
412             
413             String JavaDoc methodName = Utility.signatureToString(rType.getSignature()) + "Value";
414             
415             il.append(iFactory.createInvoke(wrappedClassName,
416                                             methodName,
417                                             rType,
418                                             Type.NO_ARGS,
419                                             Constants.INVOKEVIRTUAL));
420          }
421       }
422       
423       il.append(iFactory.createReturn(rType));
424       
425       mg.stripAttributes(true);
426       mg.setMaxStack();
427       mg.setMaxLocals();
428       
429       return getMethodAndTidyup(mg);
430    }
431
432    /**
433     * generate a field declaration of the form...
434     * <pre>
435     *
436     * <code>
437     * private InvocationHandler invocationHandler;
438     * </code>
439     *
440     * </pre>
441     *
442     * @return the method
443     *
444     */

445    public Field createInvocationHandlerField()
446    {
447       FieldGen fg = new FieldGen(Constants.ACC_PRIVATE,
448                                  INVOCATION_HANDLER_T,
449                                  INVOCATION_HANDLER_FN,
450                                  constPool);
451       return fg.getField();
452    }
453    
454    /**
455     * generate a field declaration of the form...
456     * <pre>
457     *
458     * <code>
459     * public static Runtime runtime;
460     * </code>
461     *
462     * </pre>
463     *
464     * @return the method
465     *
466     */

467    public Field createRuntimeField()
468    {
469       FieldGen fg = new FieldGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
470                                  RUNTIME_T,
471                                  Runtime.RUNTIME_FN,
472                                  constPool);
473       return fg.getField();
474    }
475
476    /**
477     * A helper to return the method from MethodGen and clean up the
478     * instruction list.
479     */

480    private Method getMethodAndTidyup(final MethodGen mg)
481    {
482       Method m = mg.getMethod();
483       il.dispose();
484
485       return m;
486    }
487 }
488
Popular Tags