KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.apache.log4j.Logger;
34
35 import org.objectweb.asm.CodeVisitor;
36 import org.objectweb.asm.Type;
37
38 import org.objectweb.fractal.api.Component;
39 import org.objectweb.fractal.api.type.InterfaceType;
40
41 import org.objectweb.proactive.core.component.ProActiveInterface;
42 import org.objectweb.proactive.core.component.exceptions.InterfaceGenerationFailedException;
43 import org.objectweb.proactive.core.mop.StubObject;
44 import org.objectweb.proactive.core.mop.Utils;
45
46 import java.io.Serializable JavaDoc;
47
48 import java.lang.reflect.Method JavaDoc;
49
50 import java.util.Hashtable JavaDoc;
51 import java.util.Map JavaDoc;
52 import java.util.Vector JavaDoc;
53
54
55 /**
56  * Generates Interface implementations for the functional interfaces of the
57  * component representative.
58  *<br>
59  * This class :<br>
60  * - implements the java interface corresponding to the functional
61  * interface of the component.<br>
62  * - implements StubObject, like the standard ProActive stub<br>
63  * - is linked to the ProActive proxy (corresponding to the actual active object)
64  *<br>
65  * Method calls are reified as MethodCall objects, that contain :<br>
66  * - a tag signaling component requests<br>
67  * - the name given to the component functional interface.<br>
68  *
69  * @author Matthieu Morel
70  */

