1 19 20 package org.netbeans.core.startup; 21 22 import java.io.BufferedInputStream ; 23 import java.io.ByteArrayInputStream ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.net.URL ; 27 import java.util.ArrayList ; 28 import java.util.Collections ; 29 import java.util.HashMap ; 30 import java.util.HashSet ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 import java.util.TreeSet ; 36 import org.openide.modules.Dependency; 37 import org.openide.modules.SpecificationVersion; 38 import org.openide.xml.XMLUtil; 39 import org.netbeans.*; 40 import org.xml.sax.Attributes ; 41 import org.xml.sax.ContentHandler ; 42 import org.xml.sax.EntityResolver ; 43 import org.xml.sax.ErrorHandler ; 44 import org.xml.sax.InputSource ; 45 import org.xml.sax.Locator ; 46 import org.xml.sax.SAXException ; 47 import org.xml.sax.SAXParseException ; 48 import org.xml.sax.XMLReader ; 49 50 59 public final class AutomaticDependencies { 60 61 private AutomaticDependencies() {} 62 63 67 public static AutomaticDependencies empty() { 68 return new AutomaticDependencies(); 69 } 70 71 81 public static AutomaticDependencies parse(URL [] urls) throws SAXException , IOException { 82 AutomaticDependencies h = new AutomaticDependencies(); 83 Parser p = new Parser(h.new Handler ()); 84 for (URL url : urls) { 85 String id = url.toExternalForm(); 86 InputStream inS = null; 87 try { 88 InputSource is = new InputSource (id); 89 inS = new BufferedInputStream (url.openStream()); 90 is.setByteStream(inS); 91 p.parse(is); 92 } catch (SAXException e) { 93 throw new SAXException ("While parsing: " + id, e); 94 } catch (IOException e) { 95 IOException exc = new IOException ("While parsing: " + id); 96 exc.initCause(e); 97 throw exc; 98 } 99 finally { 100 if (inS != null) { 101 inS.close(); 102 } 103 } 104 } 105 return h; 106 } 107 108 112 public static void main(String [] x) throws Exception { 113 URL [] urls = new URL [x.length]; 114 for (int i = 0; i < x.length; i++) { 115 urls[i] = new URL (x[i]); 116 } 117 parse(urls); long time = System.currentTimeMillis(); 119 System.out.println(parse(urls)); 120 long taken = System.currentTimeMillis() - time; 121 System.out.println("Time taken: " + taken + " msec"); 122 } 123 124 126 131 public static final class Report { 132 private final Set <Dependency> added; 133 private final Set <Dependency> removed; 134 private final Set <String > messages; 135 Report(Set <Dependency> added, Set <Dependency> removed, Set <String > messages) { 136 this.added = added; 137 this.removed = removed; 138 this.messages = messages; 139 } 140 144 public Set <Dependency> getAdded() { 145 return added; 146 } 147 151 public Set <Dependency> getRemoved() { 152 return removed; 153 } 154 159 public Set <String > getMessages() { 160 return messages; 161 } 162 166 public boolean isModified() { 167 return !added.isEmpty() || !removed.isEmpty(); 168 } 169 } 170 171 179 public Report refineDependenciesAndReport(String cnb, Set <Dependency> dependencies) { 180 Set <Dependency> oldDependencies = new HashSet <Dependency>(dependencies); 181 Map <String ,Dependency> modDeps = new HashMap <String ,Dependency>(); 185 Map <String ,Dependency> tokDeps = new HashMap <String ,Dependency>(); 186 Map <String ,Dependency> pkgDeps = new HashMap <String ,Dependency>(); 187 for (Dependency d: dependencies) { 188 switch (d.getType()) { 189 case Dependency.TYPE_MODULE: 190 String dcnb = (String )Util.parseCodeName(d.getName())[0]; 191 modDeps.put(dcnb, d); 192 break; 193 case Dependency.TYPE_PACKAGE: 194 String name = packageBaseName(d.getName()); 195 pkgDeps.put(name, d); 196 break; 197 case Dependency.TYPE_REQUIRES: 198 case Dependency.TYPE_NEEDS: 199 case Dependency.TYPE_RECOMMENDS: 200 tokDeps.put(d.getName(), d); 201 break; 202 case Dependency.TYPE_JAVA: 203 break; 205 default: 206 throw new IllegalStateException (d.toString()); 207 } 208 } 209 Set <String > messages = new TreeSet <String >(); 210 for (TransformationGroup g: groups) { 212 if (g.isExcluded(cnb)) { 213 continue; 214 } 215 Set <Dependency> oldRunningDependencies = new HashSet <Dependency>(dependencies); 216 for (Transformation t: g.transformations) { 217 t.apply(modDeps, tokDeps, pkgDeps, dependencies); 218 } 219 if (!oldRunningDependencies.equals(dependencies)) { 220 messages.add(g.description); 221 } 222 } 223 if (!oldDependencies.equals(dependencies)) { 224 assert !messages.isEmpty(); 225 Set <Dependency> added = new HashSet <Dependency>(dependencies); 226 added.removeAll(oldDependencies); 227 oldDependencies.removeAll(dependencies); 228 return new Report(added, oldDependencies, messages); 229 } else { 230 assert messages.isEmpty(); 231 return new Report(Collections.<Dependency>emptySet(), Collections.<Dependency>emptySet(), Collections.<String >emptySet()); 232 } 233 } 234 235 243 public void refineDependencies(String cnb, Set <Dependency> dependencies) { 244 refineDependenciesAndReport(cnb, dependencies); 245 } 246 247 249 private final List <TransformationGroup> groups = new ArrayList <TransformationGroup>(); 250 251 public String toString() { 252 return "AutomaticDependencies[" + groups + "]"; 253 } 254 255 private static final class Exclusion { 256 public Exclusion() {} 257 public String codenamebase; 258 public boolean prefix; 259 public String toString() { 260 return "Exclusion[" + codenamebase + ",prefix=" + prefix + "]"; 261 } 262 263 266 public boolean matches(String cnb) { 267 return cnb.equals(codenamebase) || 268 (prefix && cnb.startsWith(codenamebase + ".")); } 270 271 } 272 273 private static final class TransformationGroup { 274 public TransformationGroup() {} 275 public String description; 276 public final List <Exclusion> exclusions = new ArrayList <Exclusion>(); 277 public final List <Transformation> transformations = new ArrayList <Transformation>(); 278 public String toString() { 279 return "TransformationGroup[" + exclusions + "," + transformations + "]"; 280 } 281 282 285 public boolean isExcluded(String cnb) { 286 Iterator it = exclusions.iterator(); 287 while (it.hasNext()) { 288 if (((Exclusion)it.next()).matches(cnb)) { 289 return true; 290 } 291 } 292 return false; 293 } 294 295 } 296 297 private static final class Transformation { 298 public Transformation() {} 299 public Dep trigger; 300 public String triggerType; 301 public final List <Dep> results = new ArrayList <Dep>(); public String toString() { 303 return "Transformation[trigger=" + trigger + ",triggerType=" + triggerType + ",results=" + results + "]"; 304 } 305 306 309 public void apply(Map <String , Dependency> modDeps, 310 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 311 Set <Dependency> dependencies) { 312 Dependency d = trigger.applies(modDeps, tokDeps, pkgDeps, dependencies, triggerType); 313 if (d != null) { 314 if (triggerType.equals("cancel")) { 316 dependencies.remove(d); 318 } else if (triggerType.equals("older")) { 319 } else { 321 throw new IllegalStateException (triggerType); 322 } 323 Iterator it = results.iterator(); 325 while (it.hasNext()) { 326 Dep nue = (Dep)it.next(); 327 nue.update(modDeps, tokDeps, pkgDeps, dependencies); 328 } 329 } 330 } 331 332 } 333 334 private static abstract class Dep { 335 public Dep() {} 336 public final String toString() { 337 return manifestKey() + ": " + toManifestForm(); 338 } 339 340 343 public abstract String toManifestForm(); 344 345 348 public abstract String manifestKey(); 349 350 353 public abstract int type(); 354 355 358 public final Dependency createDependency() { 359 return Dependency.create(type(), toManifestForm()).iterator().next(); 360 } 361 362 366 public abstract Dependency applies(Map <String , Dependency> modDeps, 367 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 368 Set <Dependency> dependencies, String type); 369 370 375 public abstract void update(Map <String , Dependency> modDeps, 376 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 377 Set <Dependency> dependencies); 378 379 } 380 381 private static final class ModuleDep extends Dep { 382 public ModuleDep() {} 383 public String codenamebase; 384 public int major = -1; 385 public SpecificationVersion spec = null; 386 387 public String toManifestForm() { 388 return codenamebase + (major == -1 ? "" : "/" + major) + (spec == null ? "" : " > " + spec); 389 } 390 391 public String manifestKey() { 392 return "OpenIDE-Module-Module-Dependencies"; 393 } 394 395 public int type() { 396 return Dependency.TYPE_MODULE; 397 } 398 399 public Dependency applies(Map <String , Dependency> modDeps, 400 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 401 Set <Dependency> dependencies, String type) { 402 Dependency d = modDeps.get(codenamebase); 403 if (d == null) return null; 404 if (type.equals("cancel")) { 405 return d; 407 } else if (type.equals("older")) { 408 return older(d) ? d : null; 410 } else { 411 throw new IllegalArgumentException (type); 412 } 413 } 414 415 418 private boolean older(Dependency d) { 419 if (d.getType() != Dependency.TYPE_MODULE) throw new IllegalArgumentException (); 420 if (d.getComparison() == Dependency.COMPARE_IMPL) { 421 return false; 423 } 424 Integer dRelI = (Integer )Util.parseCodeName(d.getName())[1]; 425 int dRel = (dRelI == null) ? -1 : dRelI.intValue(); 426 if (dRel < major) return true; 427 if (dRel > major) return false; 428 if (spec == null) return false; 429 String dSpec = d.getVersion(); 430 if (dSpec == null) return true; 431 assert d.getComparison() == Dependency.COMPARE_SPEC : d.getComparison(); 432 return new SpecificationVersion(dSpec).compareTo(spec) < 0; 433 } 434 435 public void update(Map <String , Dependency> modDeps, Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, Set <Dependency> dependencies) { 436 Dependency d = modDeps.get(codenamebase); 437 if (d != null && older(d)) { 438 dependencies.remove(d); 439 Dependency nue = createDependency(); 440 assert !nue.equals(d) : "older() claimed to be true on itself for " + d; 441 dependencies.add(nue); 442 } else if (d == null) { 443 dependencies.add(createDependency()); 444 } 445 } 446 447 } 448 449 455 private static String packageBaseName(String name) { 456 int i = name.indexOf('['); 457 if (i == -1) { 458 return name; 459 } else if (i > 0) { 460 return name.substring(0, i); 461 } else { 462 int i2 = name.lastIndexOf('.'); 463 return name.substring(1, i2); 464 } 465 } 466 467 private static final class PackageDep extends Dep { 468 public PackageDep() {} 469 public String name; 470 public String bname; 471 public SpecificationVersion spec = null; 472 473 public String toManifestForm() { 474 return name + (spec == null ? "" : " > " + spec); 475 } 476 477 public String manifestKey() { 478 return "OpenIDE-Module-Package-Dependencies"; 479 } 480 481 public int type() { 482 return Dependency.TYPE_PACKAGE; 483 } 484 485 488 private boolean older(Dependency d) { 489 if (d.getType() != Dependency.TYPE_PACKAGE) throw new IllegalArgumentException (); 490 if (d.getComparison() == Dependency.COMPARE_IMPL) { 491 return false; 493 } 494 if (spec == null) return false; 495 String dSpec = d.getVersion(); 496 if (dSpec == null) return true; 497 assert d.getComparison() == Dependency.COMPARE_SPEC : d.getComparison(); 498 return new SpecificationVersion(dSpec).compareTo(spec) < 0; 499 } 500 501 public Dependency applies(Map <String , Dependency> modDeps, 502 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 503 Set <Dependency> dependencies, String type) { 504 Dependency d = pkgDeps.get(bname); 505 if (d == null) { 506 return null; 507 } 508 if (type.equals("cancel")) { 509 return d; 511 } else if (type.equals("older")) { 512 if (spec == null) throw new IllegalStateException (); 513 return older(d) ? d : null; 515 } else { 516 throw new IllegalStateException (type); 517 } 518 } 519 520 public void update(Map <String , Dependency> modDeps, 521 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 522 Set <Dependency> dependencies) { 523 Dependency d = pkgDeps.get(bname); 524 if (d != null && older(d)) { 525 dependencies.remove(d); 526 dependencies.add(createDependency()); 527 } else if (d == null) { 528 dependencies.add(createDependency()); 529 } 530 } 531 532 } 533 534 private static final class TokenDep extends Dep { 535 public TokenDep() {} 536 public String name; 537 538 public String toManifestForm() { 539 return name; 540 } 541 542 public String manifestKey() { 543 return "OpenIDE-Module-Requires"; 544 } 545 546 public int type() { 547 return Dependency.TYPE_REQUIRES; 548 } 549 550 public Dependency applies(Map <String , Dependency> modDeps, 551 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 552 Set <Dependency> dependencies, String type) { 553 Dependency d = tokDeps.get(name); 554 if (d == null) { 555 return null; 556 } 557 if (type.equals("cancel")) { 558 return d; 560 } else { 561 throw new IllegalStateException (type); 563 } 564 } 565 566 public void update(Map <String , Dependency> modDeps, 567 Map <String , Dependency> tokDeps, Map <String , Dependency> pkgDeps, 568 Set <Dependency> dependencies) { 569 if (tokDeps.get(name) == null) { 570 dependencies.add(createDependency()); 571 } 572 } 573 574 } 575 576 578 private final class Handler { 579 580 private TransformationGroup currentGroup = null; 581 private Transformation currentTransformation = null; 582 private boolean inTrigger = false; 583 584 Handler() {} 585 586 public void start_trigger(final Attributes meta) throws SAXException { 587 inTrigger = true; 588 currentTransformation.triggerType = meta.getValue("type"); 589 } 590 591 public void end_trigger() throws SAXException { 592 inTrigger = false; 593 } 594 595 public void start_transformation(final Attributes meta) throws SAXException { 596 currentTransformation = new Transformation(); 597 } 598 599 public void end_transformation() throws SAXException { 600 currentGroup.transformations.add(currentTransformation); 601 currentTransformation = null; 602 } 603 604 private void handleDep(Dep d) throws SAXException { 605 if (inTrigger) { 606 currentTransformation.trigger = d; 607 } else { 608 currentTransformation.results.add(d); 609 } 610 } 611 612 public void handle_module_dependency(final Attributes meta) throws SAXException { 613 ModuleDep d = new ModuleDep(); 614 String major = meta.getValue("major"); 615 if (major != null) { 616 d.major = Integer.parseInt(major); 617 } 618 d.codenamebase = meta.getValue("codenamebase"); 619 String s = meta.getValue("spec"); 620 d.spec = (s == null) ? null : new SpecificationVersion(s); 621 handleDep(d); 622 } 623 624 public void handle_token_dependency(final Attributes meta) throws SAXException { 625 TokenDep d = new TokenDep(); 626 d.name = meta.getValue("name"); 627 handleDep(d); 628 } 629 630 public void handle_package_dependency(final Attributes meta) throws SAXException { 631 PackageDep d = new PackageDep(); 632 d.name = meta.getValue("name"); 633 d.bname = packageBaseName(d.name); 634 if (inTrigger) { 635 if (!d.name.equals(d.bname)) throw new SAXException ("Cannot use test class in trigger"); 636 } 637 String s = meta.getValue("spec"); 638 d.spec = (s == null) ? null : new SpecificationVersion(s); 639 handleDep(d); 640 } 641 642 public void start_transformationgroup(final Attributes meta) throws SAXException { 643 currentGroup = new TransformationGroup(); 644 } 645 646 public void end_transformationgroup() throws SAXException { 647 groups.add(currentGroup); 648 currentGroup = null; 649 } 650 651 public void start_result(final Attributes meta) throws SAXException { 652 } 654 655 public void end_result() throws SAXException { 656 } 658 659 public void handle_exclusion(final Attributes meta) throws SAXException { 660 Exclusion excl = new Exclusion(); 661 excl.codenamebase = meta.getValue("codenamebase"); 662 excl.prefix = Boolean.valueOf(meta.getValue("prefix")).booleanValue(); 663 currentGroup.exclusions.add(excl); 664 } 665 666 public void handle_description(final String data, final Attributes meta) throws SAXException { 667 currentGroup.description = data; 668 } 669 670 public void start_transformations(final Attributes meta) throws SAXException { 671 if (!"1.0".equals(meta.getValue("version"))) throw new SAXException ("Unsupported DTD"); 672 } 674 675 public void end_transformations() throws SAXException { 676 } 678 679 public void start_results(final Attributes meta) throws SAXException { 680 } 682 683 public void end_results() throws SAXException { 684 } 686 687 } 688 689 private static final class Parser implements ContentHandler , ErrorHandler , EntityResolver { 690 691 private java.lang.StringBuffer buffer; 692 693 private Handler handler; 694 695 private java.util.Stack <Object []> context; 696 697 public Parser(final Handler handler) { 698 this.handler = handler; 699 buffer = new StringBuffer (111); 700 context = new java.util.Stack <Object []>(); 701 } 702 703 public final void setDocumentLocator(Locator locator) { 704 } 705 706 public final void startDocument() throws SAXException { 707 } 708 709 public final void endDocument() throws SAXException { 710 } 711 712 public final void startElement(java.lang.String ns, java.lang.String name, java.lang.String qname, Attributes attrs) throws SAXException { 713 dispatch(true); 714 context.push(new Object [] {qname, new org.xml.sax.helpers.AttributesImpl (attrs)}); 715 if ("trigger-dependency".equals(qname)) { 716 handler.start_trigger(attrs); 717 } else if ("transformation".equals(qname)) { 718 handler.start_transformation(attrs); 719 } else if ("module-dependency".equals(qname)) { 720 handler.handle_module_dependency(attrs); 721 } else if ("transformationgroup".equals(qname)) { 722 handler.start_transformationgroup(attrs); 723 } else if ("result".equals(qname)) { 724 handler.start_result(attrs); 725 } else if ("exclusion".equals(qname)) { 726 handler.handle_exclusion(attrs); 727 } else if ("token-dependency".equals(qname)) { 728 handler.handle_token_dependency(attrs); 729 } else if ("package-dependency".equals(qname)) { 730 handler.handle_package_dependency(attrs); 731 } else if ("transformations".equals(qname)) { 732 handler.start_transformations(attrs); 733 } else if ("implies".equals(qname)) { 734 handler.start_results(attrs); 735 } 736 } 737 738 public final void endElement(java.lang.String ns, java.lang.String name, java.lang.String qname) throws SAXException { 739 dispatch(false); 740 context.pop(); 741 if ("trigger-dependency".equals(qname)) { 742 handler.end_trigger(); 743 } else if ("transformation".equals(qname)) { 744 handler.end_transformation(); 745 } else if ("transformationgroup".equals(qname)) { 746 handler.end_transformationgroup(); 747 } else if ("result".equals(qname)) { 748 handler.end_result(); 749 } else if ("transformations".equals(qname)) { 750 handler.end_transformations(); 751 } else if ("implies".equals(qname)) { 752 handler.end_results(); 753 } 754 } 755 756 public final void characters(char[] chars, int start, int len) throws SAXException { 757 buffer.append(chars, start, len); 758 } 759 760 public final void ignorableWhitespace(char[] chars, int start, int len) throws SAXException { 761 } 762 763 public final void processingInstruction(java.lang.String target, java.lang.String data) throws SAXException { 764 } 765 766 public final void startPrefixMapping(final java.lang.String prefix, final java.lang.String uri) throws SAXException { 767 } 768 769 public final void endPrefixMapping(final java.lang.String prefix) throws SAXException { 770 } 771 772 public final void skippedEntity(java.lang.String name) throws SAXException { 773 } 774 775 private void dispatch(final boolean fireOnlyIfMixed) throws SAXException { 776 if (fireOnlyIfMixed && buffer.length() == 0) return; 778 Object [] ctx = context.peek(); 779 String here = (String ) ctx[0]; 780 Attributes attrs = (Attributes ) ctx[1]; 781 if ("description".equals(here)) { 782 if (fireOnlyIfMixed) throw new IllegalStateException ("Unexpected characters() event! (Missing DTD?)"); 783 handler.handle_description(buffer.length() == 0 ? null : buffer.toString(), attrs); 784 } else { 785 } 787 buffer.delete(0, buffer.length()); 788 } 789 790 796 public void parse(final InputSource input) throws SAXException , IOException { 797 XMLReader parser = XMLUtil.createXMLReader(false, false); parser.setContentHandler(this); 799 parser.setErrorHandler(this); 800 parser.setEntityResolver(this); 801 parser.parse(input); 802 } 803 804 public void error(SAXParseException ex) throws SAXException { 805 throw ex; 807 } 808 809 public void fatalError(SAXParseException ex) throws SAXException { 810 throw ex; 811 } 812 813 public void warning(SAXParseException ex) throws SAXException { 814 } 816 817 public InputSource resolveEntity(String publicId, String systemId) throws SAXException , IOException { 818 return new InputSource (new ByteArrayInputStream (new byte[0])); 820 } 821 822 } 823 824 } 825 | Popular Tags |