KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > adl > components > ComponentLoader


1 /***
2  * Fractal ADL Parser
3  * Copyright (C) 2002-2004 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.adl.components;
25
26 import org.objectweb.asm.ClassWriter;
27 import org.objectweb.asm.Type;
28 import org.objectweb.fractal.adl.ADLException;
29 import org.objectweb.fractal.adl.AbstractNode;
30 import org.objectweb.fractal.adl.Definition;
31 import org.objectweb.fractal.adl.AbstractLoader;
32 import org.objectweb.fractal.adl.Node;
33 import org.objectweb.fractal.adl.NodeClassLoader;
34
35 import java.util.ArrayList JavaDoc;
36 import java.util.Arrays JavaDoc;
37 import java.util.HashSet JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.HashMap JavaDoc;
42 import java.util.Set JavaDoc;
43
44 /**
45  * A {@link org.objectweb.fractal.adl.Loader} to check {@link Component} nodes
46  * in definitions. This loader checks sub component names, loads the definitons
47  * referenced by the component nodes (and the "extends" attribute), and merges
48  * all these definitions into a single one (by following inheritance rules).
49  */

50
51 public class ComponentLoader
52   extends AbstractLoader implements ComponentLoaderAttributes
53 {
54
55   /**
56    * The names of the "name" attribute for each AST node type. This map
57    * associates the names of the "name" attribute, used to detect overriden
58    * elements, to each AST node type that has such an attribute.
59    */

60
61   private Map JavaDoc NAME_ATTRIBUTES;
62
63   /**
64    * The class loader used to merge AST node classes. This class merging is
65    * necessary when merging several ASTs with different sources (eg different
66    * DTDs).
67    */

68   
69   private MergeClassLoader mergeClassLoader;
70   
71   // -------------------------------------------------------------------------
72
// Constructor
73
// -------------------------------------------------------------------------
74

75   public ComponentLoader () {
76     NAME_ATTRIBUTES = new HashMap JavaDoc();
77     NAME_ATTRIBUTES.put("component", "name");
78     NAME_ATTRIBUTES.put("interface", "name");
79     NAME_ATTRIBUTES.put("binding", "from");
80     NAME_ATTRIBUTES.put("attribute", "name");
81     NAME_ATTRIBUTES.put("coordinates", "name");
82     mergeClassLoader = new MergeClassLoader(getClass().getClassLoader());
83   }
84
85   // -------------------------------------------------------------------------
86
// Implementation of the ComponentLoaderAttributes interface
87
// -------------------------------------------------------------------------
88

89   public String JavaDoc getNameAttributes () {
90     StringBuffer JavaDoc b = new StringBuffer JavaDoc();
91     Iterator JavaDoc i = NAME_ATTRIBUTES.entrySet().iterator();
92     while (i.hasNext()) {
93       Map.Entry JavaDoc e = (Map.Entry JavaDoc)i.next();
94       b.append((String JavaDoc)e.getKey());
95       b.append(' ');
96       b.append((String JavaDoc)e.getValue());
97       b.append(' ');
98     }
99     return b.toString();
100   }
101   
102   public void setNameAttributes (String JavaDoc nameAttributes) {
103     NAME_ATTRIBUTES.clear();
104     String JavaDoc key = null;
105     int p = nameAttributes.indexOf(' ');
106     while (p != -1) {
107       String JavaDoc s = nameAttributes.substring(0, p);
108       if (key == null) {
109         key = s;
110       } else {
111         NAME_ATTRIBUTES.put(key, s);
112         key = null;
113       }
114       nameAttributes = nameAttributes.substring(p + 1);
115       p = nameAttributes.indexOf(' ');
116     }
117   }
118   
119   // -------------------------------------------------------------------------
120
// Implementation of the Loader interface
121
// -------------------------------------------------------------------------
122

123   public Definition load (final String JavaDoc name, final Map JavaDoc context)
124     throws ADLException
125   {
126     return load(new ArrayList JavaDoc(), name, context);
127   }
128   
129   public Definition load (
130     final List JavaDoc loaded,
131     final String JavaDoc name,
132     final Map JavaDoc context) throws ADLException
133   {
134     if (loaded.contains(name)) {
135       throw new ADLException("Cycle in definition references: " + loaded, null);
136     }
137     List JavaDoc l = new ArrayList JavaDoc(loaded);
138     l.add(name);
139     Definition d = clientLoader.load(name, context);
140     if (d instanceof ComponentDefinition) {
141       ComponentDefinition container = (ComponentDefinition)d;
142       normalizeComponentContainer(container);
143       if (container.getExtends() != null) {
144         List JavaDoc defs = parseDefinitions(container.getExtends());
145         try {
146           d = (Definition)merge((Node)d, (Node)resolveDefinitions(l, defs, context));
147         } catch (ADLException e) {
148           throw new ADLException(
149             "Cannot load super definition(s)", (Node)container, e);
150         }
151         container = (ComponentDefinition)d;
152         container.setExtends(null);
153       }
154       resolveComponentContainer(l, container, container, context);
155     }
156     return d;
157   }
158
159   // -------------------------------------------------------------------------
160
// First pass: normalization
161
// -------------------------------------------------------------------------
162

163   public void normalizeComponentContainer (final ComponentContainer container)
164     throws ADLException
165   {
166     Set JavaDoc names = new HashSet JavaDoc();
167     Component[] comps = container.getComponents();
168     for (int i = 0; i < comps.length; i++) {
169       Component comp = comps[i];
170       String JavaDoc name = comp.getName();
171       if (name == null) {
172         throw new ADLException("Component name missing", (Node)comp);
173       }
174       if (names.contains(name)) {
175         throw new ADLException(
176           "Duplicated component name '" + name + "'", (Node)comp);
177       } else {
178         names.add(name);
179       }
180       normalizeComponentContainer(comp);
181       /*if (name.indexOf('/') != -1) {
182         container.removeComponent(comp);
183         addComponent(container, comp);
184       }*/

185     }
186   }
187   
188   // this feature has been removed
189

190   /*public void addComponent (
191     final ComponentContainer container, Component comp) throws ADLException
192   {
193     String name = comp.getName();
194     int p = name.indexOf('/');
195     if (p == -1) {
196       Component c = getComponent(container, name);
197       if (c != null) {
198         replaceComponent(container, c, (Component)merge((Node)comp, (Node)c));
199       } else {
200         container.addComponent(comp);
201       }
202     } else {
203       Component parent = getComponent(container, name.substring(0, p));
204       if (parent == null) {
205         try {
206           parent = (Component)comp.getClass().newInstance();
207         } catch (InstantiationException e) {
208           throw new Error("Internal error");
209         } catch (IllegalAccessException e) {
210           throw new Error("Internal error");
211         }
212         parent.setName(name.substring(0, p));
213         container.addComponent(parent);
214       }
215       comp.setName(name.substring(p + 1));
216       addComponent(parent, comp);
217     }
218   }*/

219
220   // -------------------------------------------------------------------------
221
// Second pass: definition references resolution
222
// -------------------------------------------------------------------------
223

224   public void resolveComponentContainer (
225     final List JavaDoc loaded,
226     final ComponentContainer topLevelDefinition,
227     final ComponentContainer container,
228     final Map JavaDoc context) throws ADLException
229   {
230     Component[] comps = container.getComponents();
231     for (int i = 0; i < comps.length; i++) {
232       Component comp = comps[i];
233       resolveComponentContainer(loaded, topLevelDefinition, comp, context);
234       String JavaDoc definition = comp.getDefinition();
235       comp.setDefinition(null);
236       ((Node)comp).astSetDecoration("definition", definition);
237       if (definition != null) {
238         List JavaDoc defs = parseDefinitions(definition);
239         if (defs.size() == 1 && isShared((String JavaDoc)defs.get(0))) {
240           // shared component
241
if (definition.startsWith("./")) {
242             definition = definition.substring(2);
243           }
244           Component c = getPathComponent(topLevelDefinition, definition);
245           if (c == null) {
246             throw new ADLException(
247               "No such component", (Node)comp);
248           }
249           if (!c.getName().equals(comps[i].getName())) {
250             throw new ADLException(
251               "Shared components with distinct names not yet supported", (Node)comp);
252           }
253           Map JavaDoc replacements = new HashMap JavaDoc();
254           replacements.put(comp, c);
255           replaceComponents(topLevelDefinition, replacements);
256         } else {
257           Definition d;
258           try {
259             d = resolveDefinitions(loaded, defs, context);
260           } catch (ADLException e) {
261             throw new ADLException(
262               "Cannot load referenced definition(s)", (Node)comp, e);
263           }
264           Map JavaDoc replacements = new HashMap JavaDoc();
265           merge((Node)comp, (Node)d, replacements);
266           replaceComponents(topLevelDefinition, replacements);
267         }
268       }
269     }
270   }
271
272   public List JavaDoc parseDefinitions (String JavaDoc nameList) {
273     List JavaDoc l = new ArrayList JavaDoc();
274     int p = nameList.indexOf(',');
275     while (p != -1) {
276       l.add(nameList.substring(0, p));
277       nameList = nameList.substring(p+1);
278       p = nameList.indexOf(',');
279     }
280     l.add(nameList);
281     return l;
282   }
283   
284   public boolean isShared (String JavaDoc definition) {
285     return definition.indexOf('/') != -1;
286   }
287
288   public Definition resolveDefinitions (
289     final List JavaDoc loaded,
290     final List JavaDoc nameList,
291     final Map JavaDoc context) throws ADLException
292   {
293     Definition d = load(loaded, (String JavaDoc)nameList.get(0), context);
294     for (int i = 1; i < nameList.size(); ++i) {
295       Definition e = load(loaded, (String JavaDoc)nameList.get(i), context);
296       d = (Definition)merge((Node)e, (Node)d);
297     }
298     return d;
299   }
300
301   public Component getComponent (
302     final ComponentContainer container,
303     final String JavaDoc name)
304   {
305     Component[] comps = container.getComponents();
306     for (int i = 0; i < comps.length; i++) {
307       Component comp = comps[i];
308       if (comp.getName().equals(name)) {
309         return comp;
310       }
311     }
312     return null;
313   }
314
315   public Component getPathComponent (
316     final ComponentContainer container,
317     final String JavaDoc name)
318   {
319     int p = name.indexOf('/');
320     if (p == -1) {
321       return getComponent(container, name);
322     } else {
323       Component parent = getComponent(container, name.substring(0, p));
324       return getPathComponent(parent, name.substring(p + 1));
325     }
326   }
327
328   public ComponentContainer replaceComponents (
329     final ComponentContainer container,
330     final Map JavaDoc replacements)
331   {
332     if (replacements.get(container) != null) {
333       return (ComponentContainer)replacements.get(container);
334     }
335     Component[] comps = container.getComponents();
336     for (int i = 0; i < comps.length; i++) {
337       container.removeComponent(comps[i]);
338     }
339     for (int i = 0; i < comps.length; i++) {
340       container.addComponent(
341         (Component)replaceComponents(comps[i], replacements));
342     }
343     return container;
344   }
345
346   // -------------------------------------------------------------------------
347
// Utility methods: inheritance resolution
348
// -------------------------------------------------------------------------
349

350   public Node merge (final Node elem, final Node superElem) throws ADLException {
351     return merge(elem, superElem, null);
352   }
353       
354   public Node merge (
355     final Node elem,
356     final Node superElem,
357     final Map JavaDoc replacements) throws ADLException
358   {
359     Map JavaDoc infos = new HashMap JavaDoc();
360     computeMergeInfos(elem, superElem, infos);
361     createMergedNodes(infos);
362     Node n = initMergedNodes((MergeInfo)infos.get(elem), infos);
363     if (replacements != null) {
364       Iterator JavaDoc i = infos.entrySet().iterator();
365       while (i.hasNext()) {
366         Map.Entry JavaDoc e = (Map.Entry JavaDoc)i.next();
367         replacements.put(e.getKey(), ((MergeInfo)e.getValue()).result);
368       }
369     }
370     return n;
371   }
372
373   private void computeMergeInfos (
374     final Node elem,
375     final Node superElem,
376     final Map JavaDoc infos) throws ADLException
377   {
378     MergeInfo info = (MergeInfo)infos.get(elem);
379     if (info == null) {
380       info = new MergeInfo();
381       info.nodes.add(elem);
382       infos.put(elem, info);
383     }
384     if (info.nodes.contains(superElem)) {
385       return;
386     } else {
387       info.nodes.add(superElem);
388       infos.put(superElem, info);
389     }
390     
391     Set JavaDoc nodeTypes = new HashSet JavaDoc();
392     nodeTypes.addAll(Arrays.asList(elem.astGetNodeTypes()));
393     nodeTypes.addAll(Arrays.asList(superElem.astGetNodeTypes()));
394     
395     Iterator JavaDoc i = nodeTypes.iterator();
396     while (i.hasNext()) {
397       String JavaDoc nodeType = (String JavaDoc)i.next();
398       Node[] superNodes = superElem.astGetNodes(nodeType);
399       Node[] nodes = elem.astGetNodes(nodeType);
400       if (superNodes == null) {
401         superNodes = new Node[0];
402       }
403       if (nodes == null) {
404         nodes = new Node[0];
405       }
406       
407       String JavaDoc nameAttr = (String JavaDoc)NAME_ATTRIBUTES.get(nodeType);
408
409       if (nameAttr == null) {
410         if (superNodes.length > 0 && superNodes[0] != null) {
411           if (nodes.length == 0 || nodes[0] == null) {
412             computeMergeInfos(superNodes[0], infos);
413           } else {
414             computeMergeInfos(nodes[0], superNodes[0], infos);
415           }
416         } else {
417           if (nodes.length > 0 && nodes[0] != null) {
418             computeMergeInfos(nodes[0], infos);
419           }
420         }
421       } else {
422         for (int k = 0; k < superNodes.length; ++k) {
423           String JavaDoc superName = (String JavaDoc)superNodes[k].astGetAttributes().get(nameAttr);
424           int index = -1;
425           for (int l = 0; l < nodes.length; ++l) {
426             String JavaDoc name = (String JavaDoc)nodes[l].astGetAttributes().get(nameAttr);
427             if (name.equals(superName)) {
428               index = l;
429               break;
430             }
431           }
432           if (index == -1) {
433             computeMergeInfos(superNodes[k], infos);
434           } else {
435             computeMergeInfos(nodes[index], superNodes[k], infos);
436           }
437         }
438         
439         for (int l = 0; l < nodes.length; ++l) {
440           String JavaDoc name = (String JavaDoc)nodes[l].astGetAttributes().get(nameAttr);
441           int index = -1;
442           for (int k = 0; k < superNodes.length; ++k) {
443             String JavaDoc superName = (String JavaDoc)superNodes[k].astGetAttributes().get(nameAttr);
444             if (superName.equals(name)) {
445               index = k;
446               break;
447             }
448           }
449           if (index == -1) {
450             computeMergeInfos(nodes[l], infos);
451           }
452         }
453       }
454     }
455   }
456   
457   private void computeMergeInfos (final Node node, final Map JavaDoc infos)
458     throws ADLException
459   {
460     MergeInfo info = (MergeInfo)infos.get(node);
461     if (info != null) {
462       return;
463     }
464     info = new MergeInfo();
465     info.nodes.add(node);
466     infos.put(node, info);
467     String JavaDoc[] types = node.astGetNodeTypes();
468     for (int i = 0; i < types.length; ++i) {
469       String JavaDoc type = types[i];
470       Node[] subNodes = node.astGetNodes(type);
471       for (int j = 0; j < subNodes.length; j++) {
472         Node subNode = subNodes[j];
473         if (subNode != null) {
474           computeMergeInfos(subNode, infos);
475         }
476       }
477     }
478   }
479   
480   private void createMergedNodes (final Map JavaDoc infos)
481     throws ADLException
482   {
483     Iterator JavaDoc i = infos.values().iterator();
484     while (i.hasNext()) {
485       MergeInfo info = (MergeInfo)i.next();
486       if (info.result != null) {
487         continue;
488       }
489       
490       Node elem = (Node)info.nodes.get(0);
491       List JavaDoc classes = new ArrayList JavaDoc();
492       classes.add(elem.getClass());
493       
494       boolean ok = true;
495       for (int j = 1; j < info.nodes.size(); ++j) {
496         Class JavaDoc sec = info.nodes.get(j).getClass();
497         if (sec.getClassLoader() != ((Class JavaDoc)classes.get(0)).getClassLoader()) {
498           ok = false;
499         }
500         classes.add(sec);
501       }
502       
503       if (ok) {
504         try {
505           info.result = (Node)elem.getClass().newInstance();
506         } catch (Exception JavaDoc e) {
507           throw new ADLException("Cannot merge ASTs", elem, e);
508         }
509       } else {
510         try {
511           int hash = elem.getClass().hashCode();
512           for (int j = 1; j < classes.size(); ++j) {
513             hash = 17*(hash + classes.get(j).hashCode());
514           }
515           String JavaDoc code = Integer.toHexString(hash);
516           String JavaDoc name = "org.objectweb.fractal.adl.merged.Merged" + code;
517           Class JavaDoc merged = mergeClassLoader.mergeClass(
518             name,
519             elem.astGetType(),
520             (Class JavaDoc[])classes.toArray(new Class JavaDoc[classes.size()]));
521           info.result = (Node)merged.newInstance();
522         } catch (Exception JavaDoc e) {
523           throw new ADLException("Cannot merge AST classes", elem, e);
524         }
525       }
526     }
527   }
528
529   private Node initMergedNodes (final MergeInfo info, final Map JavaDoc infos) {
530     if (info.done) {
531       return info.result;
532     }
533     info.done = true;
534
535     Node elem = (Node)info.nodes.get(0);
536     Node result = info.result;
537     
538     // merges source
539
result.astSetSource(elem.astGetSource());
540
541     // merges attributes
542
Map JavaDoc resultAttrs = elem.astGetAttributes();
543     for (int i = 1; i < info.nodes.size(); ++i) {
544       Map JavaDoc superAttrs = ((Node)info.nodes.get(i)).astGetAttributes();
545       Iterator JavaDoc j = superAttrs.keySet().iterator();
546       while (j.hasNext()) {
547         String JavaDoc name = (String JavaDoc)j.next();
548         String JavaDoc superValue = (String JavaDoc)superAttrs.get(name);
549         String JavaDoc value = (String JavaDoc)resultAttrs.get(name);
550         if (superValue != null && value == null) {
551           resultAttrs.put(name, superValue);
552         }
553       }
554     }
555     result.astSetAttributes(resultAttrs);
556     
557     // merges decorations
558
Map JavaDoc resultDecors = elem.astGetDecorations();
559     for (int i = 1; i < info.nodes.size(); ++i) {
560       Map JavaDoc superDecors = ((Node)info.nodes.get(i)).astGetDecorations();
561       resultDecors.putAll(superDecors);
562     }
563     result.astSetDecorations(resultDecors);
564     
565     // merges sub nodes
566
Set JavaDoc nodeTypes = new HashSet JavaDoc();
567     nodeTypes.addAll(Arrays.asList(elem.astGetNodeTypes()));
568     for (int i = 1; i < info.nodes.size(); ++i) {
569       nodeTypes.addAll(
570         Arrays.asList(((Node)info.nodes.get(i)).astGetNodeTypes()));
571     }
572     
573     Iterator JavaDoc i = nodeTypes.iterator();
574     while (i.hasNext()) {
575       String JavaDoc nodeType = (String JavaDoc)i.next();
576       String JavaDoc nameAttr = (String JavaDoc)NAME_ATTRIBUTES.get(nodeType);
577       
578       List JavaDoc resultNodes = new ArrayList JavaDoc();
579       Node[] nodes = elem.astGetNodes(nodeType);
580       if (nodes == null) {
581         nodes = new Node[0];
582       }
583       for (int j = 0; j < nodes.length; ++j) {
584         if (nodes[j] != null) {
585           MergeInfo inf = (MergeInfo)infos.get(nodes[j]);
586           resultNodes.add(initMergedNodes(inf, infos));
587         }
588       }
589       
590       for (int j = 1; j < info.nodes.size(); ++j) {
591         Node superElem = (Node)info.nodes.get(j);
592         Node[] superNodes = superElem.astGetNodes(nodeType);
593         if (superNodes == null) {
594           continue;
595         }
596         
597         if (nameAttr == null) {
598           if (superNodes.length > 0 && superNodes[0] != null) {
599             if (nodes.length == 0 || nodes[0] == null) {
600               MergeInfo inf = (MergeInfo)infos.get(superNodes[0]);
601               resultNodes.add(initMergedNodes(inf, infos));
602             } else {
603               MergeInfo inf = (MergeInfo)infos.get(nodes[0]);
604               resultNodes.set(0, initMergedNodes(inf, infos));
605             }
606           }
607         } else {
608           for (int k = 0; k < superNodes.length; ++k) {
609             String JavaDoc superName = (String JavaDoc)superNodes[k].astGetAttributes().get(nameAttr);
610             int index = -1;
611             for (int l = 0; l < nodes.length; ++l) {
612               String JavaDoc name = (String JavaDoc)nodes[l].astGetAttributes().get(nameAttr);
613               if (name.equals(superName)) {
614                 index = l;
615                 break;
616               }
617             }
618             if (index == -1) {
619               MergeInfo inf = (MergeInfo)infos.get(superNodes[k]);
620               resultNodes.add(initMergedNodes(inf, infos));
621             } else {
622               MergeInfo inf = (MergeInfo)infos.get(nodes[index]);
623               resultNodes.set(index, initMergedNodes(inf, infos));
624             }
625           }
626         }
627       }
628       
629       for (int j = 0; j < resultNodes.size(); ++j) {
630         result.astAddNode((Node)resultNodes.get(j));
631       }
632     }
633     
634     return info.result;
635   }
636
637   private static class MergeInfo {
638         
639     List JavaDoc nodes = new ArrayList JavaDoc();
640     
641     Node result;
642     
643     boolean done;
644   }
645   
646   private static class MergeClassLoader extends NodeClassLoader {
647             
648     public MergeClassLoader (final ClassLoader JavaDoc parent) {
649       super(parent);
650     }
651     
652     public Class JavaDoc mergeClass (final String JavaDoc name, final String JavaDoc astNodeName, final Class JavaDoc[] classes)
653       throws ClassNotFoundException JavaDoc
654     {
655       try {
656         return loadClass(name);
657       } catch (ClassNotFoundException JavaDoc e) {
658       }
659             
660       Set JavaDoc itfs = new HashSet JavaDoc();
661       for (int i = 0; i < classes.length; ++i) {
662         Class JavaDoc[] citfs = classes[i].getInterfaces();
663         for (int j = 0; j < citfs.length; ++j) {
664           itfs.add(Type.getInternalName(citfs[j]));
665         }
666       }
667       
668       ClassWriter cw = generateClass(
669         name,
670         astNodeName,
671         Type.getInternalName(AbstractNode.class),
672         (String JavaDoc[])itfs.toArray(new String JavaDoc[itfs.size()]));
673       
674       /* DEBUG
675       try {
676         java.io.FileOutputStream fos =
677           new java.io.FileOutputStream(name + ".class");
678         fos.write(cw.toByteArray());
679         fos.close();
680       } catch (Exception _) {
681       }
682       */

683       return defineClass(name, cw.toByteArray());
684     }
685   }
686 }
687
Popular Tags