KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > proactive > core > mop > BytecodeStubBuilder


1 /*
2 * ################################################################
3 *
4 * ProActive: The Java(TM) library for Parallel, Distributed,
5 * Concurrent computing with Security and Mobility
6 *
7 * Copyright (C) 1997-2002 INRIA/University of Nice-Sophia Antipolis
8 * Contact: proactive-support@inria.fr
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
25 * Initial developer(s): The ProActive Team
26 * http://www.inria.fr/oasis/ProActive/contacts.html
27 * Contributor(s):
28 *
29 * ################################################################
30 */

31 package org.objectweb.proactive.core.mop;
32
33 import java.lang.reflect.Method JavaDoc;
34 import java.lang.reflect.Modifier JavaDoc;
35 import java.util.Vector JavaDoc;
36
37 import org.apache.bcel.Constants;
38 import org.apache.bcel.classfile.JavaClass;
39 import org.apache.bcel.generic.ArrayType;
40 import org.apache.bcel.generic.ClassGen;
41 import org.apache.bcel.generic.ConstantPoolGen;
42 import org.apache.bcel.generic.FieldGen;
43 import org.apache.bcel.generic.GOTO;
44 import org.apache.bcel.generic.ICONST;
45 import org.apache.bcel.generic.Instruction;
46 import org.apache.bcel.generic.InstructionConstants;
47 import org.apache.bcel.generic.InstructionFactory;
48 import org.apache.bcel.generic.InstructionHandle;
49 import org.apache.bcel.generic.InstructionList;
50 import org.apache.bcel.generic.LocalVariableInstruction;
51 import org.apache.bcel.generic.MethodGen;
52 import org.apache.bcel.generic.ObjectType;
53 import org.apache.bcel.generic.PUSH;
54 import org.apache.bcel.generic.ReferenceType;
55 import org.apache.bcel.generic.Type;
56
57 public class BytecodeStubBuilder {
58   // Those fields contain information about the class
59
// for which we are building a wrapper
60
protected Class JavaDoc cl;
61   protected String JavaDoc className;
62   protected String JavaDoc packageName;
63   protected Method JavaDoc[] methods;
64
65   // The following fields have to do with
66
// the actual genration of the stub
67
protected String JavaDoc stubClassSimpleName;
68   protected String JavaDoc stubClassFullName;
69   protected ClassGen classGenerator;
70
71   // We only instanciate the following InstructionList objet once and then
72
// clean it and reuse it for each new method that we want to build
73
protected InstructionList instructionList = new InstructionList();
74
75   // A few constants that come in handy when using BCEL in our case
76
protected static final Type CLASS_TYPE = convertClassNameToType("java.lang.Class");
77   protected static final Type CLASS_ARRAY_TYPE = new ArrayType(CLASS_TYPE, 1);
78   protected static final Type OBJECT_TYPE = convertClassNameToType("java.lang.Object");
79   protected static final Type OBJECT_ARRAY_TYPE = new ArrayType(OBJECT_TYPE, 1);
80   protected static final Type METHOD_TYPE = convertClassNameToType("java.lang.reflect.Method");
81   protected static final Type METHOD_ARRAY_TYPE = new ArrayType(METHOD_TYPE, 1);
82   protected static final Type PROXY_TYPE = convertClassNameToType("org.objectweb.proactive.core.mop.Proxy");
83   protected static final Type METHODCALL_TYPE = convertClassNameToType("org.objectweb.proactive.core.mop.MethodCall");
84   protected static final String JavaDoc STUB_INTERFACE_NAME = "org.objectweb.proactive.core.mop.StubObject";
85   protected static final String JavaDoc PROXY_FIELD_NAME = "myProxy";
86
87   public BytecodeStubBuilder(String JavaDoc classname) throws ClassNotFoundException JavaDoc {
88     // Obtains the object that represents the type we want to create
89
// a wrapper class for. This call may fail with a ClassNotFoundException
90
// if the class corresponding to this type cannot be found.
91
this.cl = Class.forName(classname);
92
93     // Keep this info at hand for performance purpose
94
this.className = classname;
95
96     // Fills in all the infos about this class
97
this.setInfos();
98   }
99
100   protected ClassGen createClassGenerator() {
101     String JavaDoc superclassName;
102     String JavaDoc[] interfaces;
103
104     // If we generate a stub for an interface type, we have to explicitely declare
105
// that we implement the interface. Also, the name of the superclass is not the reified
106
// type, but java.lang.Object
107
if (this.cl.isInterface()) {
108       superclassName = "java.lang.Object";
109       interfaces = new String JavaDoc[3];
110       interfaces[0] = "java.io.Serializable";
111       interfaces[1] = STUB_INTERFACE_NAME;
112       interfaces[2] = this.cl.getName();
113     } else {
114       superclassName = this.className;
115       interfaces = new String JavaDoc[2];
116       interfaces[0] = "java.io.Serializable";
117       interfaces[1] = STUB_INTERFACE_NAME;
118     }
119
120     return new ClassGen(this.stubClassFullName, // Fully-qualified class name
121
superclassName, // Superclass
122
"<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, // Same access modifiers as superclass or public ???
123
interfaces); // declared interfaces
124
}
125
126   public byte[] create() {
127     // Creates the class generator
128
this.classGenerator = this.createClassGenerator();
129
130     // Add a public no-arg constructor
131
this.createConstructor();
132
133     // Creates all the methods in the class
134
for (int i = 0; i < this.methods.length; i++) {
135       MethodGen mg = this.createMethod(i, this.methods[i]);
136       this.classGenerator.addMethod(mg.getMethod());
137       instructionList.dispose();
138     }
139
140     // Creates the two methods getProxy and setProxy
141
// declared in interface StubObject
142
this.createGetAndSetProxyMethods();
143
144     // Creates the fields of the class
145
this.createFields();
146
147     // Create the static fields
148
this.createStaticVariables();
149
150     // Creates the static initializer
151
this.createStaticInitializer();
152
153     // Actually creates the class and returns the result
154
JavaClass theClass = this.classGenerator.getJavaClass();
155
156     // Next few lines for debugging only
157
/*
158     try {
159       theClass.dump (theClass.getClassName()+".class");
160     } catch (java.io.IOException e) {
161       e.printStackTrace();
162     }*/

163     return theClass.getBytes();
164   }
165
166   protected MethodGen createMethodGenerator(Method JavaDoc m) {
167     // Extracts modifiers
168
int flags = convertJavaModifierToBCEL(m.getModifiers());
169
170     // Modifies the modifiers in order to remove 'native' and 'abstract'
171
flags = removeNativeAndAbstractModifiers(flags);
172
173     // Extracts return and arguments types
174
Type returnType = convertClassToType(m.getReturnType());
175     Class JavaDoc[] methodParams = m.getParameterTypes();
176     Type[] argumentTypes = new Type[methodParams.length];
177     for (int i = 0; i < argumentTypes.length; i++) {
178       argumentTypes[i] = convertClassToType(methodParams[i]);
179     }
180
181     // Creates argument names
182
String JavaDoc[] argumentNames = new String JavaDoc[argumentTypes.length];
183     for (int i = 0; i < argumentNames.length; i++) {
184       argumentNames[i] = new String JavaDoc("arg" + i);
185     }
186
187     // Actually creates the method generator
188
MethodGen mg = new MethodGen(flags, // access flags
189
returnType, // return type
190
argumentTypes, argumentNames, // arg names
191
m.getName(), // Method name
192
this.stubClassFullName, // Class name
193
instructionList, // Instructions list
194
this.classGenerator.getConstantPool());
195     return mg;
196   }
197
198   protected static int removeNativeAndAbstractModifiers(int modifiers) {
199     // In order to set to 0 the bit that represents 'native', we first
200
// compute the mask that contains 1s everywhere and a 0 where the bit
201
// is, and then apply this mask with an 'and', bitwise.
202
int result = modifiers & (~java.lang.reflect.Modifier.NATIVE);
203     result = result & (~java.lang.reflect.Modifier.ABSTRACT);
204     return result;
205   }
206
207   protected static int convertJavaModifierToBCEL(int javaModifier) {
208     int result = 0;
209
210     if (Modifier.isAbstract(javaModifier)) {
211       result = result | Constants.ACC_ABSTRACT;
212     }
213     if (Modifier.isFinal(javaModifier)) {
214       result = result | Constants.ACC_FINAL;
215     }
216     if (Modifier.isInterface(javaModifier)) {
217       result = result | Constants.ACC_INTERFACE;
218     }
219     if (Modifier.isNative(javaModifier)) {
220       result = result | Constants.ACC_NATIVE;
221     }
222     if (Modifier.isPrivate(javaModifier)) {
223       result = result | Constants.ACC_PRIVATE;
224     }
225     if (Modifier.isProtected(javaModifier)) {
226       result = result | Constants.ACC_PROTECTED;
227     }
228     if (Modifier.isPublic(javaModifier)) {
229       result = result | Constants.ACC_PUBLIC;
230     }
231     if (Modifier.isStatic(javaModifier)) {
232       result = result | Constants.ACC_STATIC;
233     }
234     if (Modifier.isStrict(javaModifier)) {
235       result = result | Constants.ACC_STRICT;
236     }
237     if (Modifier.isSynchronized(javaModifier)) {
238       result = result | Constants.ACC_SYNCHRONIZED;
239     }
240     if (Modifier.isTransient(javaModifier)) {
241       result = result | Constants.ACC_TRANSIENT;
242     }
243     if (Modifier.isVolatile(javaModifier)) {
244       result = result | Constants.ACC_VOLATILE;
245     }
246
247     return result;
248   }
249
250   protected MethodGen createMethod(int methodIndex, Method JavaDoc m) {
251     MethodGen mg = createMethodGenerator(m);
252     InstructionFactory factory = new InstructionFactory(classGenerator);
253
254     if (this.cl.isInterface() == false) {
255       // First, check if the method is called from within the constructor
256
// Load 'this' onto the stack
257
instructionList.append(InstructionFactory.createThis());
258
259       // Gets the value of the field 'outsideConstructor'
260
instructionList.append(factory.createGetField(this.stubClassFullName, "outsideConstructor", Type.BOOLEAN));
261     }
262
263     // Now we create the code for the case where we are outside of
264
// the constructor, i.e. we want the call to be reified
265

266     // Pushes on the stack the reference to the proxy object
267
InstructionHandle outsideConstructorHandle = instructionList.append(InstructionFactory.createThis());
268     instructionList.append(factory.createGetField(this.stubClassFullName, PROXY_FIELD_NAME, PROXY_TYPE));
269
270     // Pushes on the stack the Method object that represents the current method
271
instructionList.append(factory.createGetStatic(this.stubClassFullName, "methods", METHOD_ARRAY_TYPE));
272     instructionList.append(new PUSH(this.classGenerator.getConstantPool(), methodIndex));
273     instructionList.append(InstructionFactory.createArrayLoad(METHOD_TYPE));
274
275     Class JavaDoc[] paramTypes = m.getParameterTypes();
276     // Create an array of type Object[] for holding all the parameters
277
// Push on the stack the size of the array
278
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), paramTypes.length));
279     // Creates an array of class objects of that size
280
instructionList.append((Instruction) factory.createNewArray(OBJECT_TYPE, (byte) 1));
281
282     // Fill in the array with the parameters
283
int indexInParameterArray = 1; // Necessary because sometimes we need to jump 2 slots ahead
284
for (int i = 0; i < paramTypes.length; i++) {
285       // First, duplicate the reference to the array of type Object[]
286
// That currently sits on top of the stack
287
instructionList.append(InstructionFactory.createDup(1));
288
289       // Load the array index for storing the result
290
PUSH push = new PUSH(this.classGenerator.getConstantPool(), i);
291       instructionList.append(push);
292
293       Type theType = convertClassToType(paramTypes[i]);
294
295       // If it is a primitive type, we need to create the wrapper here
296
if (paramTypes[i].isPrimitive()) {
297         // If we have a primitive type, we need to first create a wrapper objet
298
String JavaDoc nameOfWrapper = Utils.nameOfWrapper(paramTypes[i]);
299         instructionList.append(factory.createNew(nameOfWrapper));
300         instructionList.append(InstructionFactory.createDup(1));
301         // Load the primitive value on to the stack
302
instructionList.append(InstructionFactory.createLoad(theType, indexInParameterArray));
303         // Handles the fact that some primitive types need 2 slots
304
indexInParameterArray = indexInParameterArray + lengthOfType(paramTypes[i]);
305
306         // Now, we call the constructor of the wrapper
307
Type[] argtypes = new Type[] { convertClassToType(paramTypes[i])};
308         instructionList.append(factory.createInvoke(nameOfWrapper, "<init>", Type.VOID, argtypes, Constants.INVOKESPECIAL));
309       } else {
310         // Simply pushes the argument on to the stack
311
instructionList.append(InstructionFactory.createLoad(theType, indexInParameterArray));
312         indexInParameterArray++; // Non-primitive types only use one slot
313
}
314
315       // Stores the object in the array
316
instructionList.append(InstructionFactory.createArrayStore(OBJECT_TYPE));
317     }
318
319     // So now we have the Method object and the array of objects on the stack,
320
// Let's call the static method MethodCall.getMethodCall.
321
instructionList.append(
322       factory.createInvoke(
323         "org.objectweb.proactive.core.mop.MethodCall",
324         "getMethodCall",
325         METHODCALL_TYPE,
326         new Type[] { METHOD_TYPE, OBJECT_ARRAY_TYPE },
327         Constants.INVOKESTATIC));
328
329     // Now, call 'reify' on the proxy object
330
instructionList.append(
331       factory.createInvoke("org.objectweb.proactive.core.mop.Proxy", "reify", Type.OBJECT, new Type[] { METHODCALL_TYPE }, Constants.INVOKEINTERFACE));
332
333     // If the return type of the method is a primitive type,
334
// we want to unwrap it first
335
if (m.getReturnType().isPrimitive()) {
336       this.createUnwrappingCode(factory, m.getReturnType());
337     } else {
338       // If the return type is a reference type,
339
// we need to insert a type check
340
instructionList.append(factory.createCheckCast((ReferenceType) convertClassToType(m.getReturnType())));
341     }
342
343     // Writes the code for inside constructor
344
// What follows is a quick (but not dirty, simply non-optimized) fix to the problem
345
// of stubs built for interfaces, not classes. We simply do not perform the call
346
if (this.cl.isInterface() == false) {
347       // Now we need to perform the call to super.blablabla if need be
348
// Let's stack up the arguments
349
InstructionHandle inConstructorHandle = instructionList.append(InstructionFactory.createThis());
350
351       // The following line is for inserting the conditional branch instruction
352
// at the beginning of the method. If the condition is satisfied, the
353
// control flows move to the previous instruction
354
instructionList.insert(outsideConstructorHandle, InstructionFactory.createBranchInstruction(Constants.IFEQ, inConstructorHandle));
355
356       // This is for browsing the parameter array, not forgetting that some parameters
357
// require two slots (longs and doubles)
358
indexInParameterArray = 1;
359       for (int i = 0; i < paramTypes.length; i++) {
360         Type theType = convertClassToType(paramTypes[i]);
361         LocalVariableInstruction lvi = InstructionFactory.createLoad(theType, indexInParameterArray);
362         instructionList.append(lvi);
363         indexInParameterArray = indexInParameterArray + lengthOfType(paramTypes[i]);
364       }
365
366       // And perform the call
367
String JavaDoc declaringClassName = this.methods[methodIndex].getDeclaringClass().getName();
368       instructionList.append(
369         factory.createInvoke(
370           declaringClassName,
371           m.getName(),
372           convertClassToType(m.getReturnType()),
373           convertClassArrayToTypeArray(paramTypes),
374           Constants.INVOKESPECIAL));
375
376       // Returns the result to the caller
377
InstructionHandle returnHandle = instructionList.append(InstructionFactory.createReturn(convertClassToType(m.getReturnType())));
378
379       // insert a jump from the
380
instructionList.insert(inConstructorHandle, new GOTO(returnHandle));
381     } else {
382       // If we are an interface, we need to remove from the top of the stack
383
// the value of boolean field that tells whether we are inside a constructor
384
// or not
385
// instructionList.append(factory.createPop(1));
386
instructionList.append(InstructionFactory.createReturn(convertClassToType(m.getReturnType())));
387     }
388     mg.removeLocalVariables();
389     mg.setMaxStack(); // Needed stack size
390
mg.setMaxLocals(); // Needed stack size
391

