1 19 20 package org.netbeans.spi.project.support.ant; 21 22 import java.io.ByteArrayOutputStream ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.io.OutputStream ; 26 import java.util.ArrayList ; 27 import java.util.HashSet ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Set ; 31 import javax.xml.parsers.DocumentBuilder ; 32 import javax.xml.parsers.DocumentBuilderFactory ; 33 import javax.xml.parsers.ParserConfigurationException ; 34 import org.netbeans.api.project.Project; 35 import org.netbeans.api.project.ProjectManager; 36 import org.netbeans.api.project.ant.AntArtifact; 37 import org.netbeans.modules.project.ant.AntBasedProjectFactorySingleton; 38 import org.netbeans.modules.project.ant.FileChangeSupport; 39 import org.netbeans.modules.project.ant.FileChangeSupportEvent; 40 import org.netbeans.modules.project.ant.FileChangeSupportListener; 41 import org.netbeans.modules.project.ant.UserQuestionHandler; 42 import org.netbeans.modules.project.ant.Util; 43 import org.netbeans.spi.project.AuxiliaryConfiguration; 44 import org.netbeans.spi.project.CacheDirectoryProvider; 45 import org.netbeans.spi.project.ProjectState; 46 import org.netbeans.spi.queries.FileBuiltQueryImplementation; 47 import org.netbeans.spi.queries.SharabilityQueryImplementation; 48 import org.openide.ErrorManager; 49 import org.openide.filesystems.FileLock; 50 import org.openide.filesystems.FileObject; 51 import org.openide.filesystems.FileSystem; 52 import org.openide.filesystems.FileUtil; 53 import org.openide.util.Mutex; 54 import org.openide.util.MutexException; 55 import org.openide.util.RequestProcessor; 56 import org.openide.util.UserQuestionException; 57 import org.openide.xml.XMLUtil; 58 import org.w3c.dom.Document ; 59 import org.w3c.dom.Element ; 60 import org.w3c.dom.Node ; 61 import org.w3c.dom.NodeList ; 62 import org.xml.sax.InputSource ; 63 import org.xml.sax.SAXException ; 64 65 69 public final class AntProjectHelper { 70 71 74 public static final String PROJECT_PROPERTIES_PATH = "nbproject/project.properties"; 76 79 public static final String PRIVATE_PROPERTIES_PATH = "nbproject/private/private.properties"; 81 84 public static final String PROJECT_XML_PATH = AntBasedProjectFactorySingleton.PROJECT_XML_PATH; 85 86 89 public static final String PRIVATE_XML_PATH = "nbproject/private/private.xml"; 91 94 static final String PROJECT_NS = AntBasedProjectFactorySingleton.PROJECT_NS; 95 96 99 static final String PRIVATE_NS = "http://www.netbeans.org/ns/project-private/1"; 101 static { 102 AntBasedProjectFactorySingleton.HELPER_CALLBACK = new AntBasedProjectFactorySingleton.AntProjectHelperCallback() { 103 public AntProjectHelper createHelper(FileObject dir, Document projectXml, ProjectState state, AntBasedProjectType type) { 104 return new AntProjectHelper(dir, projectXml, state, type); 105 } 106 public void save(AntProjectHelper helper) throws IOException { 107 helper.save(); 108 } 109 }; 110 } 111 112 private static final RequestProcessor RP = new RequestProcessor("AntProjectHelper.RP"); 114 117 private final FileObject dir; 118 119 122 private final ProjectState state; 123 124 127 private final AntBasedProjectType type; 128 129 133 private Document projectXml; 134 135 139 private Document privateXml; 140 141 147 private final Set <String > modifiedMetadataPaths = new HashSet <String >(); 148 149 153 private final RequestProcessor.Task clearUnmodifiedMetadataTask; 154 private static final int CLEAR_UNMODIFIED_METADATA_TIMEOUT = 15000; 155 156 160 private final List <AntProjectListener> listeners = new ArrayList <AntProjectListener>(); 161 162 165 private final ProjectProperties properties; 166 167 168 private final FileChangeSupportListener fileListener; 169 170 171 private boolean writingXML = false; 172 173 176 private ProjectXmlSavedHook pendingHook; 177 182 private int pendingHookCount; 183 184 187 private AntProjectHelper(FileObject dir, Document projectXml, ProjectState state, AntBasedProjectType type) { 188 this.dir = dir; 189 assert dir != null && FileUtil.toFile(dir) != null; 190 this.state = state; 191 assert state != null; 192 this.type = type; 193 assert type != null; 194 this.projectXml = projectXml; 195 assert projectXml != null; 196 properties = new ProjectProperties(this); 197 fileListener = new FileListener(); 198 FileChangeSupport.DEFAULT.addListener(fileListener, resolveFile(PROJECT_XML_PATH)); 199 FileChangeSupport.DEFAULT.addListener(fileListener, resolveFile(PRIVATE_XML_PATH)); 200 clearUnmodifiedMetadataTask = RP.post(new Runnable () { 201 public void run() { 202 synchronized (modifiedMetadataPaths) { 203 if (modifiedMetadataPaths.isEmpty()) { 204 AntProjectHelper.this.projectXml = null; 205 privateXml = null; 206 properties.clear(); 207 } 208 } 209 } 210 }, CLEAR_UNMODIFIED_METADATA_TIMEOUT); 211 } 212 213 216 AntBasedProjectType getType() { 217 return type; 218 } 219 220 224 private Document getConfigurationXml(boolean shared) { 225 assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); 226 assert Thread.holdsLock(modifiedMetadataPaths); 227 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 228 Document xml = shared ? projectXml : privateXml; 229 if (xml == null) { 230 String path = shared ? PROJECT_XML_PATH : PRIVATE_XML_PATH; 231 xml = loadXml(path); 232 if (xml == null) { 233 String element = shared ? "project" : "project-private"; String ns = shared ? PROJECT_NS : PRIVATE_NS; 236 xml = XMLUtil.createDocument(element, ns, null, null); 237 if (shared) { 238 Element typeEl = xml.createElementNS(PROJECT_NS, "type"); typeEl.appendChild(xml.createTextNode(getType().getType())); 241 xml.getDocumentElement().appendChild(typeEl); 242 xml.getDocumentElement().appendChild(xml.createElementNS(PROJECT_NS, "configuration")); } 244 } 245 if (shared) { 246 projectXml = xml; 247 } else { 248 privateXml = xml; 249 } 250 } 251 assert xml != null; 252 return xml; 253 } 254 255 259 static boolean QUIETLY_SWALLOW_XML_LOAD_ERRORS = false; 260 261 265 private Document loadXml(String path) { 266 assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); 267 assert Thread.holdsLock(modifiedMetadataPaths); 268 FileObject xml = dir.getFileObject(path); 269 if (xml == null || !xml.isData()) { 270 return null; 271 } 272 File f = FileUtil.toFile(xml); 273 assert f != null; 274 try { 275 return XMLUtil.parse(new InputSource (f.toURI().toString()), false, true, Util.defaultErrorHandler(), null); 276 } catch (IOException e) { 277 if (!QUIETLY_SWALLOW_XML_LOAD_ERRORS) { 278 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 279 } 280 } catch (SAXException e) { 281 if (!QUIETLY_SWALLOW_XML_LOAD_ERRORS) { 282 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 283 } 284 } 285 return null; 286 } 287 288 292 private FileLock saveXml(final Document doc, final String path) throws IOException { 293 assert ProjectManager.mutex().isWriteAccess(); 294 assert !writingXML; 295 assert Thread.holdsLock(modifiedMetadataPaths); 296 final FileLock[] _lock = new FileLock[1]; 297 writingXML = true; 298 try { 299 dir.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 300 public void run() throws IOException { 301 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 303 XMLUtil.write(doc, baos, "UTF-8"); final byte[] data = baos.toByteArray(); 305 final FileObject xml = FileUtil.createData(dir, path); 306 try { 307 _lock[0] = xml.lock(); OutputStream os = xml.getOutputStream(_lock[0]); 309 try { 310 os.write(data); 311 } finally { 312 os.close(); 313 } 314 } catch (UserQuestionException uqe) { needPendingHook(); 316 UserQuestionHandler.handle(uqe, new UserQuestionHandler.Callback() { 317 public void accepted() { 318 assert !writingXML; 320 writingXML = true; 321 try { 322 FileLock lock = xml.lock(); 323 try { 324 OutputStream os = xml.getOutputStream(lock); 325 try { 326 os.write(data); 327 } finally { 328 os.close(); 329 } 330 } finally { 331 lock.releaseLock(); 332 } 333 maybeCallPendingHook(); 334 } catch (IOException e) { 335 ErrorManager.getDefault().notify(e); 337 reload(); 338 } finally { 339 writingXML = false; 340 } 341 } 342 public void denied() { 343 reload(); 344 } 345 public void error(IOException e) { 346 ErrorManager.getDefault().notify(e); 347 reload(); 348 } 349 private void reload() { 350 if (path.equals(PROJECT_XML_PATH)) { 352 synchronized (modifiedMetadataPaths) { 353 projectXml = null; 354 } 355 } else { 356 assert path.equals(PRIVATE_XML_PATH) : path; 357 synchronized (modifiedMetadataPaths) { 358 privateXml = null; 359 } 360 } 361 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 362 fireExternalChange(path); 363 cancelPendingHook(); 364 } 365 }); 366 } 367 } 368 }); 369 } finally { 370 writingXML = false; 371 } 372 return _lock[0]; 373 } 374 375 382 private Element getConfigurationDataRoot(boolean shared) { 383 assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); 384 assert Thread.holdsLock(modifiedMetadataPaths); 385 Document doc = getConfigurationXml(shared); 386 if (shared) { 387 Element project = doc.getDocumentElement(); 388 Element config = Util.findElement(project, "configuration", PROJECT_NS); assert config != null; 390 return config; 391 } else { 392 return doc.getDocumentElement(); 393 } 394 } 395 396 401 public void addAntProjectListener(AntProjectListener listener) { 402 synchronized (listeners) { 403 listeners.add(listener); 404 } 405 } 406 407 412 public void removeAntProjectListener(AntProjectListener listener) { 413 synchronized (listeners) { 414 listeners.remove(listener); 415 } 416 } 417 418 423 void fireExternalChange(final String path) { 424 final Mutex.Action<Void > action = new Mutex.Action<Void >() { 425 public Void run() { 426 fireChange(path, false); 427 return null; 428 } 429 }; 430 if (ProjectManager.mutex().isWriteAccess()) { 431 ProjectManager.mutex().readAccess(action); 433 } else if (ProjectManager.mutex().isReadAccess()) { 434 action.run(); 436 } else { 437 RP.post(new Runnable () { 439 public void run() { 440 ProjectManager.mutex().readAccess(action); 441 } 442 }); 443 } 444 } 445 446 452 private void fireChange(String path, boolean expected) { 453 assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); 454 final AntProjectListener[] _listeners; 455 synchronized (listeners) { 456 if (listeners.isEmpty()) { 457 return; 458 } 459 _listeners = listeners.toArray(new AntProjectListener[listeners.size()]); 460 } 461 final AntProjectEvent ev = new AntProjectEvent(this, path, expected); 462 final boolean xml = path.equals(PROJECT_XML_PATH) || path.equals(PRIVATE_XML_PATH); 463 ProjectManager.mutex().readAccess(new Mutex.Action<Void >() { 464 public Void run() { 465 for (AntProjectListener l : _listeners) { 466 try { 467 if (xml) { 468 l.configurationXmlChanged(ev); 469 } else { 470 l.propertiesChanged(ev); 471 } 472 } catch (RuntimeException e) { 473 ErrorManager.getDefault().notify(e); 475 } 476 } 477 return null; 478 } 479 }); 480 } 481 482 485 private void modifying(String path) { 486 assert ProjectManager.mutex().isWriteAccess(); 487 state.markModified(); 488 synchronized (modifiedMetadataPaths) { 489 modifiedMetadataPaths.add(path); 490 } 491 fireChange(path, true); 492 } 493 494 498 public FileObject getProjectDirectory() { 499 return dir; 500 } 501 502 507 public void notifyDeleted() { 508 state.notifyDeleted(); 509 } 510 511 512 516 void markModified() { 517 assert ProjectManager.mutex().isWriteAccess(); 518 state.markModified(); 519 synchronized (modifiedMetadataPaths) { 521 modifiedMetadataPaths.add(PROJECT_XML_PATH); 522 } 523 } 524 525 530 boolean isProjectXmlModified() { 531 assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); 532 return modifiedMetadataPaths.contains(PROJECT_XML_PATH); 533 } 534 535 541 private void save() throws IOException { 542 assert ProjectManager.mutex().isWriteAccess(); 543 Set <FileLock> locks = new HashSet <FileLock>(); 544 try { 545 synchronized (modifiedMetadataPaths) { 546 assert !modifiedMetadataPaths.isEmpty(); 547 assert pendingHook == null; 548 if (modifiedMetadataPaths.contains(PROJECT_XML_PATH)) { 549 Project p = AntBasedProjectFactorySingleton.getProjectFor(this); 551 pendingHook = p.getLookup().lookup(ProjectXmlSavedHook.class); 552 } 554 Iterator <String > it = modifiedMetadataPaths.iterator(); 555 while (it.hasNext()) { 556 String path = it.next(); 557 if (path.equals(PROJECT_XML_PATH)) { 558 assert projectXml != null; 559 locks.add(saveXml(projectXml, path)); 560 } else if (path.equals(PRIVATE_XML_PATH)) { 561 assert privateXml != null; 562 locks.add(saveXml(privateXml, path)); 563 } else { 564 locks.add(properties.write(path)); 566 } 567 it.remove(); 569 } 570 if (pendingHook != null && pendingHookCount == 0) { 571 try { 572 pendingHook.projectXmlSaved(); 573 } catch (IOException e) { 574 modifiedMetadataPaths.add(PROJECT_XML_PATH); 576 throw e; 577 } 578 } 579 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 580 } 581 } finally { 582 locks.remove(null); 584 for (FileLock lock : locks) { 585 lock.releaseLock(); 586 } 587 if (pendingHookCount == 0) { 589 pendingHook = null; 590 } 591 } 592 } 593 594 595 void maybeCallPendingHook() { 596 assert pendingHookCount > 0; 598 pendingHookCount--; 599 if (pendingHookCount == 0 && pendingHook != null) { 602 try { 603 ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void >() { 604 public Void run() throws IOException { 605 pendingHook.projectXmlSaved(); 606 return null; 607 } 608 }); 609 } catch (MutexException e) { 610 ErrorManager.getDefault().notify(e); 612 } finally { 613 pendingHook = null; 614 } 615 } 616 } 617 void cancelPendingHook() { 618 assert pendingHookCount > 0; 619 pendingHookCount--; 620 if (pendingHookCount == 0) { 621 pendingHook = null; 622 } 623 } 624 void needPendingHook() { 625 pendingHookCount++; 626 } 627 628 638 public EditableProperties getProperties(final String path) { 639 if (path.equals(AntProjectHelper.PROJECT_XML_PATH) || path.equals(AntProjectHelper.PRIVATE_XML_PATH)) { 640 throw new IllegalArgumentException ("Attempt to load properties from a project XML file"); } 642 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 643 return ProjectManager.mutex().readAccess(new Mutex.Action<EditableProperties>() { 644 public EditableProperties run() { 645 return properties.getProperties(path); 646 } 647 }); 648 } 649 650 666 public void putProperties(final String path, final EditableProperties props) { 667 if (path.equals(AntProjectHelper.PROJECT_XML_PATH) || path.equals(AntProjectHelper.PRIVATE_XML_PATH)) { 668 throw new IllegalArgumentException ("Attempt to store properties from a project XML file"); } 670 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 671 ProjectManager.mutex().writeAccess(new Mutex.Action<Void >() { 672 public Void run() { 673 if (properties.putProperties(path, props)) { 674 modifying(path); 675 } 676 return null; 677 } 678 }); 679 } 680 681 689 public PropertyProvider getPropertyProvider(final String path) { 690 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 691 if (path.equals(AntProjectHelper.PROJECT_XML_PATH) || path.equals(AntProjectHelper.PRIVATE_XML_PATH)) { 692 throw new IllegalArgumentException ("Attempt to store properties from a project XML file"); } 694 return ProjectManager.mutex().readAccess(new Mutex.Action<PropertyProvider>() { 695 public PropertyProvider run() { 696 return properties.getPropertyProvider(path); 697 } 698 }); 699 } 700 701 714 public Element getPrimaryConfigurationData(final boolean shared) { 715 final String name = type.getPrimaryConfigurationDataElementName(shared); 716 assert name.indexOf(':') == -1; 717 final String namespace = type.getPrimaryConfigurationDataElementNamespace(shared); 718 assert namespace != null && namespace.length() > 0; 719 return ProjectManager.mutex().readAccess(new Mutex.Action<Element >() { 720 public Element run() { 721 synchronized (modifiedMetadataPaths) { 722 Element el = getConfigurationFragment(name, namespace, shared); 723 if (el != null) { 724 return el; 725 } else { 726 return cloneSafely(getConfigurationXml(shared).createElementNS(namespace, name)); 728 } 729 } 730 } 731 }); 732 } 733 734 750 public void putPrimaryConfigurationData(Element data, boolean shared) throws IllegalArgumentException { 751 String name = type.getPrimaryConfigurationDataElementName(shared); 752 assert name.indexOf(':') == -1; 753 String namespace = type.getPrimaryConfigurationDataElementNamespace(shared); 754 assert namespace != null && namespace.length() > 0; 755 if (!name.equals(data.getLocalName()) || !namespace.equals(data.getNamespaceURI())) { 756 throw new IllegalArgumentException ("Wrong name/namespace: expected {" + namespace + "}" + name + " but was {" + data.getNamespaceURI() + "}" + data.getLocalName()); } 758 putConfigurationFragment(data, shared); 759 } 760 761 private final class FileListener implements FileChangeSupportListener { 762 763 public FileListener() {} 764 765 private void change(File f) { 766 if (writingXML) { 767 return; 768 } 769 String path; 770 synchronized (modifiedMetadataPaths) { 771 if (f.equals(resolveFile(PROJECT_XML_PATH))) { 772 if (modifiedMetadataPaths.contains(PROJECT_XML_PATH)) { 773 return ; 775 } 776 path = PROJECT_XML_PATH; 777 projectXml = null; 778 } else if (f.equals(resolveFile(PRIVATE_XML_PATH))) { 779 if (modifiedMetadataPaths.contains(PRIVATE_XML_PATH)) { 780 return ; 782 } 783 path = PRIVATE_XML_PATH; 784 privateXml = null; 785 } else { 786 throw new AssertionError ("Unexpected file change in " + f); } 788 } 789 fireExternalChange(path); 790 } 791 792 public void fileCreated(FileChangeSupportEvent event) { 793 change(event.getPath()); 794 } 795 796 public void fileDeleted(FileChangeSupportEvent event) { 797 change(event.getPath()); 798 } 799 800 public void fileModified(FileChangeSupportEvent event) { 801 change(event.getPath()); 802 } 803 804 } 805 806 813 Element getConfigurationFragment(final String elementName, final String namespace, final boolean shared) { 814 return ProjectManager.mutex().readAccess(new Mutex.Action<Element >() { 815 public Element run() { 816 synchronized (modifiedMetadataPaths) { 817 Element root = getConfigurationDataRoot(shared); 818 Element data = Util.findElement(root, elementName, namespace); 819 if (data != null) { 820 return cloneSafely(data); 821 } else { 822 return null; 823 } 824 } 825 } 826 }); 827 } 828 829 private static final DocumentBuilder db; 830 static { 831 try { 832 db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 833 } catch (ParserConfigurationException e) { 834 throw new AssertionError (e); 835 } 836 } 837 private static Element cloneSafely(Element el) { 838 synchronized (db) { 841 Document dummy = db.newDocument(); 842 return (Element ) dummy.importNode(el, true); 843 } 844 } 845 846 851 void putConfigurationFragment(final Element fragment, final boolean shared) { 852 ProjectManager.mutex().writeAccess(new Mutex.Action<Void >() { 853 public Void run() { 854 synchronized (modifiedMetadataPaths) { 855 Element root = getConfigurationDataRoot(shared); 856 Element existing = Util.findElement(root, fragment.getLocalName(), fragment.getNamespaceURI()); 857 if (existing != null) { 859 root.removeChild(existing); 860 } 861 Node ref = null; 863 NodeList list = root.getChildNodes(); 864 for (int i=0; i<list.getLength(); i++) { 865 Node node = list.item(i); 866 if (node.getNodeType() != Node.ELEMENT_NODE) { 867 continue; 868 } 869 int comparison = node.getNodeName().compareTo(fragment.getNodeName()); 870 if (comparison == 0) { 871 comparison = node.getNamespaceURI().compareTo(fragment.getNamespaceURI()); 872 } 873 if (comparison > 0) { 874 ref = node; 875 break; 876 } 877 } 878 root.insertBefore(root.getOwnerDocument().importNode(fragment, true), ref); 879 modifying(shared ? PROJECT_XML_PATH : PRIVATE_XML_PATH); 880 } 881 return null; 882 } 883 }); 884 } 885 886 893 boolean removeConfigurationFragment(final String elementName, final String namespace, final boolean shared) { 894 return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean >() { 895 public Boolean run() { 896 synchronized (modifiedMetadataPaths) { 897 Element root = getConfigurationDataRoot(shared); 898 Element data = Util.findElement(root, elementName, namespace); 899 if (data != null) { 900 root.removeChild(data); 901 modifying(shared ? PROJECT_XML_PATH : PRIVATE_XML_PATH); 902 return true; 903 } else { 904 return false; 905 } 906 } 907 } 908 }); 909 } 910 911 916 public AuxiliaryConfiguration createAuxiliaryConfiguration() { 917 return new ExtensibleMetadataProviderImpl(this); 918 } 919 920 925 public CacheDirectoryProvider createCacheDirectoryProvider() { 926 return new ExtensibleMetadataProviderImpl(this); 927 } 928 929 972 public FileBuiltQueryImplementation createGlobFileBuiltQuery(PropertyEvaluator eval, String [] from, String [] to) throws IllegalArgumentException { 973 return new GlobFileBuiltQuery(this, eval, from, to); 974 } 975 976 989 public AntArtifact createSimpleAntArtifact(String type, String locationProperty, PropertyEvaluator eval, String targetName, String cleanTargetName) { 990 return new SimpleAntArtifact(this, type, locationProperty, eval, targetName, cleanTargetName); 991 } 992 993 1057 public SharabilityQueryImplementation createSharabilityQuery(PropertyEvaluator eval, String [] sourceRoots, String [] buildDirectories) { 1058 String [] includes = new String [sourceRoots.length + 1]; 1059 System.arraycopy(sourceRoots, 0, includes, 0, sourceRoots.length); 1060 includes[sourceRoots.length] = ""; String [] excludes = new String [buildDirectories.length + 1]; 1062 System.arraycopy(buildDirectories, 0, excludes, 0, buildDirectories.length); 1063 excludes[buildDirectories.length] = "nbproject/private"; return new SharabilityQueryImpl(this, eval, includes, excludes); 1065 } 1066 1067 1074 public PropertyProvider getStockPropertyPreprovider() { 1075 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 1076 return properties.getStockPropertyPreprovider(); 1077 } 1078 1079 1089 public PropertyEvaluator getStandardPropertyEvaluator() { 1090 clearUnmodifiedMetadataTask.schedule(CLEAR_UNMODIFIED_METADATA_TIMEOUT); 1091 return properties.getStandardPropertyEvaluator(); 1092 } 1093 1094 1100 public File resolveFile(String filename) { 1101 if (filename == null) { 1102 throw new NullPointerException ("Attempted to pass a null filename to resolveFile"); } 1104 return PropertyUtils.resolveFile(FileUtil.toFile(dir), filename); 1105 } 1106 1107 1112 public FileObject resolveFileObject(String filename) { 1113 if (filename == null) { 1114 throw new NullPointerException ("Must pass a non-null filename"); } 1116 return PropertyUtils.resolveFileObject(dir, filename); 1117 } 1118 1119 1126 public String resolvePath(String path) { 1127 if (path == null) { 1128 throw new NullPointerException ("Must pass a non-null path"); } 1130 return PropertyUtils.resolvePath(FileUtil.toFile(dir), path); 1132 } 1133 1134 public String toString() { 1135 return "AntProjectHelper[" + getProjectDirectory() + "]"; } 1137 1138} 1139 | Popular Tags |