71 public class RepresentativeInterfaceClassGenerator
72     extends AbstractInterfaceClassGenerator {
73     protected static Logger logger = Logger.getLogger(RepresentativeInterfaceClassGenerator.class.getName());
74
75     // A few constants that come in handy when using ASM in our case
76
protected static final String JavaDoc PROXY_TYPE = "Lorg/objectweb/proactive/core/mop/Proxy;";
77     protected static final String JavaDoc STUB_INTERFACE_NAME = "org/objectweb/proactive/core/mop/StubObject";
78     protected static final String JavaDoc PROXY_FIELD_NAME = "myProxy";
79
80     // generatedClassesCache that contains all the generated classes according to their name
81
private static Hashtable JavaDoc generatedClassesCache = new Hashtable JavaDoc();
82     private static RepresentativeInterfaceClassGenerator instance;
83
84     // this boolean for deciding of a possible indirection for the functionnal calls
85
protected boolean isPrimitive = false;
86     private String JavaDoc fcInterfaceName = null;
87
88     public RepresentativeInterfaceClassGenerator() {
89         // Obtains the object that represents the type we want to create
90
// a wrapper class for. This call may fail with a ClassNotFoundException
91
// if the class corresponding to this type cannot be found.
92
this.cl = ProActiveInterface.class;
93
94         // Keep this info at hand for performance purpose
95
this.className = cl.getName();
96
97         //generatedClassesCache = new Hashtable();
98
}
99
100     public static RepresentativeInterfaceClassGenerator instance() {
101         if (instance == null) {
102             return new RepresentativeInterfaceClassGenerator();
103         } else {
104             return instance;
105         }
106     }
107
108     /**
109     * retreives the bytecode associated to the generated class of the given name
110     */

111     public static byte[] getClassData(String JavaDoc classname) {
112         return (byte[]) getGeneratedClassesCache().get(classname);
113     }
114
115     /**
116     * Returns the generatedClassesCache.
117     * @return a Map acting as a cache for generated classes
118     */

119     public static Map JavaDoc getGeneratedClassesCache() {
120         return generatedClassesCache;
121     }
122
123     public ProActiveInterface generateInterface(final String JavaDoc fcInterfaceName,
124         Component owner, InterfaceType interfaceType, boolean isInternal)
125         throws InterfaceGenerationFailedException {
126         try {
127             this.fcInterfaceName = fcInterfaceName;
128
129             //isPrimitive = ((ProActiveComponentRepresentativeImpl) owner).getHierarchicalType()
130
// .equals(ComponentParameters.PRIMITIVE);
131
interfacesToImplement = new Vector JavaDoc();
132
133             // add functional interface
134
interfacesToImplement.add(Class.forName(
135                     interfaceType.getFcItfSignature()));
136
137             // add Serializable interface
138
interfacesToImplement.addElement(Serializable JavaDoc.class);
139
140             // add StubObject, so we can set the proxy
141
interfacesToImplement.addElement(StubObject.class);
142
143             this.stubClassFullName = org.objectweb.proactive.core.component.asmgen.Utils.getMetaObjectComponentRepresentativeClassName(fcInterfaceName,
144                     interfaceType.getFcItfSignature());
145             //}
146
Class JavaDoc generated_class;
147
148             // check whether class has already been generated
149
try {
150                 generated_class = loadClass(stubClassFullName);
151             } catch (ClassNotFoundException JavaDoc cnfe) {
152                 byte[] bytes;
153                 setInfos();
154                 bytes = create();
155                 RepresentativeInterfaceClassGenerator.generatedClassesCache.put(stubClassFullName,
156                     bytes);
157                 if (logger.isDebugEnabled()) {
158                     logger.debug("added " + stubClassFullName + " to cache");
159                 }
160                 if (logger.isDebugEnabled()) {
161                     logger.debug("generated classes cache is : " +
162                         generatedClassesCache.toString());
163                 }
164
165 // // Next few lines for debugging only
166
// try {
167
// java.io.File file = new java.io.File(System.getProperty("user.home") + "/ProActive/generated/" +
168
// stubClassFullName + ".class");
169
//
170
// if (logger.isDebugEnabled()) {
171
// //logger.debug("writing down the generated class : " + file.getAbsolutePath());
172
// }
173
//
174
// java.io.FileOutputStream fos = new java.io.FileOutputStream(file);
175
// fos.write(bytes);
176
// fos.close();
177
// } catch (Exception e) {
178
// // e.printStackTrace();
179
// logger.info("if you want a dump of the generated classes, you need to create a /generated folder at the root of you command");
180
// }
181
// convert the bytes into a Class
182
generated_class = defineClass(stubClassFullName, bytes);
183             }
184
185             ProActiveInterface reference = (ProActiveInterface) generated_class.newInstance();
186             reference.setName(fcInterfaceName);
187             reference.setOwner(owner);
188             reference.setType(interfaceType);
189             reference.setIsInternal(isInternal);
190
191             return reference;
192         } catch (ClassNotFoundException JavaDoc e) {
193             throw new InterfaceGenerationFailedException("cannot find interface signature class",
194                 e);
195         } catch (IllegalAccessException JavaDoc e) {
196             throw new InterfaceGenerationFailedException("constructor not accessible",
197                 e);
198         } catch (InstantiationException JavaDoc e) {
199             throw new InterfaceGenerationFailedException("constructor belongs to an abstract class?",
200                 e);
201             // TODO : check this
202
}
203     }
204
205     protected CodeVisitor createMethod(int methodIndex, Method JavaDoc m) {
206         CodeVisitor cv = createMethodGenerator(m);
207
208         // Pushes on the stack the reference to the proxy object
209
cv.visitVarInsn(ALOAD, 0);
210         cv.visitFieldInsn(GETFIELD, this.stubClassFullName.replace('.', '/'),
211             PROXY_FIELD_NAME, PROXY_TYPE);
212
213         // Pushes on the stack the Method object that represents the current method
214
cv.visitFieldInsn(GETSTATIC, this.stubClassFullName.replace('.', '/'),
215             "methods", METHOD_ARRAY_TYPE);
216         pushInt(cv, methodIndex);
217         cv.visitInsn(AALOAD);
218
219         Class JavaDoc[] paramTypes = m.getParameterTypes();
220
221         // Create an array of type Object[] for holding all the parameters
222
// Push on the stack the size of the array
223
pushInt(cv, paramTypes.length);
224
225         // Creates an array of class objects of that size
226
cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
227
228         // Fill in the array with the parameters
229
int indexInParameterArray = 1; // Necessary because sometimes we need to jump 2 slots ahead
230
for (int i = 0; i < paramTypes.length; i++) {
231             // First, duplicate the reference to the array of type Object[]
232
// That currently sits on top of the stack
233
cv.visitInsn(DUP);
234
235             // Load the array index for storing the result
236
pushInt(cv, i);
237
238             //Type theType = convertClassToType(paramTypes[i]);
239
Class JavaDoc param = paramTypes[i];
240
241             // If it is a primitive type, we need to create the wrapper here
242
if (param.isPrimitive()) {
243                 int opcode = ILOAD;
244                 String JavaDoc type;
245                 String JavaDoc desc;
246                 if (param == Byte.TYPE) {
247                     type = "java/lang/Byte";
248                     desc = "B";
249                 } else if (param == Integer.TYPE) {
250                     type = "java/lang/Integer";
251                     desc = "I";
252                 } else if (param == Boolean.TYPE) {
253                     type = "java/lang/Boolean";
254                     desc = "Z";
255                 } else if (param == Double.TYPE) {
256                     opcode = DLOAD;
257                     type = "java/lang/Double";
258                     desc = "D";
259                 } else if (param == Float.TYPE) {
260                     opcode = FLOAD;
261                     type = "java/lang/Float";
262                     desc = "F";
263                 } else if (param == Long.TYPE) {
264                     opcode = LLOAD;
265                     type = "java/lang/Long";
266                     desc = "J";
267                 } else if (param == Character.TYPE) {
268                     type = "java/lang/Character";
269                     desc = "C";
270                 } else /*if (param == Short.TYPE)*/
271                  {
272                     type = "java/lang/Short";
273                     desc = "S";
274                 }
275                 cv.visitTypeInsn(NEW, type);
276                 cv.visitInsn(DUP);
277                 cv.visitVarInsn(opcode, indexInParameterArray);
278                 cv.visitMethodInsn(INVOKESPECIAL, type, "<init>",
279                     "(" + desc + ")V");
280             } else {
281                 cv.visitVarInsn(ALOAD, indexInParameterArray);
282             }
283             indexInParameterArray += (((param == Double.TYPE) ||
284             (param == Long.TYPE)) ? 2 : 1);
285
286             // Stores the object in the array
287
cv.visitInsn(AASTORE);
288         }
289
290         // So now we have the Method object and the array of objects on the stack,
291
// Pushes on the stack the reference to the functional interface name
292
cv.visitFieldInsn(GETSTATIC, this.stubClassFullName.replace('.', '/'),
293             FUNCTIONAL_INTERFACE_NAME_FIELD_NAME, FUNCTIONAL_INTERFACE_NAME_TYPE);
294
295         cv.visitMethodInsn(INVOKESTATIC,
296             "org/objectweb/proactive/core/mop/MethodCall",
297             "getComponentMethodCall",
298             "(" + METHOD_TYPE + OBJECT_ARRAY_TYPE +
299             FUNCTIONAL_INTERFACE_NAME_TYPE + ")" + METHODCALL_TYPE);
300         // }
301
// Now, call 'reify' on the proxy object
302
cv.visitMethodInsn(INVOKEINTERFACE,
303             "org/objectweb/proactive/core/mop/Proxy", "reify",
304             "(" + METHODCALL_TYPE + ")" + OBJECT_TYPE);
305
306         // If the return type of the method is a primitive type,
307
// we want to unwrap it first
308
if (m.getReturnType().isPrimitive()) {
309             this.createUnwrappingCode(cv, m.getReturnType());
310         } else {
311             // If the return type is a reference type,
312
// we need to insert a type check
313
cv.visitTypeInsn(CHECKCAST, Type.getInternalName(m.getReturnType()));
314         }
315         createReturnCode(cv, m.getReturnType());
316         cv.visitMaxs(0, 0); // max stack and max locals automatically computed
317

318         return cv;
319     }
320
321     protected void createFields() {
322         // Creates the field that points to the active object
323
this.classGenerator.visitField(ACC_PROTECTED, PROXY_FIELD_NAME,
324             PROXY_TYPE, null, null);
325     }
326
327     protected void createStaticVariables() {
328         // Creates fields that contains the array of Method objects
329
// that represent the reified methods of this class
330
this.classGenerator.visitField(ACC_PROTECTED | ACC_STATIC, "methods",
331             METHOD_ARRAY_TYPE, null, null);
332
333         // creates and set the field that points to the functional interface name
334
this.classGenerator.visitField(ACC_PROTECTED | ACC_STATIC,
335             FUNCTIONAL_INTERFACE_NAME_FIELD_NAME,
336             FUNCTIONAL_INTERFACE_NAME_TYPE, fcInterfaceName, null);
337     }
338
339     protected void createStaticInitializer() throws ClassNotFoundException JavaDoc {
340         // Creates the class initializer method itself
341
CodeVisitor cv = this.classGenerator.visitMethod(ACC_STATIC,
342                 "<clinit>", "()V", null, null);
343
344         // Creates an array of Method objects that we will store into the static
345
// variable 'methods' of type 'Method[]'
346
// Pushes the size of the array on to the stack
347
pushInt(cv, this.methods.length);
348
349         // Creates an array of Method objects of that size
350
cv.visitTypeInsn(ANEWARRAY, "java/lang/reflect/Method");
351
352         // Stores the reference to this newly-created array into the static variable 'methods'
353
cv.visitFieldInsn(PUTSTATIC, this.stubClassFullName.replace('.', '/'),
354             "methods", METHOD_ARRAY_TYPE);
355
356         // Pushes on the stack the size of the array
357
pushInt(cv, interfacesToImplement.size());
358
359         // Creates an array of class objects of that size
360
cv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
361
362         // Stores the reference to this newly-created array as the local variable with index '1'
363
cv.visitVarInsn(ASTORE, 1);
364
365         // Make as many calls to Class.forName as is needed to fill in the array
366
for (int i = 0; i < interfacesToImplement.size(); i++) {
367             // Load onto the stack a pointer to the array
368
cv.visitVarInsn(ALOAD, 1);
369
370             // Load the index in the array where we want to store the result
371
pushInt(cv, i);
372
373             // Loads the generatedClassName of the class onto the stack
374
String JavaDoc s = ((Class JavaDoc) interfacesToImplement.elementAt(i)).getName();
375             cv.visitLdcInsn(s);
376
377             // Performs the call to Class.forName
378
cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName",
379                 "(Ljava/lang/String;)Ljava/lang/Class;");
380
381             // Stores the result of the invocation of forName into the array
382
// The index into which to store as well as the reference to the array
383
// are already on the stack
384
cv.visitInsn(AASTORE);
385         }
386
387         // Now, lookup each of the Method objects and store it into the 'method' array
388
for (int i = 0; i < this.methods.length; i++) {
389             // Stacks up the reference to the array of methods and the index in the array
390
cv.visitFieldInsn(GETSTATIC,
391                 this.stubClassFullName.replace('.', '/'), "methods",
392                 METHOD_ARRAY_TYPE);
393             pushInt(cv, i);
394
395             // Now, we load onto the stack a pointer to the class that contains the method
396
int indexInClassArray = interfacesToImplement.indexOf(this.methods[i].getDeclaringClass());
397             if (indexInClassArray == -1) {
398             }
399
400             // Load a pointer to the Class array (local variable number 1)
401
cv.visitVarInsn(ALOAD, 1);
402
403             // Access element number 'indexInClassArray'
404
pushInt(cv, indexInClassArray);
405             cv.visitInsn(AALOAD);
406
407             // Now, perform a call to 'getDeclaredMethod'
408
// First, stack up the simple generatedClassName of the method to solve
409
cv.visitLdcInsn(this.methods[i].getName());
410
411             // Now, we want to create an array of type Class[] for representing
412
// the parameters to this method. We choose to store this array into the
413
// slot number 2
414
// Pushes the size of the array
415
pushInt(cv, this.methods[i].getParameterTypes().length);
416
417             // Creates an array of class objects of that size
418
cv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
419
420             // Stores the reference to this newly-created array as the local variable with index '2'
421
cv.visitVarInsn(ASTORE, 2);
422
423             // Stack up the class objects that represent the types of all the arguments to this method
424
for (int j = 0; j < this.methods[i].getParameterTypes().length;
425                     j++) {
426                 Class JavaDoc currentParameter = this.methods[i].getParameterTypes()[j];
427
428                 // Load onto the stack a pointer to the array of Class objects (for parameters)
429
cv.visitVarInsn(ALOAD, 2);
430
431                 // Load the index in the array where we want to store the result
432
pushInt(cv, j);
433
434                 // If the type of the parameter is a primitive one, we use the predefined
435
// constants (like java.lang.Integer.TYPE) instead of calling Class.forName
436
if (currentParameter.isPrimitive()) {
437                     // Loads that static variable
438
cv.visitFieldInsn(GETSTATIC,
439                         Type.getInternalName(Utils.getWrapperClass(
440                                 currentParameter)), "TYPE", "Ljava/lang/Class;");
441                 } else {
442                     // Load the generatedClassName of the parameter class onto the stack
443
cv.visitLdcInsn(currentParameter.getName());
444
445                     // Performs a call to Class.forName
446
cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class",
447                         "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
448                 }
449
450                 // Stores the result in the array
451
cv.visitInsn(AASTORE);
452             }
453
454             // Loads the array
455
cv.visitVarInsn(ALOAD, 2);
456
457             // Perform the actual call to 'getDeclaredMethod'
458
cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class",
459                 "getDeclaredMethod",
460                 "(Ljava/lang/String;[Ljava/lang/Class;)" + METHOD_TYPE);
461
462             // Now that we have the result, let's store it into the array
463
cv.visitInsn(AASTORE);
464         }
465
466         // And returns
467
cv.visitInsn(RETURN);
468
469         // Needed stack size
470
// Needed locals
471
cv.visitMaxs(0, 0);
472
473         return;
474     }
475
476     protected void createGetAndSetProxyMethods() {
477         // Do the getProxy method first
478
CodeVisitor cv = this.classGenerator.visitMethod(ACC_PUBLIC,
479                 "getProxy", "()" + PROXY_TYPE, null, null);
480
481         // Now, fills in the instruction list
482
cv.visitVarInsn(ALOAD, 0);
483         cv.visitFieldInsn(GETFIELD, this.stubClassFullName.replace('.', '/'),
484             PROXY_FIELD_NAME, PROXY_TYPE);
485         cv.visitInsn(ARETURN);
486
487         // Needed stack size
488
// Needed locals
489
cv.visitMaxs(0, 0);
490
491         // Now, do the setProxy method
492
cv = this.classGenerator.visitMethod(ACC_PUBLIC, "setProxy",
493                 "(" + PROXY_TYPE + ")V", null, null);
494
495         // Now, fills in the instruction list
496
cv.visitVarInsn(ALOAD, 0);
497         cv.visitVarInsn(ALOAD, 1);
498         cv.visitFieldInsn(PUTFIELD, this.stubClassFullName.replace('.', '/'),
499             PROXY_FIELD_NAME, PROXY_TYPE);
500         cv.visitInsn(RETURN);
501
502         // Needed stack size
503
// Needed locals
504
cv.visitMaxs(0, 0);
505
506         return;
507     }
508
509     protected static int lengthOfType(Class JavaDoc cl) {
510         int result;
511         if (cl.isPrimitive()) {
512             if ((cl.equals(Long.TYPE)) || (cl.equals(Double.TYPE))) {
513                 result = 2;
514             } else {
515                 result = 1;
516             }
517         } else {
518             result = 1;
519         }
520         return result;
521     }
522
523     /**
524      * implementation of abstract method defined in mother class
525      */

526     protected void createDefaultMethods() {
527         createGetAndSetProxyMethods();
528     }
529 }
530
Popular Tags