1 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 ; 36 import java.util.Arrays ; 37 import java.util.HashSet ; 38 import java.util.List ; 39 import java.util.Map ; 40 import java.util.Iterator ; 41 import java.util.HashMap ; 42 import java.util.Set ; 43 44 50 51 public class ComponentLoader 52 extends AbstractLoader implements ComponentLoaderAttributes 53 { 54 55 60 61 private Map NAME_ATTRIBUTES; 62 63 68 69 private MergeClassLoader mergeClassLoader; 70 71 75 public ComponentLoader () { 76 NAME_ATTRIBUTES = new HashMap (); 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 89 public String getNameAttributes () { 90 StringBuffer b = new StringBuffer (); 91 Iterator i = NAME_ATTRIBUTES.entrySet().iterator(); 92 while (i.hasNext()) { 93 Map.Entry e = (Map.Entry )i.next(); 94 b.append((String )e.getKey()); 95 b.append(' '); 96 b.append((String )e.getValue()); 97 b.append(' '); 98 } 99 return b.toString(); 100 } 101 102 public void setNameAttributes (String nameAttributes) { 103 NAME_ATTRIBUTES.clear(); 104 String key = null; 105 int p = nameAttributes.indexOf(' '); 106 while (p != -1) { 107 String 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 123 public Definition load (final String name, final Map context) 124 throws ADLException 125 { 126 return load(new ArrayList (), name, context); 127 } 128 129 public Definition load ( 130 final List loaded, 131 final String name, 132 final Map context) throws ADLException 133 { 134 if (loaded.contains(name)) { 135 throw new ADLException("Cycle in definition references: " + loaded, null); 136 } 137 List l = new ArrayList (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 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 163 public void normalizeComponentContainer (final ComponentContainer container) 164 throws ADLException 165 { 166 Set names = new HashSet (); 167 Component[] comps = container.getComponents(); 168 for (int i = 0; i < comps.length; i++) { 169 Component comp = comps[i]; 170 String 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 185 } 186 } 187 188 190 219 220 224 public void resolveComponentContainer ( 225 final List loaded, 226 final ComponentContainer topLevelDefinition, 227 final ComponentContainer container, 228 final Map 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 definition = comp.getDefinition(); 235 comp.setDefinition(null); 236 ((Node)comp).astSetDecoration("definition", definition); 237 if (definition != null) { 238 List defs = parseDefinitions(definition); 239 if (defs.size() == 1 && isShared((String )defs.get(0))) { 240 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 replacements = new HashMap (); 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 replacements = new HashMap (); 265 merge((Node)comp, (Node)d, replacements); 266 replaceComponents(topLevelDefinition, replacements); 267 } 268 } 269 } 270 } 271 272 public List parseDefinitions (String nameList) { 273 List l = new ArrayList (); 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 definition) { 285 return definition.indexOf('/') != -1; 286 } 287 288 public Definition resolveDefinitions ( 289 final List loaded, 290 final List nameList, 291 final Map context) throws ADLException 292 { 293 Definition d = load(loaded, (String )nameList.get(0), context); 294 for (int i = 1; i < nameList.size(); ++i) { 295 Definition e = load(loaded, (String )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 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 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 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 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 replacements) throws ADLException 358 { 359 Map infos = new HashMap (); 360 computeMergeInfos(elem, superElem, infos); 361 createMergedNodes(infos); 362 Node n = initMergedNodes((MergeInfo)infos.get(elem), infos); 363 if (replacements != null) { 364 Iterator i = infos.entrySet().iterator(); 365 while (i.hasNext()) { 366 Map.Entry e = (Map.Entry )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 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 nodeTypes = new HashSet (); 392 nodeTypes.addAll(Arrays.asList(elem.astGetNodeTypes())); 393 nodeTypes.addAll(Arrays.asList(superElem.astGetNodeTypes())); 394 395 Iterator i = nodeTypes.iterator(); 396 while (i.hasNext()) { 397 String nodeType = (String )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 nameAttr = (String )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 superName = (String )superNodes[k].astGetAttributes().get(nameAttr); 424 int index = -1; 425 for (int l = 0; l < nodes.length; ++l) { 426 String name = (String )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 name = (String )nodes[l].astGetAttributes().get(nameAttr); 441 int index = -1; 442 for (int k = 0; k < superNodes.length; ++k) { 443 String superName = (String )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 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 [] types = node.astGetNodeTypes(); 468 for (int i = 0; i < types.length; ++i) { 469 String 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 infos) 481 throws ADLException 482 { 483 Iterator 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 classes = new ArrayList (); 492 classes.add(elem.getClass()); 493 494 boolean ok = true; 495 for (int j = 1; j < info.nodes.size(); ++j) { 496 Class sec = info.nodes.get(j).getClass(); 497 if (sec.getClassLoader() != ((Class )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 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 code = Integer.toHexString(hash); 516 String name = "org.objectweb.fractal.adl.merged.Merged" + code; 517 Class merged = mergeClassLoader.mergeClass( 518 name, 519 elem.astGetType(), 520 (Class [])classes.toArray(new Class [classes.size()])); 521 info.result = (Node)merged.newInstance(); 522 } catch (Exception 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 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 result.astSetSource(elem.astGetSource()); 540 541 Map resultAttrs = elem.astGetAttributes(); 543 for (int i = 1; i < info.nodes.size(); ++i) { 544 Map superAttrs = ((Node)info.nodes.get(i)).astGetAttributes(); 545 Iterator j = superAttrs.keySet().iterator(); 546 while (j.hasNext()) { 547 String name = (String )j.next(); 548 String superValue = (String )superAttrs.get(name); 549 String value = (String )resultAttrs.get(name); 550 if (superValue != null && value == null) { 551 resultAttrs.put(name, superValue); 552 } 553 } 554 } 555 result.astSetAttributes(resultAttrs); 556 557 Map resultDecors = elem.astGetDecorations(); 559 for (int i = 1; i < info.nodes.size(); ++i) { 560 Map superDecors = ((Node)info.nodes.get(i)).astGetDecorations(); 561 resultDecors.putAll(superDecors); 562 } 563 result.astSetDecorations(resultDecors); 564 565 Set nodeTypes = new HashSet (); 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 i = nodeTypes.iterator(); 574 while (i.hasNext()) { 575 String nodeType = (String )i.next(); 576 String nameAttr = (String )NAME_ATTRIBUTES.get(nodeType); 577 578 List resultNodes = new ArrayList (); 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 superName = (String )superNodes[k].astGetAttributes().get(nameAttr); 610 int index = -1; 611 for (int l = 0; l < nodes.length; ++l) { 612 String name = (String )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 nodes = new ArrayList (); 640 641 Node result; 642 643 boolean done; 644 } 645 646 private static class MergeClassLoader extends NodeClassLoader { 647 648 public MergeClassLoader (final ClassLoader parent) { 649 super(parent); 650 } 651 652 public Class mergeClass (final String name, final String astNodeName, final Class [] classes) 653 throws ClassNotFoundException 654 { 655 try { 656 return loadClass(name); 657 } catch (ClassNotFoundException e) { 658 } 659 660 Set itfs = new HashSet (); 661 for (int i = 0; i < classes.length; ++i) { 662 Class [] 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 [])itfs.toArray(new String [itfs.size()])); 673 674 683 return defineClass(name, cw.toByteArray()); 684 } 685 } 686 } 687 | Popular Tags |