392     return mg;
393   }
394
395   protected void createUnwrappingCode(InstructionFactory factory, Class JavaDoc c) {
396     // Depending on the type of the wrapper, the code differs
397
// The parameter 'c' represents the primitive type, not the type of the
398
// wrapper
399

400     if (c.equals(Void.TYPE)) {
401       // There is nothing to do, simply pop the object returned by reify
402
instructionList.append(InstructionFactory.createPop(1));
403     } else {
404       String JavaDoc nameOfPrimitiveType = c.getName();
405       String JavaDoc nameOfWrapperClass = Utils.nameOfWrapper(c);
406       // First, we should check that the object on top of
407
// the stack is of the correct type
408
instructionList.append(factory.createCheckCast((ReferenceType) convertClassNameToType(nameOfWrapperClass)));
409       // And then perform the call
410
instructionList.append(
411         factory.createInvoke(nameOfWrapperClass, nameOfPrimitiveType + "Value", convertClassToType(c), new Type[0], Constants.INVOKEVIRTUAL));
412     }
413
414     return;
415   }
416
417   protected void createFields() {
418     // Gets a reference to the constant pool
419
ConstantPoolGen cp = this.classGenerator.getConstantPool();
420
421     // Creates the boolean field that indicates whether or not
422
// we are currently inside the constructor of the stub
423
// This is only necessary if we are generating a stub for
424
// a type that is not an interface
425
if (!this.cl.isInterface()) {
426       int flags1 = Constants.ACC_PROTECTED;
427       Type type1 = Type.BOOLEAN;
428       String JavaDoc name1 = "outsideConstructor";
429       FieldGen f1 = new FieldGen(flags1, type1, name1, cp);
430
431       this.classGenerator.addField(f1.getField());
432     }
433     // Creates the field that points to the handler inside the MOP
434
int flags2 = Constants.ACC_PROTECTED;
435     Type type2 = PROXY_TYPE;
436     String JavaDoc name2 = PROXY_FIELD_NAME;
437     FieldGen f2 = new FieldGen(flags2, type2, name2, cp);
438     this.classGenerator.addField(f2.getField());
439   }
440
441   protected void createConstructor() {
442     // Actually creates the method generator
443
MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, // access flags
444
Type.VOID, // return type
445
new Type[0], new String JavaDoc[0], // arg names
446
"<init>", // Method name
447
this.stubClassFullName, // Class name
448
instructionList, // Instructions list
449
this.classGenerator.getConstantPool());
450
451     // Now, fills in the instruction list
452
InstructionFactory factory = new InstructionFactory(this.classGenerator);
453
454     if (!this.cl.isInterface()) {
455       // Calls the constructor of the super class
456
instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 0));
457       instructionList.append(factory.createInvoke(this.className, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
458
459       // Sets the value of 'outsideConstructor' to true
460
instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 0));
461       instructionList.append(new ICONST(1));
462       instructionList.append(factory.createPutField(this.stubClassFullName, "outsideConstructor", Type.BOOLEAN));
463     } else {
464       // Calls the constructor of the super class
465
instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 0));
466       instructionList.append(factory.createInvoke("java.lang.Object", "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
467     }
468
469     // And returns from the constructor
470
instructionList.append(InstructionConstants.RETURN);
471
472     mg.setMaxStack(); // Needed stack size
473
mg.setMaxLocals(); // Needed locals
474

475     // Add the method to the class
476
this.classGenerator.addMethod(mg.getMethod());
477
478     // Recycling the InstructionList object
479
this.instructionList.dispose();
480
481     return;
482   }
483
484   protected void createStaticVariables() {
485     // Gets a reference to the constant pool
486
ConstantPoolGen cp = this.classGenerator.getConstantPool();
487
488     // Creates fields that contains the array of Method objects
489
// that represent the reified methods of this class
490
int flags1 = Constants.ACC_PROTECTED | Constants.ACC_STATIC;
491     Type type1 = METHOD_ARRAY_TYPE;
492     String JavaDoc name1 = "methods";
493     FieldGen f1 = new FieldGen(flags1, type1, name1, cp);
494
495     this.classGenerator.addField(f1.getField());
496
497     return;
498   }
499
500   protected void createStaticInitializer() {
501     // Creates the class initializer method itself
502
MethodGen mg = new MethodGen(Constants.ACC_STATIC, // Static method
503
Type.VOID, // returns mothing
504
new Type[0], // No arguments
505
new String JavaDoc[0], Constants.STATIC_INITIALIZER_NAME, this.stubClassFullName, instructionList, this.classGenerator.getConstantPool());
506
507     // An instruction factory for helping us
508
InstructionFactory factory = new InstructionFactory(this.classGenerator);
509
510     // Creates an array of Method objects that we will store into the static
511
// variable 'methods' of type 'Method[]'
512
// Pushes the size of the array on to the stack
513
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), this.methods.length));
514     // Creates an array of Method objects of that size
515
instructionList.append((Instruction) factory.createNewArray(METHOD_TYPE, (byte) 1));
516
517     // Stores the reference to this newly-created array into the static variable 'methods'
518
instructionList.append(factory.createPutStatic(this.stubClassFullName, "methods", METHOD_ARRAY_TYPE));
519
520     // Creates an array of Class objects that represent all the superclasses of
521
// the stub class.
522
Vector JavaDoc vectorOfSuperClasses = new Vector JavaDoc();
523     Class JavaDoc currentClass = cl;
524     while (currentClass != null) {
525       vectorOfSuperClasses.addElement(currentClass);
526       currentClass = currentClass.getSuperclass();
527     }
528
529     // Pushes on the stack the size of the array
530
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), vectorOfSuperClasses.size()));
531     // Creates an array of class objects of that size
532
instructionList.append((Instruction) factory.createNewArray(CLASS_TYPE, (byte) 1));
533     // Stores the reference to this newly-created array as the local variable with index '1'
534
instructionList.append(InstructionFactory.createStore(Type.OBJECT, 1));
535
536     // Make as many calls to Class.forName as is needed to fill in the array
537
for (int i = 0; i < vectorOfSuperClasses.size(); i++) {
538       // Load onto the stack a pointer to the array
539
instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 1));
540       // Load the index in the array where we want to store the result
541
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), i));
542       // Loads the name of the class onto the stack
543
String JavaDoc s = ((Class JavaDoc) vectorOfSuperClasses.elementAt(i)).getName();
544       instructionList.append(new PUSH(this.classGenerator.getConstantPool(), s));
545       // Performs the call to Class.forName
546
Type[] argstypes = new Type[1];
547       argstypes[0] = Type.STRING;
548       instructionList.append(factory.createInvoke("java.lang.Class", "forName", CLASS_TYPE, argstypes, Constants.INVOKESTATIC));
549
550       // Stores the result of the invocation of forName into the array
551
// The index into which to store as well as the reference to the array
552
// are already on the stack
553
instructionList.append(InstructionFactory.createArrayStore(Type.OBJECT));
554     }
555
556     // Now, lookup each of the Method objects and store it into the 'method' array
557
for (int i = 0; i < this.methods.length; i++) {
558       // Stacks up the reference to the array of methods and the index in the array
559
instructionList.append(factory.createGetStatic(this.stubClassFullName, "methods", METHOD_ARRAY_TYPE));
560       instructionList.append(new PUSH(this.classGenerator.getConstantPool(), i));
561
562       // Now, we load onto the stack a pointer to the class that contains the method
563
int indexInClassArray = vectorOfSuperClasses.indexOf(this.methods[i].getDeclaringClass());
564       if (indexInClassArray == -1) {}
565       // Load a pointer to the Class array (local variable number 1)
566
instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 1));
567       // Access element number 'indexInClassArray'
568
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), indexInClassArray));
569       instructionList.append(InstructionFactory.createArrayLoad(CLASS_TYPE));
570       // Now, perform a call to 'getDeclaredMethod'
571
// First, stack up the simple name of the method to solve
572
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), this.methods[i].getName()));
573       // Now, we want to create an array of type Class[] for representing
574
// the parameters to this method. We choose to store this array into the
575
// slot number 2
576
// Pushes the size of the array
577
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), this.methods[i].getParameterTypes().length));
578       // Creates an array of class objects of that size
579
instructionList.append((Instruction) factory.createNewArray(CLASS_TYPE, (byte) 1));
580       // Stores the reference to this newly-created array as the local variable with index '2'
581
instructionList.append(InstructionFactory.createStore(Type.OBJECT, 2));
582
583       // Stack up the class objects that represent the types of all the arguments to this method
584
for (int j = 0; j < this.methods[i].getParameterTypes().length; j++) {
585         Class JavaDoc currentParameter = this.methods[i].getParameterTypes()[j];
586
587         // Load onto the stack a pointer to the array of Class objects (for parameters)
588
instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 2));
589         // Load the index in the array where we want to store the result
590
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), j));
591
592         // If the type of the parameter is a primitive one, we use the predefined
593
// constants (like java.lang.Integer.TYPE) instead of calling Class.forName
594
if (currentParameter.isPrimitive()) {
595           // Loads that static variable
596
instructionList.append(factory.createGetStatic(Utils.getWrapperClass(currentParameter).getName(), "TYPE", CLASS_TYPE));
597         } else {
598           // Load the name of the parameter class onto the stack
599
instructionList.append(new PUSH(this.classGenerator.getConstantPool(), currentParameter.getName()));
600           // Performs a call to Class.forName
601
Type[] argstypes = new Type[1];
602           argstypes[0] = Type.STRING;
603           instructionList.append(factory.createInvoke("java.lang.Class", "forName", CLASS_TYPE, argstypes, Constants.INVOKESTATIC));
604         }
605
606         // Stores the result in the array
607
instructionList.append(InstructionFactory.createArrayStore(Type.OBJECT));
608       }
609
610       // Loads the array
611
instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 2));
612
613       // Perform the actual call to 'getDeclaredMethod'
614
Type[] argstypes = new Type[2];
615       argstypes[0] = Type.STRING;
616       argstypes[1] = CLASS_ARRAY_TYPE;
617       instructionList.append(factory.createInvoke("java.lang.Class", "getDeclaredMethod", METHOD_TYPE, argstypes, Constants.INVOKEVIRTUAL));
618       // Now that we have the result, let's store it into the array
619
instructionList.append(InstructionFactory.createArrayStore(Type.OBJECT));
620     }
621
622     // And returns
623
instructionList.append(InstructionConstants.RETURN);
624
625     mg.setMaxStack(); // Needed stack size
626
mg.setMaxLocals(); // Needed locals
627

