KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > julia > asm > ContextClassGenerator


1 /***
2  * Julia: France Telecom's implementation of the Fractal API
3  * Copyright (C) 2001-2002 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: Eric.Bruneton@rd.francetelecom.com
20  *
21  * Author: Eric Bruneton
22  */

23
24 package org.objectweb.fractal.julia.asm;
25
26 import org.objectweb.fractal.julia.loader.Loader;
27 import org.objectweb.fractal.julia.loader.Tree;
28
29 import org.objectweb.asm.ClassVisitor;
30 import org.objectweb.asm.ClassWriter;
31 import org.objectweb.asm.CodeVisitor;
32 import org.objectweb.asm.Constants;
33 import org.objectweb.asm.Label;
34 import org.objectweb.asm.Type;
35
36 import java.util.ArrayList JavaDoc;
37 import java.util.Arrays JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Map JavaDoc;
41
42 /**
43  * A class generator to generate {@link
44  * org.objectweb.fractal.julia.InitializationContext} classes. This class
45  * generates classes of the following form:
46  *
47  * <pre>
48  * public class <i>XYZ</i> extends InitializationContext implements Generated {
49  *
50  * private static ComponentType componentType;
51  * private static ComponentType internalComponentType;
52  *
53  * public void create() {
54  * super.create();
55  * ComponentType compType;
56  * if (componentType == null) {
57  * TypeFactory tf = (TypeFactory)hints;
58  * componentType = tf.createFcType(new InterfaceType[] {
59  * tf.createFcItfType(...),
60  * ...
61  * tf.createFcItfType(...)
62  * });
63  * internalComponentType = tf.createFcType(new InterfaceType[] {
64  * tf.createFcItfType(...),
65  * ...
66  * tf.createFcItfType(...)
67  * });
68  * }
69  * compType = componentType;
70  * controllers.add(new <i>controller-class1</i>());
71  * ...
72  * controllers.add(new <i>controller-classN</i>());
73  * [ if (content == null) content = new <i>content-class</i>(); ]
74  * Component owner = null;
75  * Object impl = controllers.get(0);
76  * interfaces.put("component", owner = new <i>interface-class1</i>(..., impl));
77  * ...
78  * impl = controllers.get(<i>I</i>); // or impl = content;
79  * [ impl = new <i>interceptor-classM</i>(impl); ]
80  * [ controllers.add(impl); ]
81  * interfaces.put("...", new <i>interface-classM</i>(..., impl));
82  * [ internalInterfaces.put("...", new <i>interface-classM</i>(..., impl)); ]
83  * return;
84  * }
85  *
86  * public String getFcGeneratorParameters() {
87  * return "(... ...)";
88  * }
89  * }
90  * </pre>
91  */

