KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > proactive > core > component > asmgen > AbstractInterfaceClassGenerator


1 /*
2  * ################################################################
3  *
4  * ProActive: The Java(TM) library for Parallel, Distributed,
5  * Concurrent computing with Security and Mobility
6  *
7  * Copyright (C) 1997-2004 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.component.asmgen;
32
33 import java.lang.reflect.InvocationTargetException JavaDoc;
34 import java.lang.reflect.Method JavaDoc;
35 import java.lang.reflect.Modifier JavaDoc;
36
37 import java.util.Vector JavaDoc;
38
39 import org.objectweb.asm.ClassWriter;
40 import org.objectweb.asm.CodeVisitor;
41 import org.objectweb.asm.Constants;
42 import org.objectweb.asm.Type;
43
44 import org.objectweb.proactive.core.ProActiveRuntimeException;
45
46
47 /**
48  * Abstract parent class for Interface implementation generation.
49  * It defines a skeleton for the classes generation, and provides a set of utility
50  * methods that will be used by derived classes.
51  *
52  * @author Matthieu Morel
53  */

54 public abstract class AbstractInterfaceClassGenerator implements Constants {
55     // A few constants that come in handy when using ASM in our case
56
protected static final String JavaDoc METHODCALL_TYPE = "Lorg/objectweb/proactive/core/mop/MethodCall;";
57     protected static final String JavaDoc OBJECT_TYPE = "Ljava/lang/Object;";
58     protected static final String JavaDoc OBJECT_ARRAY_TYPE = "[Ljava/lang/Object;";
59     protected static final String JavaDoc METHOD_TYPE = "Ljava/lang/reflect/Method;";
60     protected static final String JavaDoc METHOD_ARRAY_TYPE = "[Ljava/lang/reflect/Method;";
61     protected static final String JavaDoc FUNCTIONAL_INTERFACE_NAME_TYPE = "Ljava/lang/String;";
62     protected static final String JavaDoc FUNCTIONAL_INTERFACE_NAME_FIELD_NAME = "fcFunctionalInterfaceName";
63     protected static final String JavaDoc SUPER_CLASS_NAME = "org/objectweb/proactive/core/component/ProActiveInterface";
64
65     // Those fields contain information about the class
66
// for which we are building a wrapper
67
protected Class JavaDoc cl;
68     protected String JavaDoc className;
69     protected String JavaDoc packageName;
70     protected Method JavaDoc[] methods;
71     protected Vector JavaDoc interfacesToImplement; // contains Class object corresponding to the interfaces
72
protected ClassWriter classGenerator;
73
74     // The following fields have to do with
75
// the actual generation of the stub
76
protected String JavaDoc stubClassSimpleName;
77     protected String JavaDoc stubClassFullName;
78
79     /**
80      * Method createStaticInitializer.
81      */

82     protected abstract void createStaticInitializer() throws ClassNotFoundException JavaDoc;
83
84     /**
85      * Method createFields.
86      */

87     protected abstract void createFields();
88
89     /**
90      * Method createDefaultMethods.
91      */

92     protected abstract void createDefaultMethods();
93
94     /**
95      * Method createMethod.
96      * @param i
97      * @param method
98      * @return CodeVisitor
99      */

100     protected abstract CodeVisitor createMethod(int i, Method JavaDoc method);
101
102     /**
103      * Method createStaticVariables.
104      */

105     protected abstract void createStaticVariables();
106
107     // ASM : added utility methods
108
static void pushInt(CodeVisitor cv, int i) {
109         if ((i >= -128) && (i < 128)) {
110             cv.visitIntInsn(BIPUSH, i);
111         } else if ((i >= -32768) && (i < 32768)) {
112             cv.visitIntInsn(SIPUSH, i);
113         } else {
114             cv.visitLdcInsn(new Integer JavaDoc(i));
115         }
116     }
117
118     /** utility method
119      * @param javaModifier
120      * @return the code identifying the java modifier with ASM
121      */

122     protected static int convertJavaModifierToASM(int javaModifier) {
123         int result = 0;
124
125         if (Modifier.isAbstract(javaModifier)) {
126             result = result | Constants.ACC_ABSTRACT;
127         }
128         if (Modifier.isFinal(javaModifier)) {
129             result = result | Constants.ACC_FINAL;
130         }
131         if (Modifier.isInterface(javaModifier)) {
132             result = result | Constants.ACC_INTERFACE;
133         }
134         if (Modifier.isNative(javaModifier)) {
135             result = result | Constants.ACC_NATIVE;
136         }
137         if (Modifier.isPrivate(javaModifier)) {
138             result = result | Constants.ACC_PRIVATE;
139         }
140         if (Modifier.isProtected(javaModifier)) {
141             result = result | Constants.ACC_PROTECTED;
142         }
143         if (Modifier.isPublic(javaModifier)) {
144             result = result | Constants.ACC_PUBLIC;
145         }
146         if (Modifier.isStatic(javaModifier)) {
147             result = result | Constants.ACC_STATIC;
148         }
149         if (Modifier.isSynchronized(javaModifier)) {
150             result = result | Constants.ACC_SYNCHRONIZED;
151         }
152         if (Modifier.isTransient(javaModifier)) {
153             result = result | Constants.ACC_TRANSIENT;
154         }
155         if (Modifier.isVolatile(javaModifier)) {
156             result = result | Constants.ACC_VOLATILE;
157         }
158
159         return result;
160     }
161
162     /** utility method
163      * @param modifiers
164      * @return modifiers after applying masks
165      */

166     protected static int removeNativeAndAbstractModifiers(int modifiers) {
167         // In order to set to 0 the bit that represents 'native', we first
168
// compute the mask that contains 1s everywhere and a 0 where the bit
169
// is, and then apply this mask with an 'and', bitwise.
170
int result = modifiers & (~Modifier.NATIVE);
171         result = result & (~Modifier.ABSTRACT);
172         return result;
173     }
174
175     /** utility method
176      * @return the full class name of the stub
177      */

178     public String JavaDoc getStubClassFullName() {
179         return this.stubClassFullName;
180     }
181
182     /** actually creates the bytecode corresponding to the generated class
183      * @throws ClassNotFoundException
184      * @return the bytecode corresponding to the generated class
185      */

186     public byte[] create() throws ClassNotFoundException JavaDoc {
187         // Creates the class generator
188
this.classGenerator = this.createClassGenerator();
189
190
191         // Add a public no-arg constructor
192
this.createConstructor();
193
194         // Creates all the methods in the class
195
for (int i = 0; i < this.methods.length; i++) {
196             // walkaround (NOT CLEAN) to avoid generating reified calls for the proxy methods
197
if (!(methods[i].getName().equals("getProxy") || methods[i].getName().equals("setProxy"))) {
198                 CodeVisitor mg = this.createMethod(i, this.methods[i]);
199             }
200         }
201
202         this.createDefaultMethods();
203
204
205         // Creates the fields of the class
206
this.createFields();
207
208
209         // Create the static fields
210
this.createStaticVariables();
211
212
213         // Creates the static initializer
214
this.createStaticInitializer();
215
216         return this.classGenerator.toByteArray();
217     }
218
219     /**
220      * @return a visitor for writing Java classes
221      */

222     protected ClassWriter createClassGenerator() {
223         String JavaDoc[] interfaces = new String JavaDoc[interfacesToImplement.size()];
224         for (int i = 0; i < interfacesToImplement.size(); i++) {
225             interfaces[i] = ((Class JavaDoc) interfacesToImplement.get(i)).getName().replace('.', '/');
226         }
227
228         ClassWriter cw = new ClassWriter(true);
229         cw.visit(Constants.ACC_PUBLIC | Constants.ACC_SUPER, // Same access modifiers as superclass or public ???
230

231         this.stubClassFullName, SUPER_CLASS_NAME, // Superclass
232
interfaces, // declared interfaces
233
"<generated>");
234         return cw;
235     }
236
237     protected void createConstructor() {
238         // Actually creates the method generator (ASM : uses the visitor)
239
CodeVisitor cv = this.classGenerator.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
240
241         //Calls the constructor of the super class
242
cv.visitVarInsn(ALOAD, 0);
243
244         //cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
245
cv.visitMethodInsn(INVOKESPECIAL, SUPER_CLASS_NAME, "<init>", "()V");
246
247         // And returns from the constructor
248
cv.visitInsn(RETURN);
249
250
251         // Needed stack size
252
// Needed locals
253
cv.visitMaxs(0, 0);
254
255         return;
256     }
257
258     protected CodeVisitor createMethodGenerator(Method JavaDoc m) {
259         // Extracts modifiers
260
int flags = convertJavaModifierToASM(m.getModifiers());
261
262
263         // Modifies the modifiers in order to remove 'native' and 'abstract'
264
flags = removeNativeAndAbstractModifiers(flags);
265
266         // Extracts return and arguments types
267
String JavaDoc mDesc = Type.getMethodDescriptor(m);
268
269         // Actually creates the method generator
270
CodeVisitor cv = this.classGenerator.visitMethod(flags, // access flags
271
m.getName(), // Method generatedClassName
272
mDesc, // return and argument types
273
null, // exceptions
274
null); // Attributes
275
return cv;
276     }
277
278     protected void createUnwrappingCode(CodeVisitor cv, Class JavaDoc c) {
279         // Depending on the type of the wrapper, the code differs
280
// The parameter 'c' represents the primitive type, not the type of the
281
// wrapper
282
if (c == Void.TYPE) {
283             cv.visitInsn(POP);
284         } else if (c.isPrimitive()) {
285             String JavaDoc type;
286             String JavaDoc meth;
287             String JavaDoc desc;
288             if (c == Byte.TYPE) {
289                 type = "java/lang/Byte";
290                 meth = "byteValue";
291                 desc = "B";
292             } else if (c == Integer.TYPE) {
293                 type = "java/lang/Integer";
294                 meth = "intValue";
295                 desc = "I";
296             } else if (c == Boolean.TYPE) {
297                 type = "java/lang/Boolean";
298                 meth = "booleanValue";
299                 desc = "Z";
300             } else if (c == Double.TYPE) {
301                 type = "java/lang/Double";
302                 meth = "doubleValue";
303                 desc = "D";
304             } else if (c == Float.TYPE) {
305                 type = "java/lang/Float";
306                 meth = "floatValue";
307                 desc = "F";
308             } else if (c == Long.TYPE) {
309                 type = "java/lang/Long";
310                 meth = "longValue";
311                 desc = "J";
312             } else if (c == Character.TYPE) {
313                 type = "java/lang/Character";
314                 meth = "charValue";
315                 desc = "C";
316             } else/*if (result == Short.TYPE)*/
317             {
318                 type = "java/lang/Short";
319                 meth = "shortValue";
320                 desc = "S";
321             }
322             cv.visitTypeInsn(CHECKCAST, type);
323             cv.visitMethodInsn(INVOKEVIRTUAL, type, meth, "()" + desc);
324         } else {
325             cv.visitTypeInsn(CHECKCAST, Type.getInternalName(c));
326         }
327
328         return;
329     }
330
331     protected void createReturnCode(CodeVisitor cv, Class JavaDoc c) {
332         if (c == Void.TYPE) {
333             cv.visitInsn(RETURN);
334         } else if (c.isPrimitive()) {
335             int opcode;
336             if (c == Double.TYPE) {
337                 opcode = DRETURN;
338             } else if (c == Float.TYPE) {
339                 opcode = FRETURN;
340             } else if (c == Long.TYPE) {
341                 opcode = LRETURN;
342             } else {
343                 opcode = IRETURN;
344             }
345             cv.visitInsn(opcode);
346         } else {
347             cv.visitInsn(ARETURN);
348         }
349     }
350
351     /**
352     * Returns the offset which must be added to some opcodes to get an opcode of
353     * the given type. More precisely, returns the offset which must be added to
354     * an opc_iXXXX opcode to get the opc_YXXXX opcode corresponding to the given
355     * type. For example, if the given type is double the result is 3, which
356     * means that opc_dload, opc_dstore, opc_dreturn... opcodes are equal to
357     * opc_iload+3, opc_istore+3, opc_ireturn+3...
358     *
359     * @param type a Java class representing a Java type (primitive or not).
360     * @return the opcode offset of the corresponding to the given type.
361     */

362     protected int getOpcodeOffset(final Class JavaDoc type) {
363         if (type == Double.TYPE) {
364             return 3;
365         } else if (type == Float.TYPE) {
366             return 2;
367         } else if (type == Long.TYPE) {
368             return 1;
369         } else if (type.isPrimitive()) {
370             return 0;
371         }
372         return 4;
373     }
374
375     /**
376      * Return the size of the given type. This size is 2 for the double and long
377      * types, and 1 for the other types.
378      *
379      * @param type a Java class representing a Java type (primitive or not).
380      * @return the size of the given type.
381      */

382     protected int getSize(final Class JavaDoc type) {
383         return (((type == Double.TYPE) || (type == Long.TYPE)) ? 2 : 1);
384     }
385
386     protected Class JavaDoc defineClass(final String JavaDoc className, final byte[] bytes) {
387         // The following code invokes defineClass on the current thread classloader by reflection
388
try {
389             Class JavaDoc clc = Class.forName("java.lang.ClassLoader");
390             Class JavaDoc[] argumentTypes = new Class JavaDoc[4];
391             argumentTypes[0] = className.getClass();
392             argumentTypes[1] = bytes.getClass();
393             argumentTypes[2] = Integer.TYPE;
394             argumentTypes[3] = Integer.TYPE;
395
396             Method JavaDoc method = clc.getDeclaredMethod("defineClass", argumentTypes);
397             method.setAccessible(true);
398
399             Object JavaDoc[] effectiveArguments = new Object JavaDoc[4];
400             effectiveArguments[0] = className;
401             effectiveArguments[1] = bytes;
402             effectiveArguments[2] = new Integer JavaDoc(0);
403             effectiveArguments[3] = new Integer JavaDoc(bytes.length);
404
405             return (Class JavaDoc) method.invoke(Thread.currentThread().getContextClassLoader(), effectiveArguments);
406         } catch (ClassNotFoundException JavaDoc cnfe) {
407             cnfe.printStackTrace();
408
409             //cat.error(cnfe.toString());
410
throw new ProActiveRuntimeException(cnfe.toString());
411         } catch (NoSuchMethodException JavaDoc nsme) {
412             nsme.printStackTrace();
413
414             //cat.error(nsme.toString());
415
throw new ProActiveRuntimeException(nsme.toString());
416         } catch (IllegalAccessException JavaDoc iae) {
417             iae.printStackTrace();
418             throw new ProActiveRuntimeException(iae.toString());
419         } catch (InvocationTargetException JavaDoc ite) {
420             ite.printStackTrace();
421             throw new ProActiveRuntimeException(ite.toString());
422         }
423     }
424
425     protected Class JavaDoc loadClass(final String JavaDoc className) throws ClassNotFoundException JavaDoc {
426         // try to fetch the class from the default class loader
427
return Thread.currentThread().getContextClassLoader().loadClass(className);
428     }
429
430     /**
431     * This method is called by the constructor
432     */

433     protected void setInfos() throws ClassNotFoundException JavaDoc {
434         // This Vector keeps track of all the methods accessible from this class
435
Vector JavaDoc tempVector = new Vector JavaDoc();
436         Class JavaDoc[] params;
437         Object JavaDoc exists;
438
439         // If the target type is an interface, the only thing we have to do is to
440
// get the list of all its public methods.
441

442         for (int j = 0; j < interfacesToImplement.size(); j++) {
443             //Class interface_class = Class.forName((String) interfacesToImplement.get(j));
444
Class JavaDoc interface_class = (Class JavaDoc) interfacesToImplement.get(j);
445             Method JavaDoc[] allPublicMethods = interface_class.getMethods();
446             for (int i = 0; i < allPublicMethods.length; i++) {
447                 tempVector.addElement(allPublicMethods[i]);
448             }
449         }
450
451         // Turns the vector into an array of type Method[]
452
this.methods = new Method JavaDoc[tempVector.size()];
453         tempVector.copyInto(this.methods);
454
455         // Determines which methods are valid for reification
456
// It is the responsibility of method checkMethod in class Utils
457
// to decide if a method is valid for reification or not
458
Vector JavaDoc v = new Vector JavaDoc();
459         int initialNumberOfMethods = this.methods.length;
460
461         for (int i = 0; i < initialNumberOfMethods; i++) {
462             if (org.objectweb.proactive.core.mop.Utils.checkMethod(this.methods[i])) {
463                 v.addElement(this.methods[i]);
464             }
465         }
466
467         Method JavaDoc[] validMethods = new Method JavaDoc[v.size()];
468         v.copyInto(validMethods);
469
470
471         // Installs the list of valid methods as an instance variable of this object
472
this.methods = validMethods;
473
474
475         this.packageName = null;
476         this.stubClassSimpleName = org.objectweb.proactive.core.mop.Utils.getSimpleName(this.stubClassFullName);
477
478         return;
479     }
480 }
Popular Tags