1 19 20 package org.apache.tools.ant.module.api.support; 21 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.util.ArrayList ; 27 import java.util.Collection ; 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.Locale ; 34 import java.util.Map ; 35 import java.util.Properties ; 36 import java.util.Set ; 37 import java.util.WeakHashMap ; 38 import org.apache.tools.ant.module.api.AntProjectCookie; 39 import org.apache.tools.ant.module.xml.AntProjectSupport; 40 import org.openide.filesystems.FileObject; 41 import org.openide.filesystems.FileUtil; 42 import org.openide.loaders.DataObject; 43 import org.openide.loaders.DataObjectNotFoundException; 44 import org.openide.util.NbCollections; 45 import org.openide.util.TopologicalSortException; 46 import org.openide.util.Union2; 47 import org.openide.util.Utilities; 48 import org.w3c.dom.Element ; 49 import org.w3c.dom.Node ; 50 import org.w3c.dom.NodeList ; 51 52 79 public class TargetLister { 80 81 private TargetLister() {} 82 83 92 public static Set <Target> getTargets(AntProjectCookie script) throws IOException { 93 Set <File > alreadyImported = new HashSet <File >(); 94 Map <String ,String > properties = NbCollections.checkedMapByFilter(System.getProperties(), String .class, String .class, false); 95 Script main = new Script(null, script, alreadyImported, properties, Collections.<String ,Element >emptyMap()); 96 Set <Target> targets = new HashSet <Target>(); 97 Set <AntProjectCookie> visitedScripts = new HashSet <AntProjectCookie>(); 98 traverseScripts(main, targets, visitedScripts); 99 return targets; 100 } 101 102 107 private static void traverseScripts(Script script, Set <Target> targets, Set <AntProjectCookie> visitedScripts) throws IOException { 108 if (!visitedScripts.add(script.getScript())) { 109 return; 110 } 111 targets.addAll(script.getTargets()); 112 for (Script imported : script.getImports()) { 113 traverseScripts(imported, targets, visitedScripts); 114 } 115 } 116 117 120 public static final class Target { 121 122 private final Script script; 123 private final Element el; 124 private final String name; 125 126 Target(Script script, Element el, String name) { 127 this.script = script; 128 this.el = el; 129 this.name = name; 130 } 131 132 137 public String getName() { 138 return name; 139 } 140 141 152 public String getQualifiedName() { 153 String n = script.getName(); 154 if (n != null) { 155 return n + '.' + getName(); 156 } else { 157 return getName(); 158 } 159 } 160 161 165 public Element getElement() { 166 return el; 167 } 168 169 174 public AntProjectCookie getScript() { 175 return script.getScript(); 176 } 177 178 187 public boolean isDescribed() { 188 return el.getAttribute("description").length() > 0; 189 } 190 191 201 public boolean isInternal() { 202 String n = getName(); 203 return n.length() > 0 && n.charAt(0) == '-'; 204 } 205 206 218 public boolean isOverridden() { 219 return !script.defines(getName()); 220 } 221 222 229 public boolean isDefault() { 230 return !isOverridden() && getName().equals(script.getMainScript().getDefaultTargetName()); 231 } 232 233 @Override 234 public String toString() { 235 return "Target " + getName() + " in " + getScript(); } 237 238 } 239 240 243 private static final class Script { 244 245 private final AntProjectCookie apc; 246 private final Script importingScript; 247 private final Map <String ,Target> targets; 248 private final String defaultTarget; 249 private final List <Script> imports; 250 private final String name; 251 252 private static final Set <String > TRUE_VALS = new HashSet <String >(5); 253 static { 254 TRUE_VALS.add("true"); TRUE_VALS.add("yes"); TRUE_VALS.add("on"); } 258 259 public Script(Script importingScript, AntProjectCookie apc, Set <File > alreadyImported, Map <String ,String > inheritedPropertyDefs, Map <String ,Element > inheritedMacroDefs) throws IOException { 260 this.importingScript = importingScript; 261 this.apc = apc; 262 Element prj = apc.getProjectElement(); 263 if (prj == null) { 264 throw new IOException ("Could not parse " + apc); } 266 File prjFile = apc.getFile(); 267 if (prjFile != null) { 268 alreadyImported.add(prjFile); 269 } 270 String _defaultTarget = prj.getAttribute("default"); defaultTarget = _defaultTarget.length() > 0 ? _defaultTarget : null; 272 String _name = prj.getAttribute("name"); name = _name.length() > 0 ? _name : null; 274 String basedirS = prj.getAttribute("basedir"); if (basedirS.length() == 0) { 278 basedirS = "."; } else { 280 basedirS = basedirS.replace('/', File.separatorChar).replace('\\', File.separatorChar); 281 } 282 File _basedir = new File (basedirS); 283 File basedir; 284 if (_basedir.isAbsolute()) { 285 basedir = _basedir; 286 } else { 287 if (prjFile != null) { 288 basedir = new File (prjFile.getParentFile(), basedirS); 289 } else { 290 basedir = null; 292 } 293 } 294 targets = new HashMap <String ,Target>(); 296 Map <String ,String > propertyDefs = new HashMap <String ,String >(inheritedPropertyDefs); 297 if (basedir != null && !propertyDefs.containsKey("basedir")) { propertyDefs.put("basedir", basedir.getAbsolutePath()); } 300 Map <String ,Element > macroDefs = new HashMap <String ,Element >(inheritedMacroDefs); 301 imports = new ArrayList <Script>(); 305 interpretTasks(alreadyImported, prj, basedir, propertyDefs, macroDefs, null); 306 } 307 308 private void interpretTasks(Set <File > alreadyImported, Element container, File basedir, Map <String ,String > propertyDefs, Map <String ,Element > macroDefs, Map <String ,String > macroParams) throws IOException { 309 NodeList nl = container.getChildNodes(); 311 int len = nl.getLength(); 312 for (int i = 0; i < len; i++) { 313 Node n = nl.item(i); 314 if (n.getNodeType() != Node.ELEMENT_NODE) { 315 continue; 316 } 317 Element el = (Element )n; 318 String elName = el.getLocalName(); 319 String fullname = elName; 320 String uri = el.getNamespaceURI(); 323 if (uri != null) { 324 fullname = uri + '#' + fullname; 325 } 326 Element macro = macroDefs.get(fullname); 327 if (macro != null) { 328 Map <String ,String > newMacroParams = new HashMap <String ,String >(); 329 NodeList macroKids = macro.getChildNodes(); 330 for (int j = 0; j < macroKids.getLength(); j++) { 331 if (macroKids.item(j).getNodeType() != Node.ELEMENT_NODE) { 332 continue; 333 } 334 Element el2 = (Element ) macroKids.item(j); 335 String elName2 = el2.getLocalName(); 336 if (elName2.equals("attribute")) { String attrName = el2.getAttribute("name"); if (attrName.length() == 0) { 339 continue; 340 } 341 String attrVal = el.getAttribute(attrName); 342 String attrValSubst = replaceAntProperties(attrVal, propertyDefs); 343 if (attrValSubst == null) { 344 continue; 345 } 346 newMacroParams.put(attrName, attrValSubst); 347 } else if (elName2.equals("sequential")) { interpretTasks(alreadyImported, el2, basedir, propertyDefs, macroDefs, newMacroParams); 349 } 350 } 351 } else if (macroParams == null && elName.equals("target")) { String name = el.getAttribute("name"); targets.put(name, new Target(this, el, name)); 354 } else if (macroParams == null && elName.equals("import")) { String fileS = el.getAttribute("file").replace('/', File.separatorChar).replace('\\', File.separatorChar); String fileSubstituted = replaceAntProperties(fileS, propertyDefs); 357 if (fileSubstituted.indexOf("${") != -1) { continue; 362 } 363 File _file = new File (fileSubstituted); 364 File file; 365 if (_file.isAbsolute()) { 366 file = _file; 367 } else { 368 if (apc.getFile() == null) { 369 continue; 372 } 373 file = new File (apc.getFile().getParentFile(), fileSubstituted); 375 } 376 if (alreadyImported.contains(file)) { 377 continue; 379 } 380 if (file.canRead()) { 381 FileObject fileObj = FileUtil.toFileObject(FileUtil.normalizeFile(file)); 382 assert fileObj != null : file; 383 AntProjectCookie importedApc = getAntProjectCookie(fileObj); 384 imports.add(new Script(this, importedApc, alreadyImported, propertyDefs, macroDefs)); 385 } else { 386 String optionalS = el.getAttribute("optional"); boolean optional = TRUE_VALS.contains(optionalS.toLowerCase(Locale.US)); 388 if (!optional) { 389 throw new IOException ("Cannot find import " + file + " from " + apc); } 391 } 392 } else if (elName.equals("property")) { if (el.hasAttribute("value")) { String name = replaceMacroParams(el.getAttribute("name"), macroParams); if (name.length() == 0) { 396 continue; 397 } 398 if (propertyDefs.containsKey(name)) { 399 continue; 400 } 401 String value = replaceMacroParams(el.getAttribute("value"), macroParams); String valueSubst = replaceAntProperties(value, propertyDefs); 403 propertyDefs.put(name, valueSubst); 404 continue; 405 } 406 String file = replaceMacroParams(el.getAttribute("file"), macroParams); if (file.length() > 0) { 408 String fileSubst = replaceAntProperties(file, propertyDefs); 409 File propertyFile = new File (fileSubst); 410 if (!propertyFile.isAbsolute() && basedir != null) { 411 propertyFile = new File (basedir, fileSubst.replace('/', File.separatorChar).replace('\\', File.separatorChar)); 412 } 413 if (!propertyFile.canRead()) { 414 continue; 416 } 417 Properties p = new Properties (); 418 InputStream is = new FileInputStream (propertyFile); 419 try { 420 p.load(is); 421 } finally { 422 is.close(); 423 } 424 Map <String ,String > evaluatedProperties = evaluateAll(propertyDefs, Collections.singletonList(NbCollections.checkedMapByFilter(p, String .class, String .class, true))); 425 if (evaluatedProperties == null) { 427 continue; 428 } 429 Iterator it = evaluatedProperties.entrySet().iterator(); 430 while (it.hasNext()) { 431 Map.Entry entry = (Map.Entry ) it.next(); 432 String k = (String ) entry.getKey(); 433 if (!propertyDefs.containsKey(k)) { 434 propertyDefs.put(k, (String ) entry.getValue()); 435 } 436 } 437 } 438 } else if (elName.equals("macrodef")) { String name = el.getAttribute("name"); 440 if (name.length() == 0) { 441 continue; 442 } 443 uri = el.getAttribute("uri"); if (uri.length() > 0) { 445 name = uri + '#' + name; 446 } 447 if (!macroDefs.containsKey(name)) { 448 macroDefs.put(name, el); 449 } 450 } 451 } 452 } 453 454 private static String replaceMacroParams(String rawval, Map <String ,String > defs) { 455 if (rawval.indexOf('@') == -1) { 456 return rawval; 458 } 459 int idx = 0; 460 StringBuffer val = new StringBuffer (); 461 while (true) { 462 int monkey = rawval.indexOf('@', idx); 463 if (monkey == -1 || monkey == rawval.length() - 1) { 464 val.append(rawval.substring(idx)); 465 return val.toString(); 466 } 467 char c = rawval.charAt(monkey + 1); 468 if (c == '{') { 469 int end = rawval.indexOf('}', monkey + 2); 470 if (end != -1) { 471 String otherprop = rawval.substring(monkey + 2, end); 472 if (defs.containsKey(otherprop)) { 473 val.append(rawval.substring(idx, monkey)); 474 val.append(defs.get(otherprop)); 475 } else { 476 val.append(rawval.substring(idx, end + 1)); 477 } 478 idx = end + 1; 479 } else { 480 val.append(rawval.substring(idx)); 481 return val.toString(); 482 } 483 } else { 484 val.append(rawval.substring(idx, idx + 2)); 485 idx += 2; 486 } 487 } 488 } 489 490 private static String replaceAntProperties(String rawval, Map <String ,String > defs) { 491 return subst(rawval, defs, Collections.<String >emptySet()).first(); 492 } 493 494 private static Map <String ,String > evaluateAll(Map <String ,String > predefs, List <Map <String ,String >> defs) { 496 Map <String ,String > m = new HashMap <String ,String >(predefs); 497 for (Map <String ,String > curr : defs) { 498 Map <String ,Set <String >> dependOnSiblings = new HashMap <String ,Set <String >>(); 500 for (Map.Entry <String ,String > entry : curr.entrySet()) { 501 String prop = entry.getKey(); 502 if (!m.containsKey(prop)) { 503 String rawval = entry.getValue(); 504 Union2<String ,Set <String >> r = subst(rawval, m, curr.keySet()); 506 if (r.hasFirst()) { 507 m.put(prop, r.first()); 508 } else { 509 dependOnSiblings.put(prop, r.second()); 510 } 511 } 512 } 513 Set <String > toSort = new HashSet <String >(dependOnSiblings.keySet()); 514 for (Set <String > sibs : dependOnSiblings.values()) { 515 toSort.addAll(sibs); 516 } 517 List <String > sorted; 518 try { 519 sorted = Utilities.topologicalSort(toSort, dependOnSiblings); 520 } catch (TopologicalSortException e) { 521 return null; 523 } 524 Collections.reverse(sorted); 525 for (String prop : sorted) { 526 if (!m.containsKey(prop)) { 527 String rawval = curr.get(prop); 528 m.put(prop, subst(rawval, m, curr.keySet()).first()); 529 } 530 } 531 } 532 return m; 533 } 534 private static Union2<String ,Set <String >> subst(String rawval, Map <String ,String > predefs, Set <String > siblingProperties) { 535 assert rawval != null : "null rawval passed in"; 536 if (rawval.indexOf('$') == -1) { 537 return Union2.createFirst(rawval); 540 } 541 int idx = 0; 543 StringBuffer val = new StringBuffer (); 545 Set <String > needed = new HashSet <String >(); 547 while (true) { 548 int shell = rawval.indexOf('$', idx); 549 if (shell == -1 || shell == rawval.length() - 1) { 550 if (needed.isEmpty()) { 553 val.append(rawval.substring(idx)); 554 return Union2.createFirst(val.toString()); 555 } else { 556 return Union2.createSecond(needed); 557 } 558 } 559 char c = rawval.charAt(shell + 1); 560 if (c == '$') { 561 if (needed.isEmpty()) { 564 val.append('$'); 565 } 566 idx += 2; 567 } else if (c == '{') { 568 int end = rawval.indexOf('}', shell + 2); 570 if (end != -1) { 571 String otherprop = rawval.substring(shell + 2, end); 573 if (predefs.containsKey(otherprop)) { 575 if (needed.isEmpty()) { 577 val.append(rawval.substring(idx, shell)); 578 val.append(predefs.get(otherprop)); 579 } 580 idx = end + 1; 581 } else if (siblingProperties.contains(otherprop)) { 582 needed.add(otherprop); 583 idx = end + 1; 585 } else { 586 if (needed.isEmpty()) { 588 val.append(rawval.substring(idx, end + 1)); 589 } 590 idx = end + 1; 591 } 592 } else { 593 if (needed.isEmpty()) { 595 val.append(rawval.substring(idx)); 596 return Union2.createFirst(val.toString()); 597 } else { 598 return Union2.createSecond(needed); 599 } 600 } 601 } else { 602 if (needed.isEmpty()) { 605 val.append(rawval.substring(idx, idx + 2)); 606 } 607 idx += 2; 608 } 609 } 610 } 611 612 613 public AntProjectCookie getScript() { 614 return apc; 615 } 616 617 618 public String getName() { 619 return name; 620 } 621 622 623 public Collection <Target> getTargets() { 624 return targets.values(); 625 } 626 627 628 public String getDefaultTargetName() { 629 return defaultTarget; 630 } 631 632 633 public Collection <Script> getImports() { 634 return imports; 635 } 636 637 638 public Script getImportingScript() { 639 return importingScript; 640 } 641 642 643 public Script getMainScript() { 644 if (importingScript != null) { 645 return importingScript.getMainScript(); 646 } else { 647 return this; 648 } 649 } 650 651 652 public boolean defines(String targetName) { 653 if (!targets.containsKey(targetName)) { 654 return false; 655 } 656 for (Script s = importingScript; s != null; s = s.importingScript) { 657 if (s.targets.containsKey(targetName)) { 658 return false; 659 } 660 } 661 return true; 662 } 663 664 } 665 666 669 static AntProjectCookie getAntProjectCookie(FileObject fo) { 670 try { 671 DataObject d = DataObject.find(fo); 672 AntProjectCookie apc = d.getCookie(AntProjectCookie.class); 673 if (apc != null) { 674 return apc; 675 } 676 } catch (DataObjectNotFoundException e) { 677 assert false : e; 678 } 679 synchronized (antProjectCookies) { 681 AntProjectCookie apc = antProjectCookies.get(fo); 682 if (apc == null) { 683 apc = new AntProjectSupport(fo); 684 antProjectCookies.put(fo, apc); 685 } 686 return apc; 687 } 688 } 689 private static final Map <FileObject,AntProjectCookie> antProjectCookies = new WeakHashMap <FileObject,AntProjectCookie>(); 690 691 } 692 | Popular Tags |