628     // Add the method to the class
629
this.classGenerator.addMethod(mg.getMethod());
630
631     // Recycling the InstructionList object
632
this.instructionList.dispose();
633
634     return;
635   }
636
637   protected void createGetAndSetProxyMethods() {
638     // Do the getProxy method first
639
MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, // access flags
640
PROXY_TYPE, new Type[0], new String JavaDoc[0], // arg names
641
"getProxy", // Method name
642
this.stubClassFullName, // Class name
643
instructionList, // Instructions list
644
this.classGenerator.getConstantPool());
645
646     // Now, fills in the instruction list
647
InstructionFactory factory = new InstructionFactory(this.classGenerator);
648
649     instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 0));
650     instructionList.append(factory.createGetField(this.stubClassFullName, PROXY_FIELD_NAME, PROXY_TYPE));
651     instructionList.append(InstructionFactory.createReturn(Type.OBJECT));
652
653     mg.setMaxStack(); // Needed stack size
654
mg.setMaxLocals(); // Needed locals
655

656     this.classGenerator.addMethod(mg.getMethod());
657
658     this.instructionList.dispose();
659
660     // Now, do the setProxy method
661
Type[] types = new Type[1];
662     types[0] = PROXY_TYPE;
663     String JavaDoc[] argnames = new String JavaDoc[1];
664     argnames[0] = "p";
665
666       mg = new MethodGen(Constants.ACC_PUBLIC, // access flags
667
Type.VOID, types, argnames, "setProxy", // Method name
668
this.stubClassFullName, // Class name
669
instructionList, // Instructions list
670
this.classGenerator.getConstantPool());
671
672     // Now, fills in the instruction list
673
factory = new InstructionFactory(this.classGenerator);
674
675     instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 0));
676     instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 1));
677     instructionList.append(factory.createPutField(this.stubClassFullName, PROXY_FIELD_NAME, PROXY_TYPE));
678     instructionList.append(InstructionFactory.createReturn(Type.VOID));
679
680     mg.setMaxStack(); // Needed stack size
681
mg.setMaxLocals(); // Needed locals
682