92
93 public class ContextClassGenerator implements Constants, ClassGenerator {
94
95   /**
96    * Internal name of the super class of the classes generated by this
97    * generator.
98    */

99
100   private final static String JavaDoc SUPER =
101     "org/objectweb/fractal/julia/InitializationContext";
102
103   /**
104    * The valid optimization levels.
105    */

106
107   private final static String JavaDoc[] OPTIMIZATIONS = {
108     "none",
109     "mergeControllers",
110     "mergeControllersAndInterceptors",
111     "mergeControllersAndContent",
112     "mergeControllersInterceptorsAndContent"
113   };
114
115   /**
116    * Internal name of the class generated by this generator.
117    */

118
119   private String JavaDoc name;
120
121   /**
122    * The class visitor used to generate the class.
123    */

124
125   private ClassVisitor cv;
126
127   /**
128    * The descriptor of the class that is being generated.
129    */

130
131   private Tree args;
132
133   /**
134    * The loader used to load auxiliary classes.
135    */

136
137   private Loader loader;
138
139   private ClassLoader JavaDoc classLoader;
140   
141   /**
142    * The types of the functional and control interfaces of the components that
143    * will be created by the generated class.
144    */

145
146   private Tree interfaceTypes;
147
148   /**
149    * The names of the classes of the controller objects of the components that
150    * will be created by the generated class.
151    */

152
153   private Tree[] controllerTrees;
154
155   /**
156    * The classes of the controller objects of the components that will be
157    * created by the generated class.
158    */

159
160   private List JavaDoc controllerClasses;
161
162   /**
163    * The class of the content part of the components that will be created by the
164    * generated class.
165    */

166
167   private Class JavaDoc contentClass;
168
169   /**
170    * Generates the class whose descriptor is given, with the given name.
171    *
172    * @param name the name of the class to be generated.
173    * @param args the descriptor of the class to be generated. This
174    * descriptor <i>must</i> be of the form "(type-descriptor
175    * controller-descriptor content-descriptor)", where "type-descriptor"
176    * is of the form "((name signature isClient isOptional isCollection)
177    * ...)", "controller-descriptor" is of the form described in the Julia
178    * tutorial, and "content-descriptor" is a fully qualified class name or
179    * "EMPTY".
180    * @param loader the loader to be used to load or generate auxiliary classes,
181    * if needed.
182    * @param classLoader the class loader to be used to load auxiliary classes,
183    * if needed.
184    * @return a class named <tt>name</tt> and whose content is described by the
185    * given class descriptor.
186    * @throws ClassGenerationException if a problem occurs during the generation
187    * of the class.
188    */

189
190   public byte[] generateClass (
191     final String JavaDoc name,
192     final Tree args,
193     final Loader loader,
194     final ClassLoader JavaDoc classLoader) throws ClassGenerationException
195   {
196     this.name = name.replace('.', '/');
197     this.cv = new ClassWriter(true);
198     this.args = args;
199     this.loader = loader;
200     this.classLoader = classLoader;
201
202     // creates the class header
203
cv.visit(
204       V1_1,
205       ACC_PUBLIC,
206       this.name,
207       SUPER,
208       new String JavaDoc[] { "org/objectweb/fractal/julia/loader/Generated" },
209       null);
210
211     // generates the "componentType" static field
212
cv.visitField(
213       ACC_PRIVATE + ACC_STATIC,
214       "componentType",
215       "Lorg/objectweb/fractal/api/type/ComponentType;",
216       null,
217       null);
218
219     // generates the "internalComponentType" static field
220
cv.visitField(
221       ACC_PRIVATE + ACC_STATIC,
222       "internalComponentType",
223       "Lorg/objectweb/fractal/api/type/ComponentType;",
224       null,
225       null);
226
227     // generates the default constructor
228
CodeVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
229     mv.visitVarInsn(ALOAD, 0);
230     mv.visitMethodInsn(INVOKESPECIAL, SUPER, "<init>", "()V");
231     mv.visitInsn(RETURN);
232     mv.visitMaxs(0, 0);
233
234     // generates the "create" method (see InitilizationContext)
235
mv = cv.visitMethod(ACC_PUBLIC, "create", "()V", null, null);
236     mv.visitVarInsn(ALOAD, 0);
237     mv.visitMethodInsn(INVOKESPECIAL, SUPER, "create", "()V");
238     computeInterfaceTypes();
239     generateCreateType(mv);
240     generateCreateControllers(mv);
241     generateCreateContent(mv);
242     generateCreateInterfaces(mv);
243     mv.visitInsn(RETURN);
244     mv.visitMaxs(0, 0);
245
246     // generates the 'getFcGeneratorParameters' method
247
String JavaDoc mName = "getFcGeneratorParameters";
248     String JavaDoc mDesc = "()Ljava/lang/String;";
249     mv = cv.visitMethod(ACC_PUBLIC, mName, mDesc, null, null);
250     mv.visitLdcInsn(args.toString());
251     mv.visitInsn(ARETURN);
252     mv.visitMaxs(0, 0);
253
254     // returns the generated class
255
return ((ClassWriter)cv).toByteArray();
256   }
257
258   /**
259    * Computes all the interface types of the component. This method merges the
260    * control interface type descriptors and the functional interface type
261    * descriptors into a single descriptor "interfaceTypes"
262    */

263
264   public void computeInterfaceTypes () {
265     Tree[] functionalItfs = args.getSubTree(1).getSubTrees();
266     Tree[] controlItfs = args.getSubTree(2).getSubTree(1).getSubTrees();
267     Tree[] allItfs = new Tree[functionalItfs.length + controlItfs.length];
268     for (int i = 0; i < controlItfs.length; ++i) {
269       allItfs[i] = new Tree(new Tree[] {
270         controlItfs[i].getSubTree(0),
271         controlItfs[i].getSubTree(1),
272         new Tree("false"),
273         new Tree("false"),
274         new Tree("false")
275       });
276     }
277     for (int i = 0; i < functionalItfs.length; ++i) {
278       allItfs[i + controlItfs.length] = functionalItfs[i];
279     }
280     interfaceTypes = new Tree(allItfs);
281   }
282
283   /**
284    * Generates the code to initialize the "componentType" and
285    * "internalComponentType" static fields of the generated class.
286    *
287    * @param mv the code visitor to be used to generate the code.
288    */

289
290   public void generateCreateType (final CodeVisitor mv) {
291     // generates "if (componentType == null) {"
292
Label l = new Label();
293     mv.visitFieldInsn(
294       GETSTATIC,
295       name,
296       "componentType",
297       "Lorg/objectweb/fractal/api/type/ComponentType;");
298     mv.visitJumpInsn(IFNONNULL, l);
299
300     // generates "TypeFactory tf = (TypeFactory)hints;"
301
mv.visitVarInsn(ALOAD, 0);
302     mv.visitFieldInsn(GETFIELD, name, "hints", "Ljava/lang/Object;");
303     mv.visitTypeInsn(CHECKCAST, "org/objectweb/fractal/api/type/TypeFactory");
304     mv.visitVarInsn(ASTORE, 1);
305
306     // EXTERNAL COMPONENT TYPE
307

308     // computes the number of external public interfaces
309
int externalItfs = interfaceTypes.getSize();
310     for (int i = 0; i < interfaceTypes.getSize(); ++i) {
311       Tree itf = interfaceTypes.getSubTree(i);
312       if (itf.getSubTree(0).toString().startsWith("/")) {
313         --externalItfs;
314       }
315     }
316
317     // generates "new InterfaceType[...] {"
318
mv.visitVarInsn(ALOAD, 1);
319     mv.visitIntInsn(SIPUSH, externalItfs);
320     mv.visitTypeInsn(ANEWARRAY, "org/objectweb/fractal/api/type/InterfaceType");
321
322     int j = 0;
323     for (int i = 0; i < interfaceTypes.getSize(); ++i) {
324       Tree itf = interfaceTypes.getSubTree(i);
325       if (itf.getSubTree(0).toString().startsWith("/")) {
326         continue;
327       }
328       // generates "tf.createFcItfType(...);"
329
mv.visitInsn(DUP);
330       mv.visitIntInsn(SIPUSH, j++);
331       mv.visitVarInsn(ALOAD, 1);
332       mv.visitLdcInsn(itf.getSubTree(0).toString());
333       mv.visitLdcInsn(itf.getSubTree(1).toString());
334       mv.visitInsn(itf.getSubTree(2).equals("true") ? ICONST_1 : ICONST_0);
335       mv.visitInsn(itf.getSubTree(3).equals("true") ? ICONST_1 : ICONST_0);
336       mv.visitInsn(itf.getSubTree(4).equals("true") ? ICONST_1 : ICONST_0);
337       mv.visitMethodInsn(
338         INVOKEINTERFACE,
339         "org/objectweb/fractal/api/type/TypeFactory",
340         "createFcItfType",
341         "(Ljava/lang/String;Ljava/lang/String;ZZZ)" +
342         "Lorg/objectweb/fractal/api/type/InterfaceType;");
343       mv.visitInsn(AASTORE);
344     }
345
346     // generates "componentType = tf.createFcType(...);"
347
mv.visitMethodInsn(
348       INVOKEINTERFACE,
349       "org/objectweb/fractal/api/type/TypeFactory",
350       "createFcType",
351       "([Lorg/objectweb/fractal/api/type/InterfaceType;)" +
352       "Lorg/objectweb/fractal/api/type/ComponentType;");
353     mv.visitFieldInsn(
354       PUTSTATIC,
355       name,
356       "componentType",
357       "Lorg/objectweb/fractal/api/type/ComponentType;");
358
359     // INTERNAL COMPONENT TYPE
360

361     // computes the number of internal public interfaces
362
int internalIfts = interfaceTypes.getSize();
363     for (int i = 0; i < interfaceTypes.getSize(); ++i) {
364       Tree itf = interfaceTypes.getSubTree(i);
365       String JavaDoc name = itf.getSubTree(0).toString();
366       if (name.startsWith("/") ||
367           name.equals("component") ||
368           name.endsWith("-controller"))
369       {
370         --internalIfts;
371       }
372     }
373
374     // generates "new InterfaceType[...] {"
375
mv.visitVarInsn(ALOAD, 1);
376     mv.visitIntInsn(SIPUSH, internalIfts);
377     mv.visitTypeInsn(ANEWARRAY, "org/objectweb/fractal/api/type/InterfaceType");
378
379     j = 0;
380     for (int i = 0; i < interfaceTypes.getSize(); ++i) {
381       Tree itf = interfaceTypes.getSubTree(i);
382       String JavaDoc name = itf.getSubTree(0).toString();
383       if (name.startsWith("/") ||
384           name.equals("component") ||
385           name.endsWith("-controller"))
386       {
387         continue;
388       }
389       // generates "tf.createFcItfType(...);"
390
mv.visitInsn(DUP);
391       mv.visitIntInsn(SIPUSH, j++);
392       mv.visitVarInsn(ALOAD, 1);
393       mv.visitLdcInsn(itf.getSubTree(0).toString());
394       mv.visitLdcInsn(itf.getSubTree(1).toString());
395       mv.visitInsn(itf.getSubTree(2).equals("true") ? ICONST_0 : ICONST_1);
396       mv.visitInsn(itf.getSubTree(3).equals("true") ? ICONST_1 : ICONST_0);
397       mv.visitInsn(itf.getSubTree(4).equals("true") ? ICONST_1 : ICONST_0);
398       mv.visitMethodInsn(
399         INVOKEINTERFACE,
400         "org/objectweb/fractal/api/type/TypeFactory",
401         "createFcItfType",
402         "(Ljava/lang/String;Ljava/lang/String;ZZZ)" +
403         "Lorg/objectweb/fractal/api/type/InterfaceType;");
404       mv.visitInsn(AASTORE);
405     }
406
407     // generates "internalComponentType = tf.createFcType(...);"
408
mv.visitMethodInsn(
409       INVOKEINTERFACE,
410       "org/objectweb/fractal/api/type/TypeFactory",
411       "createFcType",
412       "([Lorg/objectweb/fractal/api/type/InterfaceType;)" +
413       "Lorg/objectweb/fractal/api/type/ComponentType;");
414     mv.visitFieldInsn(
415       PUTSTATIC,
416       name,
417       "internalComponentType",
418       "Lorg/objectweb/fractal/api/type/ComponentType;");
419
420     // generates "}" (end of "if (componentType == null)" statement)
421
mv.visitLabel(l);
422
423     // generates "type = componentType;"
424
mv.visitVarInsn(ALOAD, 0);
425     mv.visitFieldInsn(
426       GETSTATIC,
427       name,
428       "componentType",
429       "Lorg/objectweb/fractal/api/type/ComponentType;");
430     mv.visitFieldInsn(
431       PUTFIELD,
432       name,
433       "type",
434       "Lorg/objectweb/fractal/api/Type;");
435
436     // generates "ComponentType compType = componentType;"
437
mv.visitFieldInsn(
438       GETSTATIC,
439       name,
440       "componentType",
441       "Lorg/objectweb/fractal/api/type/ComponentType;");
442     mv.visitVarInsn(ASTORE, 2);
443   }
444
445   /**
446    * Generates the code to create the component's controller objects.
447    *
448    * @param mv the code visitor to be used to generate the code.
449    * @throws ClassGenerationException if a problem occurs
450    */

451
452   public void generateCreateControllers (final CodeVisitor mv)
453     throws ClassGenerationException
454   {
455     // creates a context to evaluate the controller descriptors
456
Map JavaDoc context = new HashMap JavaDoc();
457     for (int i = 0; i < interfaceTypes.getSize(); ++i) {
458       String JavaDoc itfName = interfaceTypes.getSubTree(i).getSubTree(0).toString();
459       if (itfName.equals("attribute-controller")) {
460         Tree itfSignature = interfaceTypes.getSubTree(i).getSubTree(1);
461         context.put("attributeControllerInterface", itfSignature);
462         break;
463       }
464     }
465
466     // evaluates the controller descriptors
467
Tree[] controllerDescs;
468     Tree[] controllerArgs;
469     try {
470       Tree t = args.getSubTree(2).getSubTree(2);
471       controllerDescs = loader.evalTree(t, context).getSubTrees();
472       controllerArgs = new Tree[controllerDescs.length];
473       for (int i = 0; i < controllerDescs.length; i++) {
474         Tree controllerDesc = controllerDescs[i];
475         if (controllerDesc.getSize() > 0) {
476           controllerDescs[i] = controllerDesc.getSubTree(0);
477           if (controllerDesc.getSize() > 1) {
478             Tree[] trees = controllerDesc.getSubTrees();
479             Tree[] args = new Tree[trees.length - 1];
480             System.arraycopy(trees, 1, args, 0, args.length);
481             controllerArgs[i] = new Tree(args);
482           }
483         }
484       }
485     } catch (Exception JavaDoc e) {
486       throw new ClassGenerationException(
487         e,
488         args.toString(),
489         "Cannot find or evaluate the controller class descriptors");
490     }
491
492     // checks the optimization level
493
String JavaDoc optimize = args.getSubTree(2).getSubTree(5).toString();
494     if (!Arrays.asList(OPTIMIZATIONS).contains(optimize)) {
495       throw new ClassGenerationException(
496         null, args.toString(), "Invalid optimization level: " + optimize);
497     }
498
499     controllerClasses = new ArrayList JavaDoc();
500     if (optimize.indexOf("Controllers") != -1) {
501       // computes the class descriptor of the merged controller class
502
Tree[] mergeClassDesc = new Tree[controllerDescs.length + 2];
503       // name of the "merge class generator" class
504
mergeClassDesc[0] = args.getSubTree(2).getSubTree(4);
505       // super to be used for the merged class
506
mergeClassDesc[1] = new Tree("java.lang.Object");
507
508       String JavaDoc content = args.getSubTree(3).toString();
509       if (optimize.indexOf("Content") != -1 && !content.equals("EMPTY")) {
510         try {
511           contentClass = loader.loadClass(content, classLoader);
512         } catch (ClassNotFoundException JavaDoc e) {
513           throw new ClassGenerationException(
514             e, args.toString(), "Cannot find the '" + content + "' class");
515         }
516         mergeClassDesc[1] = new Tree(content);
517       }
518       // classes to be merged
519
for (int i = 0; i < controllerDescs.length; ++i) {
520         Tree controllerDesc = controllerDescs[i];
521         try {
522           Class JavaDoc c = loader.loadClass(controllerDesc, classLoader);
523           mergeClassDesc[i + 2] = new Tree(c.getName());
524         } catch (ClassNotFoundException JavaDoc e) {
525           throw new ClassGenerationException(
526             e,
527             args.toString(),
528             "Cannot find or generate the '" + controllerDesc +
529             "' controller class");
530         }
531       }
532
533       // loads the merged controller class
534
Class JavaDoc mergedClass;
535       String JavaDoc mergedClassName;
536       try {
537         mergedClass = loader.loadClass(new Tree(mergeClassDesc), classLoader);
538         mergedClassName = Type.getInternalName(mergedClass);
539       } catch (ClassNotFoundException JavaDoc e) {
540         throw new ClassGenerationException(
541           e,
542           args.toString(),
543           "Cannot find or generate the merged controller class");
544       }
545
546       Tree interceptors = args.getSubTree(2).getSubTree(3);
547       if (optimize.indexOf("Interceptors") > 0 && interceptors.getSize() > 0) {
548         // generates a sub class of mergedClass
549
// with the interceptor class generator
550

551         // computes the arguments for the merged interceptor class generator
552
List JavaDoc itfList = new ArrayList JavaDoc();
553         List JavaDoc itfNameList = new ArrayList JavaDoc();
554         for (int i = 0; i < interfaceTypes.getSize(); ++i) {
555           Tree itfType = interfaceTypes.getSubTree(i);
556           String JavaDoc itfName = itfType.getSubTree(0).toString();
557           String JavaDoc itfSignature = itfType.getSubTree(1).toString();
558           boolean isClient = itfType.getSubTree(2).equals("true");
559           boolean isControl =
560             itfName.startsWith("/") ||
561             itfName.equals("component") ||
562             itfName.endsWith("-controller");
563           if (!isClient && !isControl && !itfList.contains(itfSignature)) {
564             itfList.add(itfSignature);
565             itfNameList.add(new Tree(itfName));
566           }
567         }
568         for (int i = 0; i < itfList.size(); ++i) {
569           itfList.set(i, new Tree((String JavaDoc)itfList.get(i)));
570         }
571         Tree[] itfTrees =
572           (Tree[])itfList.toArray(new Tree[itfList.size()]);
573         Tree[] itfNameTrees =
574           (Tree[])itfNameList.toArray(new Tree[itfNameList.size()]);
575
576         // computes the merged interceptor class generator descriptor
577
Map JavaDoc itfCtxt = new HashMap JavaDoc();
578         itfCtxt.put("interfaceName", new Tree(itfNameTrees));
579         Tree classGen;
580         try {
581           classGen = loader.evalTree(interceptors.getSubTree(0), itfCtxt);
582         } catch (Exception JavaDoc e) {
583           throw new ClassGenerationException(
584             e,
585             args.toString(),
586             "Cannot get the merged interceptor class generator descriptor");
587         }
588
589         // loads the merged interceptor class, sub class of 'mergeClass'
590
try {
591           mergedClass = loader.loadClass(new Tree(new Tree[] {
592             classGen,
593             new Tree(mergedClass.getName()),
594             new Tree(itfTrees),
595             new Tree(new Tree[0]),
596             new Tree("in")
597           }), classLoader);
598           mergedClassName = Type.getInternalName(mergedClass);
599         } catch (ClassNotFoundException JavaDoc e) {
600           throw new ClassGenerationException(
601             e,
602             args.toString(),
603             "Cannot find or generate the merged interceptor class");
604         }
605       }
606
607       controllerClasses.add(mergedClass);
608
609       // generates "new <merged controller class>()"
610
mv.visitVarInsn(ALOAD, 0);
611       mv.visitFieldInsn(GETFIELD, name, "controllers", "Ljava/util/List;");
612       mv.visitTypeInsn(NEW, mergedClassName);
613       mv.visitInsn(DUP);
614       mv.visitMethodInsn(INVOKESPECIAL, mergedClassName, "<init>", "()V");
615       // generates the code to initialize the merged controller object
616
mv.visitInsn(DUP);
617       mv.visitTypeInsn(
618         CHECKCAST,
619         "org/objectweb/fractal/julia/loader/Initializable");
620       generateCreateTreeCode(mv, new Tree(controllerArgs));
621       mv.visitMethodInsn(
622         INVOKEINTERFACE,
623         "org/objectweb/fractal/julia/loader/Initializable",
624         "initialize",
625         "(Lorg/objectweb/fractal/julia/loader/Tree;)V");
626       // generates "controllers.add(...);"
627
mv.visitMethodInsn(
628         INVOKEINTERFACE,
629         "java/util/List",
630         "add",
631         "(Ljava/lang/Object;)Z");
632       mv.visitInsn(POP);
633
634       if (optimize.indexOf("Content") != -1 && !content.equals("EMPTY")) {
635         // generates "content = controllers.get(0);"
636
mv.visitVarInsn(ALOAD, 0);
637         mv.visitVarInsn(ALOAD, 0);
638         mv.visitFieldInsn(GETFIELD, name, "controllers", "Ljava/util/List;");
639         mv.visitInsn(ICONST_0);
640         mv.visitMethodInsn(
641           INVOKEINTERFACE,
642           "java/util/List",
643           "get",
644           "(I)Ljava/lang/Object;");
645         mv.visitFieldInsn(PUTFIELD, name, "content", "Ljava/lang/Object;");
646       }
647     } else {
648       // generates the code to create each controller object separately
649
for (int i = 0; i < controllerDescs.length; ++i) {
650         Tree controllerDesc = controllerDescs[i];
651         Class JavaDoc c;
652         String JavaDoc n;
653         try {
654           c = loader.loadClass(controllerDesc, classLoader);
655           n = c.getName().replace('.', '/');
656           controllerClasses.add(c);
657         } catch (ClassNotFoundException JavaDoc e) {
658           throw new ClassGenerationException(
659             e,
660             args.toString(),
661             "Cannot find or generate the '" + controllerDesc +
662             "' controller class");
663         }
664         // generates "new <controller class>()"
665
mv.visitVarInsn(ALOAD, 0);
666         mv.visitFieldInsn(GETFIELD, name, "controllers", "Ljava/util/List;");
667         mv.visitTypeInsn(NEW, n);
668         mv.visitInsn(DUP);
669         mv.visitMethodInsn(INVOKESPECIAL, n, "<init>", "()V");
670         if (controllerArgs[i] != null) {
671           // generates the code to initialize the controller object
672
mv.visitInsn(DUP);
673           mv.visitTypeInsn(
674             CHECKCAST,
675             "org/objectweb/fractal/julia/loader/Initializable");
676           generateCreateTreeCode(mv, controllerArgs[i]);
677           mv.visitMethodInsn(
678             INVOKEINTERFACE,
679             "org/objectweb/fractal/julia/loader/Initializable",
680             "initialize",
681             "(Lorg/objectweb/fractal/julia/loader/Tree;)V");
682         }
683         // generates "controllers.add(...);"
684
mv.visitMethodInsn(
685           INVOKEINTERFACE,
686           "java/util/List",
687           "add",
688           "(Ljava/lang/Object;)Z");
689         mv.visitInsn(POP);
690       }
691     }
692
693     // stores the names of the 'controllerClasses' classes in 'controllerTrees'
694
controllerTrees = new Tree[controllerClasses.size()];
695     for (int l = 0; l < controllerTrees.length; ++l) {
696       controllerTrees[l] = new Tree(((Class JavaDoc)controllerClasses.get(l)).getName());
697     }
698   }
699
700   /**
701    * Generates the code to create the given tree.
702    *
703    * @param mv the code visitor to be used to generate the code.
704    * @param t a tree.
705    */

706
707   private void generateCreateTreeCode (final CodeVisitor mv, final Tree t) {
708     String JavaDoc tree = "org/objectweb/fractal/julia/loader/Tree";
709     if (t == null) {
710       mv.visitInsn(ACONST_NULL);
711     } else if (t.getSize() == 0) {
712       mv.visitTypeInsn(NEW, tree);
713       mv.visitInsn(DUP);
714       mv.visitLdcInsn(t.toString());
715       mv.visitMethodInsn(INVOKESPECIAL, tree, "<init>", "(Ljava/lang/String;)V");
716     } else {
717       mv.visitTypeInsn(NEW, tree);
718       mv.visitInsn(DUP);
719       mv.visitIntInsn(SIPUSH, t.getSize());
720       mv.visitTypeInsn(ANEWARRAY, tree);
721       for (int i = 0; i < t.getSize(); ++i) {
722         mv.visitInsn(DUP);
723         mv.visitIntInsn(SIPUSH, i);
724         generateCreateTreeCode(mv, t.getSubTree(i));
725         mv.visitInsn(AASTORE);
726       }
727       mv.visitMethodInsn(INVOKESPECIAL, tree, "<init>", "([L" + tree + ";)V");
728     }
729   }
730
731   /**
732    * Generates the code to create the component's content.
733    *
734    * @param mv the code visitor to be used to generate the code.
735    * @throws ClassGenerationException if the component's content class cannot be
736    * found.
737    */

738
739   public void generateCreateContent (final CodeVisitor mv)
740     throws ClassGenerationException
741   {
742     String JavaDoc content = args.getSubTree(3).toString();
743     if (content.equals("EMPTY")) {
744       return;
745     }
746
747     // 'contentClass' can have been initialized in generateCreateControllers
748
if (contentClass == null) {
749       try {
750         contentClass = loader.loadClass(content, classLoader);
751       } catch (ClassNotFoundException JavaDoc e) {
752         throw new ClassGenerationException(
753           e, args.toString(), "Cannot find the '" + content + "' class");
754       }
755       content = content.replace('.', '/');
756       // generates "content = new <content class>();"
757
Label end = new Label();
758       mv.visitVarInsn(ALOAD, 0);
759       mv.visitFieldInsn(GETFIELD, name, "content", "Ljava/lang/Object;");
760       mv.visitJumpInsn(IFNONNULL, end);
761       mv.visitVarInsn(ALOAD, 0);
762       mv.visitTypeInsn(NEW, content);
763       mv.visitInsn(DUP);
764       mv.visitMethodInsn(INVOKESPECIAL, content, "<init>", "()V");
765       mv.visitFieldInsn(PUTFIELD, name, "content", "Ljava/lang/Object;");
766       mv.visitLabel(end);
767     }
768
769     // generates "interfaces.put("/content", content);"
770
mv.visitVarInsn(ALOAD, 0);
771     mv.visitFieldInsn(GETFIELD, this.name, "interfaces", "Ljava/util/Map;");
772     mv.visitLdcInsn("/content");
773     mv.visitVarInsn(ALOAD, 0);
774     mv.visitFieldInsn(GETFIELD, name, "content", "Ljava/lang/Object;");
775     mv.visitMethodInsn(
776       INVOKEINTERFACE,
777       "java/util/Map",
778       "put",
779       "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
780     mv.visitInsn(POP);
781   }
782
783   /**
784    * Generates the code to create the component interfaces.
785    *
786    * @param mv the code visitor to be used to generate the code.
787    * @throws ClassGenerationException if a problem occurs.
788    */

789
790   public void generateCreateInterfaces (final CodeVisitor mv)
791     throws ClassGenerationException
792   {
793     String JavaDoc optimize = args.getSubTree(2).getSubTree(5).toString();
794     Tree interceptors = args.getSubTree(2).getSubTree(3);
795     boolean interceptorsMerged = optimize.indexOf("Interceptors") != -1;
796
797     Tree itfClassGen = args.getSubTree(2).getSubTree(0);
798     boolean hasItfClassGen = !itfClassGen.equals("NONE");
799
800     // generates "Component owner = null;"
801
mv.visitInsn(ACONST_NULL);
802     mv.visitVarInsn(ASTORE, 3);
803
804     for (int i = 0; i < interfaceTypes.getSize(); ++i) {
805       Tree itf = interfaceTypes.getSubTree(i);
806       String JavaDoc itfName = itf.getSubTree(0).toString();
807       String JavaDoc itfSignature = itf.getSubTree(1).toString();
808       boolean isClient = itf.getSubTree(2).toString().equals("true");
809       boolean isCollection = itf.getSubTree(4).toString().equals("true");
810       boolean isControl =
811         !isClient &&
812         (itfName.startsWith("/") ||
813          itfName.equals("component") ||
814          itfName.endsWith("-controller"));
815
816       // loads the functional interface
817
Class JavaDoc itfClass;
818       try {
819         itfClass = loader.loadClass(itfSignature, classLoader);
820       } catch (ClassNotFoundException JavaDoc e) {
821         throw new ClassGenerationException(
822           e, args.toString(), "Cannot find the '" + itfSignature + "' class");
823       }
824
825       // loads the corresponding ComponentInterface sub class
826
Class JavaDoc compItfClass;
827       String JavaDoc compItfClassName;
828       if (hasItfClassGen) {
829         try {
830           compItfClass = loader.loadClass(new Tree(new Tree[] {
831             itfClassGen,
832             new Tree(new Tree[] { new Tree(itfSignature) })
833           }), classLoader);
834           compItfClassName = compItfClass.getName().replace('.', '/');
835         } catch (ClassNotFoundException JavaDoc e) {
836           throw new ClassGenerationException(
837             e,
838             args.toString(),
839             "Cannot find or generate the ComponentInterface class for the '" +
840             itfSignature + "' class");
841         }
842       } else {
843         compItfClass = null;
844         compItfClassName = null;
845       }
846
847       // finds the ComponentInterace.getFcItfImpl object, and generates the
848
// corresponding "Object impl = ...;" code
849

850       if (isClient) {
851         // generates "Object impl = null;"
852
mv.visitInsn(ACONST_NULL);
853         mv.visitVarInsn(ASTORE, 4);
854       } else {
855         // looks for 'impl' in the controller objects, and in 'content'
856
int u = -1;
857         int v = -1;
858         int w;
859         for (int j = 0; j < controllerClasses.size(); ++j) {
860           if (itfClass.isAssignableFrom((Class JavaDoc)controllerClasses.get(j))) {
861             u = j + 1;
862             break;
863           }
864         }
865         if (contentClass != null && itfClass.isAssignableFrom(contentClass)) {
866           v = 0;
867         }
868         if (isControl || interceptorsMerged) {
869           w = u != -1 ? u : v;
870         } else {
871           w = v != -1 ? v : u;
872         }
873         if (w == -1 && isControl) {
874           throw new ClassGenerationException(
875             null,
876             args.toString(),
877             "Implementation missing for control interface " +
878             itfName + " of type " + itfSignature);
879         }
880
881         // generates the code to store the object that has been found in 'impl'
882
if (w != -1) {
883           if (w == 0) {
884             // generates "Object impl = null;"
885
mv.visitVarInsn(ALOAD, 0);
886             mv.visitFieldInsn(GETFIELD, name, "content", "Ljava/lang/Object;");
887           } else {
888             // generates "Object impl = controllers.get(<index>);"
889
mv.visitVarInsn(ALOAD, 0);
890             mv.visitFieldInsn(GETFIELD, name, "controllers", "Ljava/util/List;");
891             mv.visitIntInsn(SIPUSH, w - 1);
892             mv.visitMethodInsn(
893               INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");
894           }
895         } else {
896           // generates "Object impl = null;"
897
mv.visitInsn(ACONST_NULL);
898         }
899         mv.visitVarInsn(ASTORE, 4);
900       }
901
902       // if there are interceptors,
903
// generates "impl = new <interceptor class>(impl);"
904
// "controllers.add(impl);"
905

906       if (!isControl &&
907           interceptors.getSize() > 0 &&
908           (isClient || !interceptorsMerged))
909       {
910         // if the input interceptors have been merged to the controller
911
// class, and if the interface is a server interface, we must not
912
// create a redundant interceptor for it. Hence the last condition.
913

914         // loads the interceptor class
915
Class JavaDoc ic;
916         try {
917           // computes the interceptor's super class
918
// TODO remove these hardcoded class names -> move them to julia.cfg
919
String JavaDoc superClass;
920           if (isClient) {
921             superClass = "org.objectweb.fractal.julia.InterceptorInterface";
922           } else {
923             superClass = "java.lang.Object";
924           }
925
926           // creates a context to evaluate the interceptor class descriptor
927
Map JavaDoc itfCtxt = new HashMap JavaDoc();
928           itfCtxt.put(
929             "interfaceName",
930             new Tree(new Tree[] { new Tree(itfName) }));
931
932           // computes the interceptor class descriptor
933
Tree icDesc = new Tree(new Tree[] {
934             loader.evalTree(interceptors.getSubTree(0), itfCtxt),
935             new Tree(superClass),
936             new Tree(new Tree[] { new Tree(itfSignature) }),
937             new Tree(controllerTrees),
938             new Tree(isClient ? "out" : "in")
939           });
940
941           // loads the interceptor class
942
ic = loader.loadClass(icDesc, classLoader);
943         } catch (IllegalClassDescriptorException e) {
944           ic = null;
945         } catch (Exception JavaDoc e) {
946           throw new ClassGenerationException(
947             e,
948             args.toString(),
949             "Cannot find or generate the interceptor class for the '" +
950             itfSignature + "' interface");
951         }
952
953         if (ic != null) {
954           // name of the interceptor class
955
String JavaDoc icName = ic.getName().replace('.', '/');
956
957           // generates "impl = new <interceptor class>(impl);"
958
mv.visitTypeInsn(NEW, icName);
959           mv.visitInsn(DUP);
960           mv.visitVarInsn(ALOAD, 4);
961           mv.visitMethodInsn(
962             INVOKESPECIAL, icName, "<init>", "(Ljava/lang/Object;)V");
963           mv.visitVarInsn(ASTORE, 4);
964
965           // generates "controllers.add(impl);"
966
mv.visitVarInsn(ALOAD, 0);
967           mv.visitFieldInsn(GETFIELD, name, "controllers", "Ljava/util/List;");
968           mv.visitVarInsn(ALOAD, 4);
969           mv.visitMethodInsn(
970             INVOKEINTERFACE,
971             "java/util/List",
972             "add",
973             "(Ljava/lang/Object;)Z");
974           mv.visitInsn(POP);
975         }
976       }
977
978       // EXTERNAL INTERFACE
979

980       // begins generation of "interfaces.put(<itf name>, new ...);"
981
mv.visitVarInsn(ALOAD, 0);
982       mv.visitFieldInsn(GETFIELD, name, "interfaces", "Ljava/util/Map;");
983       mv.visitLdcInsn(isCollection ? "/collection/" + itfName : itfName);
984
985       if (hasItfClassGen) {
986         // generates "new <itf class name>(
987
// owner,
988
// <itf name>,
989
// componentType.getFcItfType(<itf name>), // or null
990
// false,
991
// impl)
992
mv.visitTypeInsn(NEW, compItfClassName);
993         mv.visitInsn(DUP);
994         mv.visitVarInsn(ALOAD, 3);
995         mv.visitLdcInsn(itfName);
996         if (itfName.startsWith("/")) {
997           mv.visitInsn(ACONST_NULL);
998         } else {
999           mv.visitVarInsn(ALOAD, 2);
1000          mv.visitLdcInsn(itfName);
1001          mv.visitMethodInsn(
1002            INVOKEINTERFACE,
1003            "org/objectweb/fractal/api/type/ComponentType",
1004            "getFcInterfaceType",
1005            "(Ljava/lang/String;)Lorg/objectweb/fractal/api/type/InterfaceType;");
1006        }
1007        mv.visitInsn(ICONST_0);
1008        mv.visitVarInsn(ALOAD, 4);
1009        mv.visitMethodInsn(
1010          INVOKESPECIAL,
1011          compItfClassName,
1012          "<init>",
1013          "(Lorg/objectweb/fractal/api/Component;Ljava/lang/String;" +
1014          "Lorg/objectweb/fractal/api/Type;ZLjava/lang/Object;)V");
1015      } else {
1016        // generates 'impl'
1017
mv.visitVarInsn(ALOAD, 4);
1018      }
1019
1020      if (itfName.equals("component")) {
1021        // generates "owner = <previously generated expression>"
1022
mv.visitInsn(DUP);
1023        mv.visitVarInsn(ASTORE, 3);
1024      }
1025
1026      // ends generation of "interfaces.put(<itf name>, new ...);"
1027
mv.visitMethodInsn(
1028        INVOKEINTERFACE,
1029        "java/util/Map",
1030        "put",
1031        "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1032      mv.visitInsn(POP);
1033
1034      // INTERNAL INTERFACE
1035

1036      if (isControl) {
1037        continue;
1038      }
1039
1040      // begins generation of "internalInterfaces.put(<itf name>, new ...);"
1041
mv.visitVarInsn(ALOAD, 0);
1042      mv.visitFieldInsn(GETFIELD, name, "internalInterfaces", "Ljava/util/Map;");
1043      mv.visitLdcInsn(isCollection ? "/collection/" + itfName : itfName);
1044
1045      if (hasItfClassGen) {
1046        // generates "new <itf class name>(
1047
// owner,
1048
// <itf name>,
1049
// internalComponentType.getFcItfType(<itf name>),
1050
// true,
1051
// impl)
1052
mv.visitTypeInsn(NEW, compItfClassName);
1053        mv.visitInsn(DUP);
1054        mv.visitVarInsn(ALOAD, 3);
1055        mv.visitLdcInsn(itfName);
1056        mv.visitFieldInsn(
1057          GETSTATIC,
1058          name,
1059          "internalComponentType",
1060          "Lorg/objectweb/fractal/api/type/ComponentType;");
1061        mv.visitLdcInsn(itfName);
1062        mv.visitMethodInsn(
1063          INVOKEINTERFACE,
1064          "org/objectweb/fractal/api/type/ComponentType",
1065          "getFcInterfaceType",
1066          "(Ljava/lang/String;)Lorg/objectweb/fractal/api/type/InterfaceType;");
1067        mv.visitInsn(ICONST_1);
1068        mv.visitVarInsn(ALOAD, 4);
1069        mv.visitMethodInsn(
1070          INVOKESPECIAL,
1071          compItfClassName,
1072          "<init>",
1073          "(Lorg/objectweb/fractal/api/Component;Ljava/lang/String;" +
1074          "Lorg/objectweb/fractal/api/Type;ZLjava/lang/Object;)V");
1075      } else {
1076        // generates 'impl'
1077
mv.visitVarInsn(ALOAD, 4);
1078      }
1079
1080      // ends generation of "internalInterfaces.put(<itf name>, new ...);"
1081
mv.visitMethodInsn(
1082        INVOKEINTERFACE,
1083        "java/util/Map",
1084        "put",
1085        "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1086      mv.visitInsn(POP);
1087    }
1088  }
1089}
1090
Popular Tags