1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package org.objectweb.fractal.cecilia.adl.idl;
27
28 import static org.objectweb.fractal.cecilia.adl.ReservedWordsChecker.isReservedCWord;
29 import static org.objectweb.fractal.cecilia.adl.idl.util.Util.getComplexType;
30 import static org.objectweb.fractal.cecilia.adl.idl.util.Util.getContainedType;
31 import static org.objectweb.fractal.cecilia.adl.idl.util.Util.isComplexType;
32 import static org.objectweb.fractal.cecilia.adl.idl.util.Util.setContainedDefinition;
33 import static org.objectweb.fractal.cecilia.adl.idl.util.Util.setImportedAST;
34
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.net.URL;
38 import java.util.ArrayList;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Set;
45
46 import org.objectweb.fractal.adl.ADLException;
47 import org.objectweb.fractal.adl.CompilerError;
48 import org.objectweb.fractal.adl.ContextLocal;
49 import org.objectweb.fractal.adl.Node;
50 import org.objectweb.fractal.adl.error.ChainedErrorLocator;
51 import org.objectweb.fractal.adl.error.GenericErrors;
52 import org.objectweb.fractal.adl.error.NodeErrorLocator;
53 import org.objectweb.fractal.adl.interfaces.IDLLoader;
54 import org.objectweb.fractal.adl.timestamp.Timestamp;
55 import org.objectweb.fractal.adl.util.ClassLoaderHelper;
56 import org.objectweb.fractal.adl.xml.XMLNode;
57 import org.objectweb.fractal.adl.xml.XMLNodeFactory;
58 import org.objectweb.fractal.api.NoSuchInterfaceException;
59 import org.objectweb.fractal.api.control.BindingController;
60 import org.objectweb.fractal.api.control.IllegalBindingException;
61 import org.objectweb.fractal.api.control.IllegalLifeCycleException;
62 import org.objectweb.fractal.cecilia.adl.idl.ast.ComplexType;
63 import org.objectweb.fractal.cecilia.adl.idl.ast.EnumDefinition;
64 import org.objectweb.fractal.cecilia.adl.idl.ast.ExtendingDefinition;
65 import org.objectweb.fractal.cecilia.adl.idl.ast.Field;
66 import org.objectweb.fractal.cecilia.adl.idl.ast.FieldContainer;
67 import org.objectweb.fractal.cecilia.adl.idl.ast.IDLDefinition;
68 import org.objectweb.fractal.cecilia.adl.idl.ast.Import;
69 import org.objectweb.fractal.cecilia.adl.idl.ast.ImportContainer;
70 import org.objectweb.fractal.cecilia.adl.idl.ast.InterfaceDefinition;
71 import org.objectweb.fractal.cecilia.adl.idl.ast.Method;
72 import org.objectweb.fractal.cecilia.adl.idl.ast.MethodContainer;
73 import org.objectweb.fractal.cecilia.adl.idl.ast.Parameter;
74 import org.objectweb.fractal.cecilia.adl.idl.ast.ParameterContainer;
75 import org.objectweb.fractal.cecilia.adl.idl.ast.RecordDefinition;
76 import org.objectweb.fractal.cecilia.adl.idl.ast.Type;
77 import org.objectweb.fractal.cecilia.adl.idl.ast.TypeContainer;
78 import org.objectweb.fractal.cecilia.adl.idl.ast.UnionDefinition;
79 import org.objectweb.fractal.cecilia.adl.idl.parser.IDLParser;
80 import org.objectweb.fractal.cecilia.adl.idl.parser.ParseException;
81 import org.objectweb.fractal.cecilia.adl.interfaces.InterfaceDecorationUtil;
82 import org.xml.sax.SAXException;
83
84
85
86
87
88
89
90
91 public class BasicIDLLoader implements IDLLoader, BindingController {
92
93
94 public static final String NODE_FACTORY_ITF_NAME = "node-factory";
95
96
97
98
99
100 public XMLNodeFactory nodeFactoryItf;
101
102 protected ContextLocal<Map<String, IDLDefinition>> loadedCode = new ContextLocal<Map<String, IDLDefinition>>();
103
104
105
106
107
108 public Object loadInterface(final String signature,
109 final Map<Object, Object> context) throws ADLException {
110
111 Map<String, IDLDefinition> cache = loadedCode.get(context);
112 if (cache == null) {
113 cache = new HashMap<String, IDLDefinition>();
114 loadedCode.set(context, cache);
115 }
116 final Object c = cache.get(signature);
117 if (c != null) return c;
118
119 final ClassLoader loader = ClassLoaderHelper.getClassLoader(this, context);
120 final Map<String, DependantNode> toBeLoaded = new HashMap<String, DependantNode>();
121 final IDLDefinition definition = loadIDL(signature, toBeLoaded,
122 new ArrayList<String>(), loader, cache);
123
124
125
126
127 while (!toBeLoaded.isEmpty()) {
128
129
130 final Iterator<Map.Entry<String, DependantNode>> iter = toBeLoaded
131 .entrySet().iterator();
132 final Map.Entry<String, DependantNode> elem = iter.next();
133 iter.remove();
134
135 final DependantNode dep = elem.getValue();
136
137 try {
138 final IDLDefinition def = loadIDL(elem.getKey(), toBeLoaded,
139 new ArrayList<String>(), loader, cache);
140
141 dep.setDefinition(def);
142 } catch (final ADLException e) {
143 if (dep.imports != null)
144 ChainedErrorLocator.chainLocator(e, dep.imports.get(0));
145 else if (dep.types != null)
146 ChainedErrorLocator.chainLocator(e, dep.types.get(0));
147
148 throw e;
149 }
150 }
151 return definition;
152 }
153
154
155
156
157
158 protected IDLDefinition loadIDL(final String signature,
159 final Map<String, DependantNode> toBeLoaded,
160 final List<String> inheritancePath, final ClassLoader loader,
161 final Map<String, IDLDefinition> cache) throws ADLException {
162
163
164 IDLDefinition node = cache.get(signature);
165 if (node != null) return node;
166
167 final URL srcFile = locate(signature, loader);
168
169 InputStream inputStream;
170 try {
171 inputStream = srcFile.openStream();
172 } catch (final IOException e) {
173 throw new ADLException(IDLErrors.IO_ERROR, e, srcFile.getPath());
174 }
175 node = parseIDL(inputStream, signature, srcFile.getPath());
176
177
178 Timestamp.setTimestamp(node, srcFile);
179
180 check(signature, node, toBeLoaded, inheritancePath, loader, cache);
181 if (node instanceof ImportContainer) {
182 for (final Import i : ((ImportContainer) node).getImports()) {
183 DependantNode d = toBeLoaded.get(i.getName());
184 if (d == null) {
185 d = new DependantNode();
186 toBeLoaded.put(i.getName(), d);
187 }
188 d.addImport(i);
189 }
190 }
191
192 cache.put(signature, node);
193 return node;
194 }
195
196
197
198
199
200
201
202
203
204 protected IDLDefinition parseIDL(final InputStream inputStream,
205 final String signature, final String srcFile) throws ADLException {
206 IDLDefinition node;
207 final IDLParser parser = new IDLParser(inputStream);
208 parser.init(nodeFactoryItf, CeciliaIDLConstants.CECILIA_IDL_DTD, srcFile);
209 try {
210 node = parser.getIDLNode();
211 } catch (final ParseException e) {
212 throw new ADLException(IDLErrors.SYNTAX_ERROR, signature, e.getMessage());
213 }
214 return node;
215 }
216
217 protected URL locate(final String signature, final ClassLoader loader)
218 throws ADLException {
219 final URL srcFile = loader
220 .getResource(signature.replace('.', '/') + ".idl");
221 if (srcFile == null) {
222 throw new ADLException(IDLErrors.IDL_NOT_FOUND, signature);
223 }
224 return srcFile;
225 }
226
227 protected void resolv(final ComplexType typeNode,
228 final IDLDefinition idlNode, final Map<String, DependantNode> toBeLoaded,
229 final ClassLoader loader, final Map<String, IDLDefinition> cache)
230 throws ADLException {
231 final String signatureToResolv = typeNode.getName();
232 final String resolvedSignature = resolveSignature(idlNode,
233 signatureToResolv, typeNode, loader);
234 addImport(resolvedSignature, (ImportContainer) idlNode);
235 final IDLDefinition definition = cache.get(resolvedSignature);
236 if (definition == null) {
237
238 DependantNode l = toBeLoaded.get(resolvedSignature);
239 if (l == null) {
240 l = new DependantNode();
241 toBeLoaded.put(resolvedSignature, l);
242 }
243 l.addComplexType(typeNode);
244 } else {
245 setContainedDefinition(typeNode, definition);
246 }
247 }
248
249
250
251
252 protected String resolveSignature(final IDLDefinition idlNode,
253 final String signatureToResolv, final Node referencingNode,
254 final ClassLoader loader) throws ADLException {
255 final String idlSignature = idlNode.getName();
256 String resolvedSignature = null;
257 if (signatureToResolv.equals(idlSignature)) {
258 return idlSignature;
259 } else if (signatureToResolv.indexOf('.') != -1) {
260
261 resolvedSignature = signatureToResolv;
262 } else {
263 for (final Import imp : ((ImportContainer) idlNode).getImports()) {
264 final String importName = imp.getName();
265 final String interfaceName = importName.substring(importName
266 .lastIndexOf('.') + 1);
267 if (signatureToResolv.equals(interfaceName)) {
268 resolvedSignature = importName;
269 break;
270 }
271 }
272
273 if (resolvedSignature == null) {
274
275
276 final int i = idlSignature.lastIndexOf('.');
277 if (i < 0) {
278 resolvedSignature = signatureToResolv;
279 } else {
280 resolvedSignature = idlSignature.substring(0, i) + "."
281 + signatureToResolv;
282 }
283 }
284 }
285 try {
286 locate(resolvedSignature, loader);
287 } catch (final ADLException e) {
288 ChainedErrorLocator.chainLocator(e, referencingNode);
289 throw e;
290 }
291 return resolvedSignature;
292 }
293
294 protected void check(final String signature, IDLDefinition node,
295 final Map<String, DependantNode> toBeLoaded,
296 final List<String> inheritancePath, final ClassLoader loader,
297 final Map<String, IDLDefinition> cache) throws ADLException {
298
299 checkPackageSrcCompatibility(signature, node);
300 checkInterfaceNameSrcCompatibility(signature, node);
301 normalizeIDL(node, loader);
302
303
304
305
306
307 InterfaceDecorationUtil.updateInheritancePathDecoration(node, signature);
308
309 if (node instanceof InterfaceDefinition) {
310 final InterfaceDefinition interfaceDefinition = (InterfaceDefinition) node;
311 inheritancePath.add(signature);
312 String ext = null;
313 if (interfaceDefinition instanceof ExtendingDefinition) {
314 ext = ((ExtendingDefinition) interfaceDefinition).getExtends();
315 ((ExtendingDefinition) interfaceDefinition).setExtends(null);
316 }
317 if (ext != null) {
318
319 final String resolvedSuperSignature = resolveSignature(node, ext, node,
320 loader);
321 if (inheritancePath.contains(resolvedSuperSignature)) {
322 throw new ADLException(IDLErrors.INHERITANCE_CYCLE,
323 interfaceDefinition, signature, resolvedSuperSignature);
324 }
325 final IDLDefinition def;
326 try {
327 def = loadIDL(resolvedSuperSignature, toBeLoaded, inheritancePath,
328 loader, cache);
329 } catch (final ADLException e) {
330 ChainedErrorLocator.chainLocator(e, interfaceDefinition);
331 throw e;
332 }
333 if (!(def instanceof InterfaceDefinition)) {
334 throw new ADLException(IDLErrors.INVALID_SUPER_INTERFACE,
335 interfaceDefinition, resolvedSuperSignature);
336 }
337 addImport(resolvedSuperSignature, (ImportContainer) node);
338 node = merge(def, node);
339 }
340 inheritancePath.remove(inheritancePath.size() - 1);
341
342 for (final Field field : ((FieldContainer) interfaceDefinition)
343 .getFields()) {
344 final Type type = getContainedType(field);
345 if (isComplexType(type))
346 resolv(getComplexType(type), node, toBeLoaded, loader, cache);
347 }
348 for (final Method method : ((MethodContainer) interfaceDefinition)
349 .getMethods()) {
350 final Type returnType = getContainedType(method);
351 if (isComplexType(returnType))
352 resolv(getComplexType(returnType), node, toBeLoaded, loader, cache);
353
354 for (final Parameter parameter : ((ParameterContainer) method)
355 .getParameters()) {
356 final Type parameterType = getContainedType(parameter);
357 if (isComplexType(parameterType))
358 resolv(getComplexType(parameterType), node, toBeLoaded, loader,
359 cache);
360 }
361 }
362 } else if (node instanceof RecordDefinition) {
363 final RecordDefinition recordDefinition = (RecordDefinition) node;
364
365 for (final Field field : ((FieldContainer) recordDefinition).getFields()) {
366 final Type type = getContainedType(field);
367 if (isComplexType(type))
368 resolv(getComplexType(type), node, toBeLoaded, loader, cache);
369 }
370 } else if (node instanceof UnionDefinition) {
371 final UnionDefinition unionDefinition = (UnionDefinition) node;
372
373 for (final Field field : ((FieldContainer) unionDefinition).getFields()) {
374 final Type type = getContainedType(field);
375 if (isComplexType(type))
376 resolv(getComplexType(type), node, toBeLoaded, loader, cache);
377 }
378 } else if (node instanceof EnumDefinition) {
379
380 } else {
381 throw new CompilerError(GenericErrors.INTERNAL_ERROR,
382 new NodeErrorLocator(node), "Unrecognized IDL construct in '"
383 + signature + "'");
384 }
385 }
386
387 protected IDLDefinition merge(final IDLDefinition superNode,
388 final IDLDefinition node) throws ADLException {
389
390 final Set<String> imports = new HashSet<String>();
391 for (final Import i : ((ImportContainer) node).getImports())
392 imports.add(i.getName());
393
394
395 for (final Import i : ((ImportContainer) superNode).getImports())
396 if (imports.add(i.getName())) ((ImportContainer) node).addImport(i);
397
398
399
400
401
402
403
404 final FieldContainer nodeFieldCtn = (FieldContainer) node;
405 final Field[] nodeFields = nodeFieldCtn.getFields();
406 final MethodContainer nodeMethodCtn = (MethodContainer) node;
407 final Method[] nodeMethods = nodeMethodCtn.getMethods();
408
409
410
411
412
413 final Map<String, Node> nodes = new HashMap<String, Node>();
414 for (final Field f : nodeFieldCtn.getFields()) {
415 nodes.put(f.getName(), f);
416 nodeFieldCtn.removeField(f);
417 }
418 for (final Method m : (nodeMethodCtn).getMethods()) {
419 nodes.put(m.getName(), m);
420 nodeMethodCtn.removeMethod(m);
421 }
422
423
424 for (final Field f : ((FieldContainer) superNode).getFields()) {
425 final Node n = nodes.put(f.getName(), f);
426 if (n != null) {
427 throw new ADLException(IDLErrors.DUPLICATED_FIELD_NAME, f, f.getName(),
428 new NodeErrorLocator(n));
429 }
430 nodeFieldCtn.addField(f);
431 }
432
433
434 for (final Method m : ((MethodContainer) superNode).getMethods()) {
435 final Node n = nodes.put(m.getName(), m);
436 if (n != null) {
437 throw new ADLException(IDLErrors.DUPLICATED_METHOD_NAME, m,
438 m.getName(), new NodeErrorLocator(n));
439 }
440 nodeMethodCtn.addMethod(m);
441 }
442
443
444 for (final Field field : nodeFields)
445 nodeFieldCtn.addField(field);
446
447
448 for (final Method method : nodeMethods)
449 nodeMethodCtn.addMethod(method);
450
451
452 InterfaceDecorationUtil.updateInheritancePathDecoration(node,
453 InterfaceDecorationUtil.getInheritancePathDecoration(superNode));
454
455
456 Timestamp.setTimestamp(node, Timestamp.getTimestamp(superNode));
457 return node;
458 }
459
460 protected void normalizeIDL(final IDLDefinition idlNode,
461 final ClassLoader loader) throws ADLException {
462 if (idlNode instanceof ImportContainer) {
463 for (final Import i : ((ImportContainer) idlNode).getImports()) {
464 try {
465 locate(i.getName(), loader);
466 } catch (final ADLException e) {
467 ChainedErrorLocator.chainLocator(e, i);
468 throw e;
469 }
470 }
471 }
472 final Map<String, Node> nodes = new HashMap<String, Node>();
473
474 if (isReservedCWord(idlNode.getName())) {
475 throw new ADLException(IDLErrors.IDL_NAME_IS_RESERVED_WORD, idlNode,
476 idlNode.getName());
477 }
478
479
480 if (idlNode instanceof FieldContainer) {
481 for (final Field f : ((FieldContainer) idlNode).getFields()) {
482 if (isReservedCWord(f.getName())) {
483 throw new ADLException(IDLErrors.IDL_NAME_IS_RESERVED_WORD, f, f
484 .getName());
485 }
486 final Node n = nodes.put(f.getName(), f);
487 if (n != null)
488 throw new ADLException(IDLErrors.DUPLICATED_FIELD_NAME, f, f
489 .getName(), new NodeErrorLocator(n));
490 }
491 }
492
493 if (idlNode instanceof MethodContainer) {
494 for (final Method m : ((MethodContainer) idlNode).getMethods()) {
495 if (isReservedCWord(m.getName())) {
496 throw new ADLException(IDLErrors.IDL_NAME_IS_RESERVED_WORD, m, m
497 .getName());
498 }
499 final Node previousDeclaration = nodes.put(m.getName(), m);
500 if (previousDeclaration != null)
501 throw new ADLException(IDLErrors.DUPLICATED_METHOD_NAME, m, m
502 .getName(), new NodeErrorLocator(previousDeclaration));
503 final Map<String, Node> params = new HashMap<String, Node>();
504 for (final Parameter p : m.getParameters()) {
505 if (isReservedCWord(p.getName())) {
506 throw new ADLException(IDLErrors.IDL_NAME_IS_RESERVED_WORD, p, p
507 .getName());
508 }
509 final Node n1 = params.put(p.getName(), p);
510 if (n1 != null) {
511 throw new ADLException(IDLErrors.DUPLICATED_PARAMETER_NAME, p, p
512 .getName(), new NodeErrorLocator(n1));
513 }
514 }
515 }
516 }
517 }
518
519 protected XMLNode newNode(final String name) {
520 try {
521 return nodeFactoryItf.newXMLNode(CeciliaIDLConstants.CECILIA_IDL_DTD,
522 name);
523 } catch (final SAXException e) {
524 throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
525 "Unable to create node \"" + name + "\"");
526 }
527 }
528
529 protected void addImport(final String signature,
530 final ImportContainer importContainer) {
531 for (final Import i : importContainer.getImports()) {
532 if (i.getName().equals(signature)) return;
533 }
534 final Import newImport = (Import) newNode("import");
535 newImport.setName(signature);
536 importContainer.addImport(newImport);
537 }
538
539 protected void addComplexType(final IDLDefinition node,
540 final TypeContainer complexTypeContainer) {
541
542 if (complexTypeContainer.getComplexType() == null) {
543 throw new IllegalStateException("There is already a sub element");
544 }
545 final ComplexType ct = (ComplexType) newNode("complexType");
546 ct.setIDLDefinition(node);
547 complexTypeContainer.setComplexType(ct);
548 }
549
550 protected void checkPackageSrcCompatibility(final String signature,
551 final IDLDefinition node) throws ADLException {
552 final String nodeSignature = node.getName();
553 final String nodePkgName = (nodeSignature.lastIndexOf('.') < 0)
554 ? ""
555 : nodeSignature.substring(0, nodeSignature.lastIndexOf('.'));
556 final String expPkgName = (signature.lastIndexOf('.') < 0) ? "" : signature
557 .substring(0, signature.lastIndexOf('.'));
558 if (!expPkgName.equals(nodePkgName))
559 throw new ADLException(IDLErrors.INVALID_PACKAGE_NAME, node, nodePkgName,
560 expPkgName);
561 }
562
563 protected void checkInterfaceNameSrcCompatibility(final String signature,
564 final IDLDefinition node) throws ADLException {
565 final String nodeSignature = node.getName();
566 final String nodeItfName = (nodeSignature.lastIndexOf('.') < 0)
567 ? nodeSignature
568 : nodeSignature.substring(nodeSignature.lastIndexOf('.') + 1);
569 final String expItfName = (signature.lastIndexOf('.') < 0)
570 ? signature
571 : signature.substring(signature.lastIndexOf('.') + 1);
572 if (!expItfName.equals(nodeItfName))
573 throw new ADLException(IDLErrors.INVALID_IDL_NAME, node, nodeItfName,
574 expItfName);
575 }
576
577 protected static final class DependantNode {
578 private List<ComplexType> types;
579 private List<Import> imports;
580
581 protected void addComplexType(final ComplexType type) {
582 if (types == null) types = new ArrayList<ComplexType>();
583 types.add(type);
584 }
585
586 protected void addImport(final Import i) {
587 if (imports == null) imports = new ArrayList<Import>();
588 imports.add(i);
589 }
590
591 protected void setDefinition(final IDLDefinition def) {
592
593 if (types != null) {
594 for (final ComplexType ct : types) {
595 ct.setIDLDefinition(def);
596 }
597 }
598
599 if (imports != null) {
600 for (final Import i : imports)
601 setImportedAST(i, def);
602 }
603 }
604 }
605
606
607
608
609
610 public void bindFc(final String itfName, final Object value)
611 throws NoSuchInterfaceException, IllegalBindingException,
612 IllegalLifeCycleException {
613
614 if (itfName == null) {
615 throw new IllegalArgumentException("Interface name can't be null");
616 }
617
618 if (itfName.equals(NODE_FACTORY_ITF_NAME)) {
619 this.nodeFactoryItf = (XMLNodeFactory) value;
620 } else {
621 throw new NoSuchInterfaceException("There is no interface named '"
622 + itfName + "'");
623 }
624
625 }
626
627 public String[] listFc() {
628 return new String[]{NODE_FACTORY_ITF_NAME};
629 }
630
631 public Object lookupFc(final String itfName) throws NoSuchInterfaceException {
632
633 if (itfName == null) {
634 throw new IllegalArgumentException("Interface name can't be null");
635 }
636
637 if (itfName.equals(NODE_FACTORY_ITF_NAME)) {
638 return this.nodeFactoryItf;
639 } else {
640 throw new NoSuchInterfaceException("There is no interface named '"
641 + itfName + "'");
642 }
643 }
644
645 public void unbindFc(final String itfName) throws NoSuchInterfaceException,
646 IllegalBindingException, IllegalLifeCycleException {
647
648 if (itfName == null) {
649 throw new IllegalArgumentException("Interface name can't be null");
650 }
651
652 if (itfName.equals(NODE_FACTORY_ITF_NAME)) {
653 this.nodeFactoryItf = null;
654 } else {
655 throw new NoSuchInterfaceException("There is no interface named '"
656 + itfName + "'");
657 }
658 }
659 }