683     this.classGenerator.addMethod(mg.getMethod());
684
685     this.instructionList.dispose();
686
687     return;
688   }
689
690   protected static Type convertClassNameToType(String JavaDoc className) {
691     try {
692       return convertClassToType(Class.forName(className));
693     } catch (ClassNotFoundException JavaDoc e) {
694       return null;
695     }
696   }
697
698   /**
699    * Converts a java.lang.Class object to its org.apache.bcel.generic.Type equivalent
700    */

701
702   protected static Type convertClassToType(Class JavaDoc cl) {
703     if (cl.isPrimitive()) {
704       if (cl.equals(Void.TYPE)) {
705         return Type.VOID;
706       } else if (cl.equals(Boolean.TYPE)) {
707         return Type.BOOLEAN;
708       } else if (cl.equals(Byte.TYPE)) {
709         return Type.BYTE;
710       } else if (cl.equals(Short.TYPE)) {
711         return Type.SHORT;
712       } else if (cl.equals(Integer.TYPE)) {
713         return Type.INT;
714       } else if (cl.equals(Character.TYPE)) {
715         return Type.CHAR;
716       } else if (cl.equals(Long.TYPE)) {
717         return Type.LONG;
718       } else if (cl.equals(Float.TYPE)) {
719         return Type.FLOAT;
720       } else if (cl.equals(Double.TYPE)) {
721         return Type.DOUBLE;
722       } else {
723         return Type.UNKNOWN;
724       }
725     } else {
726       if (cl.isArray()) {
727         return new ArrayType(convertClassToType(cl.getComponentType()), 1);
728       } else {
729         return new ObjectType(cl.getName());
730       }
731     }
732   }
733
734   protected static int lengthOfType(Class JavaDoc cl) {
735     int result;
736     if (cl.isPrimitive()) {
737       if ((cl.equals(Long.TYPE)) || (cl.equals(Double.TYPE))) {
738         result = 2;
739       } else {
740         result = 1;
741       }
742     } else {
743       result = 1;
744     }
745     return result;
746   }
747
748   protected static Type[] convertClassArrayToTypeArray(Class JavaDoc[] cl) {
749     Type[] result = new Type[cl.length];
750     for (int i = 0; i < cl.length; i++) {
751       result[i] = convertClassToType(cl[i]);
752     }
753     return result;
754   }
755
756   /**
757    * This method is called by the constructor
758    */

759
760   protected void setInfos() {
761     // This hashtable is used for keeping track of the method signatures
762
// we have already met while going up the inheritance branch
763
java.util.Hashtable JavaDoc temp = new java.util.Hashtable JavaDoc();
764
765     // Recursively calls getDeclaredMethods () on the target type
766
// and each of its superclasses, all the way up to java.lang.Object
767
// We have to be careful and only take into account overriden methods once
768
Class JavaDoc currentClass = this.cl;
769
770     // This Vector keeps track of all the methods accessible from this class
771
java.util.Vector JavaDoc tempVector = new java.util.Vector JavaDoc();
772     Class JavaDoc[] params;
773     Object JavaDoc exists;
774
775     // If the target type is an interface, the only thing we have to do is to
776
// get the list of all its public methods.
777
if (this.cl.isInterface()) {
778       Method JavaDoc[] allPublicMethods = this.cl.getMethods();
779       for (int i = 0; i < allPublicMethods.length; i++) {
780         tempVector.addElement(allPublicMethods[i]);
781       }
782     } else // If the target type is an actual class, we climb up the tree
783
{
784       do // Loops from the current class up to java.lang.Object
785
{
786         // The declared methods for the current class
787
Method JavaDoc[] declaredMethods = currentClass.getDeclaredMethods();
788
789         // For each method declared in this class
790
for (int i = 0; i < declaredMethods.length; i++) {
791           Method JavaDoc currentMethod = declaredMethods[i];
792           // Build a key with the simple name of the method
793
// and the names of its parameters in the right order
794
String JavaDoc key = "";
795           key = key + currentMethod.getName();
796           params = currentMethod.getParameterTypes();
797           for (int k = 0; k < params.length; k++) {
798             key = key + params[k].getName();
799           }
800
801           // Tests if we already have met this method in a subclass
802
exists = temp.get(key);
803           if (exists == null) {
804             // The only method we ABSOLUTELY want to be called directly
805
// on the stub (and thus not reified) is
806
// the protected void finalize () throws Throwable
807
if ((key.equals("finalize")) && (params.length == 0)) {
808               // Do nothing, simply avoid adding this method to the list
809
} else {
810               // If not, adds this method to the Vector that
811
// holds all the methods for this class
812
tempVector.addElement(currentMethod);
813               temp.put(key, currentMethod);
814             }
815           } else {
816             // We already know this method because it is overriden
817
// in a subclass. Then do nothing
818
}
819         }
820         currentClass = currentClass.getSuperclass();
821       } while (currentClass != null); // Continue until we ask for the superclass of java.lang.Object
822
}
823
824     // Turns the vector into an array of type Method[]
825
this.methods = new Method JavaDoc[tempVector.size()];
826     tempVector.copyInto(this.methods);
827
828     // Determines which methods are valid for reification
829
// It is the responsibility of method checkMethod in class Utils
830
// to decide if a method is valid for reification or not
831

832     java.util.Vector JavaDoc v = new java.util.Vector JavaDoc();
833     int initialNumberOfMethods = this.methods.length;
834
835     for (int i = 0; i < initialNumberOfMethods; i++) {
836       if (Utils.checkMethod(this.methods[i])) {
837         v.addElement(this.methods[i]);
838       }
839     }
840     Method JavaDoc[] validMethods = new Method JavaDoc[v.size()];
841     v.copyInto(validMethods);
842
843     // Installs the list of valid methods as an instance variable of this object
844
this.methods = validMethods;
845
846     this.packageName = Utils.getPackageName(this.className);
847     this.stubClassFullName = Utils.convertClassNameToStubClassName(this.className);
848     this.stubClassSimpleName = Utils.getSimpleName(this.stubClassFullName);
849
850     return;
851   }
852
853   public String JavaDoc getStubClassFullName() {
854     return this.stubClassFullName;
855   }
856 }
Popular Tags