KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > spi > project > support > rake > ReferenceHelper


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.ruby.spi.project.support.rake;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.net.URI JavaDoc;
25 import java.net.URISyntaxException JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Arrays JavaDoc;
28 import java.util.Collection JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.Properties JavaDoc;
36 import java.util.Set JavaDoc;
37 import java.util.TreeSet JavaDoc;
38 import java.util.regex.Matcher JavaDoc;
39 import java.util.regex.Pattern JavaDoc;
40 import org.netbeans.api.project.Project;
41 import org.netbeans.api.project.ProjectManager;
42 import org.netbeans.api.project.ProjectUtils;
43 import org.netbeans.modules.ruby.api.project.rake.RakeArtifact;
44 import org.netbeans.modules.ruby.api.project.rake.RakeArtifactQuery;
45 import org.netbeans.api.queries.CollocationQuery;
46 import org.netbeans.modules.ruby.modules.project.rake.RakeBasedProjectFactorySingleton;
47 import org.netbeans.modules.ruby.modules.project.rake.Util;
48 import org.netbeans.spi.project.AuxiliaryConfiguration;
49 import org.netbeans.spi.project.SubprojectProvider;
50 import org.openide.ErrorManager;
51 import org.openide.filesystems.FileObject;
52 import org.openide.filesystems.FileUtil;
53 import org.openide.util.Mutex;
54 import org.openide.util.NbCollections;
55 import org.openide.xml.XMLUtil;
56 import org.w3c.dom.Document JavaDoc;
57 import org.w3c.dom.Element JavaDoc;
58 import org.w3c.dom.NodeList JavaDoc;
59
60 // XXX need a method to update non-key data in references e.g. during projectOpened()
61

62 /**
63  * Helps manage inter-project references.
64  * Normally you would create an instance of this object and keep it in your
65  * project object in order to support {@link SubprojectProvider} and various
66  * operations that change settings which might refer to build artifacts from
67  * other projects: e.g. when changing the classpath for a Java-based project
68  * you would want to use this helper to scan potential classpath entries for
69  * JARs coming from other projects that you would like to be able to build
70  * as dependencies before your project is built.
71  * <p>
72  * You probably only need the higher-level methods such as {@link #addReference}
73  * and {@link #removeReference(String,String)}; the lower-level methods such as {@link #addRawReference}
74  * are provided for completeness, but typical client code should not need them.
75  * <p>
76  * Only deals with references needed to support build artifacts coming from
77  * foreign projects. If for some reason you wish to store other kinds of
78  * references to foreign projects, you do not need this class; just store
79  * them however you wish, and be sure to create an appropriate {@link SubprojectProvider}.
80  * <p>
81  * Modification methods (add, remove) mark the project as modified but do not save it.
82  * @author Jesse Glick
83  */

84 public final class ReferenceHelper {
85     
86     /**
87      * XML element name used to store references in <code>project.xml</code>.
88      */

89     static final String JavaDoc REFS_NAME = "references"; // NOI18N
90

91     /**
92      * XML element name used to store one reference in <code>project.xml</code>.
93      */

94     static final String JavaDoc REF_NAME = "reference"; // NOI18N
95

96     /**
97      * XML namespace used to store references in <code>project.xml</code>.
98      */

99     static final String JavaDoc REFS_NS = "http://www.netbeans.org/ns/rake-project-references/1"; // NOI18N
100

101     /**
102      * Newer version of {@link #REFS_NS} supporting Properties and with changed semantics of <script>.
103      */

104     static final String JavaDoc REFS_NS2 = "http://www.netbeans.org/ns/rake-project-references/2"; // NOI18N
105

106     /** Set of property names which values can be used as additional base
107      * directories. */

108     private Set JavaDoc<String JavaDoc> extraBaseDirectories = new HashSet JavaDoc<String JavaDoc>();
109     
110     private final RakeProjectHelper h;
111     final PropertyEvaluator eval;
112     private final AuxiliaryConfiguration aux;
113
114     /**
115      * Create a new reference helper.
116      * It needs an {@link RakeProjectHelper} object in order to update references
117      * in <code>project.xml</code>,
118      * as well as set project or private properties referring to the locations
119      * of foreign projects on disk.
120      * <p>
121      * The property evaluator may be used in {@link #getForeignFileReferenceAsArtifact},
122      * {@link ReferenceHelper.RawReference#toRakeArtifact}, or
123      * {@link #createSubprojectProvider}. Typically this would
124      * be {@link RakeProjectHelper#getStandardPropertyEvaluator}. You can substitute
125      * a custom evaluator but be warned that this helper class assumes that
126      * {@link RakeProjectHelper#PROJECT_PROPERTIES_PATH} and {@link RakeProjectHelper#PRIVATE_PROPERTIES_PATH}
127      * have their customary meanings; specifically that they are both used when evaluating
128      * properties (such as the location of a foreign project) and that private properties
129      * can override public properties.
130      * @param helper an Ant project helper object representing this project's configuration
131      * @param aux an auxiliary configuration provider needed to store references
132      * @param eval a property evaluator
133      */

134     public ReferenceHelper(RakeProjectHelper helper, AuxiliaryConfiguration aux, PropertyEvaluator eval) {
135         h = helper;
136         this.aux = aux;
137         this.eval = eval;
138     }
139
140     /**
141      * Load <references> from project.xml.
142      * @return can return null if there are no references stored yet
143      */

144     private Element JavaDoc loadReferences() {
145         assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess();
146         Element JavaDoc references = aux.getConfigurationFragment(REFS_NAME, REFS_NS2, true);
147         if (references == null) {
148             references = aux.getConfigurationFragment(REFS_NAME, REFS_NS, true);
149         }
150         return references;
151     }
152
153     /**
154      * Store <references> to project.xml (i.e. to memory and mark project modified).
155      */

156     private void storeReferences(Element JavaDoc references) {
157         assert ProjectManager.mutex().isWriteAccess();
158         assert references != null && references.getLocalName().equals(REFS_NAME) &&
159             (REFS_NS.equals(references.getNamespaceURI()) || REFS_NS2.equals(references.getNamespaceURI()));
160         aux.putConfigurationFragment(references, true);
161     }
162     
163     private void removeOldReferences() {
164         assert ProjectManager.mutex().isWriteAccess();
165         aux.removeConfigurationFragment(REFS_NAME, REFS_NS, true);
166     }
167     
168     /**
169      * Add a reference to an artifact coming from a foreign project.
170      * <p>
171      * For more info see {@link #addReference(RakeArtifact, URI)}.
172      * @param artifact the artifact to add
173      * @return true if a reference or some property was actually added or modified,
174      * false if everything already existed and was not modified
175      * @throws IllegalArgumentException if the artifact is not associated with a project
176      * @deprecated to add reference use {@link #addReference(RakeArtifact, URI)};
177      * to check whether reference exist or not use {@link #isReferenced(RakeArtifact, URI)}.
178      * This method creates reference for the first artifact location only.
179      */

180     @Deprecated JavaDoc
181     public boolean addReference(final RakeArtifact artifact) throws IllegalArgumentException JavaDoc {
182         Object JavaDoc ret[] = addReference0(artifact, artifact.getArtifactLocations()[0]);
183         return ((Boolean JavaDoc)ret[0]).booleanValue();
184     }
185
186     // @return array of two elements: [Boolean - any modification, String - reference]
187
private Object JavaDoc[] addReference0(final RakeArtifact artifact, final URI JavaDoc location) throws IllegalArgumentException JavaDoc {
188         return ProjectManager.mutex().writeAccess(new Mutex.Action<Object JavaDoc[]>() {
189             public Object JavaDoc[] run() {
190                 int index = findLocationIndex(artifact, location);
191                 Project forProj = artifact.getProject();
192                 if (forProj == null) {
193                     throw new IllegalArgumentException JavaDoc("No project associated with " + artifact); // NOI18N
194
}
195                 // Set up the raw reference.
196
File JavaDoc forProjDir = FileUtil.toFile(forProj.getProjectDirectory());
197                 assert forProjDir != null : forProj.getProjectDirectory();
198                 String JavaDoc projName = getUsableReferenceID(ProjectUtils.getInformation(forProj).getName());
199                 String JavaDoc forProjName = findReferenceID(projName, "project.", forProjDir.getAbsolutePath());
200                 if (forProjName == null) {
201                     forProjName = generateUniqueID(projName, "project.", forProjDir.getAbsolutePath());
202                 }
203                 RawReference ref;
204                 File JavaDoc scriptFile = artifact.getScriptLocation();
205                 if (canUseVersion10(artifact, forProjDir)) {
206                     String JavaDoc rel = PropertyUtils.relativizeFile(forProjDir, scriptFile);
207                     URI JavaDoc scriptLocation;
208                     try {
209                         scriptLocation = new URI JavaDoc(null, null, rel, null);
210                     } catch (URISyntaxException JavaDoc ex) {
211                         scriptLocation = forProjDir.toURI().relativize(scriptFile.toURI());
212                     }
213                     ref = new RawReference(forProjName, artifact.getType(), scriptLocation, artifact.getTargetName(), artifact.getCleanTargetName(), artifact.getID());
214                 } else {
215                     String JavaDoc scriptLocation;
216                     if (scriptFile.getAbsolutePath().startsWith(forProjDir.getAbsolutePath())) {
217                         String JavaDoc rel = PropertyUtils.relativizeFile(forProjDir, scriptFile);
218                         assert rel != null : "Relativization must succeed for files: "+forProjDir+ " "+scriptFile;
219                         scriptLocation = "${project."+forProjName+"}/"+rel;
220                     } else {
221                         scriptLocation = "build.script.reference." + forProjName;
222                         setPathProperty(forProjDir, scriptFile, scriptLocation);
223                         scriptLocation = "${"+scriptLocation+"}";
224                     }
225                     ref = new RawReference(forProjName, artifact.getType(), scriptLocation,
226                         artifact.getTargetName(), artifact.getCleanTargetName(),
227                         artifact.getID(), artifact.getProperties());
228                 }
229                 boolean success = addRawReference0(ref);
230                 // Set up ${project.whatever}.
231
FileObject myProjDirFO = RakeBasedProjectFactorySingleton.getProjectFor(h).getProjectDirectory();
232                 File JavaDoc myProjDir = FileUtil.toFile(myProjDirFO);
233                 if (setPathProperty(myProjDir, forProjDir, "project." + forProjName)) {
234                     success = true;
235                 }
236                 // Set up ${reference.whatever.whatever}.
237
String JavaDoc propertiesFile;
238                 String JavaDoc forProjPathProp = "project." + forProjName; // NOI18N
239
URI JavaDoc artFile = location;
240                 String JavaDoc refPath;
241                 if (artFile.isAbsolute()) {
242                     refPath = new File JavaDoc(artFile).getAbsolutePath();
243                     propertiesFile = RakeProjectHelper.PRIVATE_PROPERTIES_PATH;
244                 } else {
245                     refPath = "${" + forProjPathProp + "}/" + artFile.getPath(); // NOI18N
246
propertiesFile = RakeProjectHelper.PROJECT_PROPERTIES_PATH;
247                 }
248                 EditableProperties props = h.getProperties(propertiesFile);
249                 String JavaDoc refPathProp = "reference." + forProjName + '.' + getUsableReferenceID(artifact.getID()); // NOI18N
250
if (index > 0) {
251                     refPathProp += "."+index;
252                 }
253                 if (!refPath.equals(props.getProperty(refPathProp))) {
254                     props.put(refPathProp, refPath);
255                     h.putProperties(propertiesFile, props);
256                     success = true;
257                 }
258                 return new Object JavaDoc[] {success, "${" + refPathProp + "}"}; // NOI18N
259
}
260         });
261     }
262     
263     private int findLocationIndex(final RakeArtifact artifact, final URI JavaDoc location) throws IllegalArgumentException JavaDoc {
264         if (location == null) {
265             throw new IllegalArgumentException JavaDoc("location cannot be null");
266         }
267         URI JavaDoc uris[] = artifact.getArtifactLocations();
268         for (int i=0; i<uris.length; i++) {
269             if (uris[i].equals(location)) {
270                 return i;
271             }
272         }
273         throw new IllegalArgumentException JavaDoc("location ("+location+") must be in RakeArtifact's locations ("+artifact+")");
274     }
275
276     /**
277      * Test whether the artifact can be stored as /1 artifact or not.
278      */

279     private static boolean canUseVersion10(RakeArtifact aa, File JavaDoc projectDirectory) {
280         // is there multiple outputs?
281
if (aa.getArtifactLocations().length > 1) {
282             return false;
283         }
284         // has some properties?
285
if (aa.getProperties().keySet().size() > 0) {
286             return false;
287         }
288         // does Ant script lies under project directory?
289
if (!aa.getScriptLocation().getAbsolutePath().startsWith(projectDirectory.getAbsolutePath())) {
290             return false;
291         }
292         return true;
293     }
294
295     /**
296      * Helper method which checks collocation status of two files and based on
297      * that it will in private or project properties file set up property with
298      * the given name and with absolute or relative path value.
299      * @return was there any change or not
300      */

301     private boolean setPathProperty(File JavaDoc base, File JavaDoc path, String JavaDoc propertyName) {
302         String JavaDoc[] values;
303         String JavaDoc[] propertiesFiles;
304         
305         String JavaDoc relativePath = relativizeFileToExtraBaseFolders(path);
306         // try relativize against external base dirs
307
if (relativePath != null) {
308             propertiesFiles = new String JavaDoc[] {
309                 RakeProjectHelper.PROJECT_PROPERTIES_PATH
310             };
311             values = new String JavaDoc[] {
312                 relativePath
313             };
314         }
315         else if (CollocationQuery.areCollocated(base, path)) {
316             // Fine, using a relative path to subproject.
317
relativePath = PropertyUtils.relativizeFile(base, path);
318             assert relativePath != null : "These dirs are not really collocated: " + base + " & " + path;
319             values = new String JavaDoc[] {
320                 relativePath,
321                 path.getAbsolutePath()
322             };
323             propertiesFiles = new String JavaDoc[] {
324                 RakeProjectHelper.PROJECT_PROPERTIES_PATH,
325                 RakeProjectHelper.PRIVATE_PROPERTIES_PATH,
326             };
327         } else {
328             // use an absolute path.
329
propertiesFiles = new String JavaDoc[] {
330                 RakeProjectHelper.PRIVATE_PROPERTIES_PATH
331             };
332             values = new String JavaDoc[] {
333                 path.getAbsolutePath()
334             };
335         }
336         
337         boolean metadataChanged = false;
338         for (int i=0; i<propertiesFiles.length; i++) {
339             EditableProperties props = h.getProperties(propertiesFiles[i]);
340             if (!values[i].equals(props.getProperty(propertyName))) {
341                 props.put(propertyName, values[i]);
342                 h.putProperties(propertiesFiles[i], props);
343                 metadataChanged = true;
344             }
345         }
346         
347         if (propertiesFiles.length == 1) {
348             // check presence of this property in opposite property file and
349
// remove it if necessary
350
String JavaDoc propertiesFile = (propertiesFiles[0] == RakeProjectHelper.PROJECT_PROPERTIES_PATH ?
351                 RakeProjectHelper.PRIVATE_PROPERTIES_PATH : RakeProjectHelper.PROJECT_PROPERTIES_PATH);
352             EditableProperties props = h.getProperties(propertiesFile);
353             if (props.remove(propertyName) != null) {
354                 h.putProperties(propertiesFile, props);
355             }
356         }
357         return metadataChanged;
358     }
359     
360     /**
361      * Add a reference to an artifact's location coming from a foreign project.
362      * <p>
363      * Records the name of the foreign project.
364      * Normally the foreign project name is that project's code name,
365      * but it may be uniquified if that name is already taken to refer
366      * to a different project with the same code name.
367      * <p>
368      * Adds a project property if necessary to refer to its location of the foreign
369      * project - a shared property if the foreign project
370      * is {@link CollocationQuery collocated} with this one, else a private property.
371      * This property is named <samp>project.<i>foreignProjectName</i></samp>.
372      * Example: <samp>project.mylib=../mylib</samp>
373      * <p>
374      * Adds a project property to refer to the artifact's location.
375      * This property is named <samp>reference.<i>foreignProjectName</i>.<i>targetName</i></samp>
376      * and will use <samp>${project.<i>foreignProjectName</i>}</samp> and be a shared
377      * property - unless the artifact location is an absolute URI, in which case the property
378      * will also be private.
379      * Example: <samp>reference.mylib.jar=${project.mylib}/dist/mylib.jar</samp>
380      * <p>
381      * Also records the artifact type, (relative) script path, and build and
382      * clean target names.
383      * <p>
384      * If the reference already exists (keyed by foreign project object
385      * and target name), nothing is done, unless some other field (script location,
386      * clean target name, or artifact type) needed to be updated, in which case
387      * the new information replaces the old. Similarly, the artifact location
388      * property is updated if necessary.
389      * <p>
390      * Acquires write access.
391      * @param artifact the artifact to add
392      * @param location the artifact's location to create reference to
393      * @return name of reference which was created or already existed
394      * @throws IllegalArgumentException if the artifact is not associated with a project
395      * or if the location is not artifact's location
396      * @since 1.5
397      */

398     public String JavaDoc addReference(final RakeArtifact artifact, URI JavaDoc location) throws IllegalArgumentException JavaDoc {
399         Object JavaDoc ret[] = addReference0(artifact, location);
400         return (String JavaDoc)ret[1];
401     }
402     
403     /**
404      * Tests whether reference for artifact's location was already created by
405      * {@link #addReference(RakeArtifact, URI)} for this project or not. This
406      * method returns false also in case when reference exist but needs to be
407      * updated.
408      * <p>
409      * Acquires read access.
410      * @param artifact the artifact to add
411      * @param location the artifact's location to create reference to
412      * @return true if already referenced
413      * @throws IllegalArgumentException if the artifact is not associated with a project
414      * or if the location is not artifact's location
415      * @since 1.5
416      */

417     public boolean isReferenced(final RakeArtifact artifact, final URI JavaDoc location) throws IllegalArgumentException JavaDoc {
418         return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean JavaDoc>() {
419             public Boolean JavaDoc run() {
420                 int index = findLocationIndex(artifact, location);
421                 Project forProj = artifact.getProject();
422                 if (forProj == null) {
423                     throw new IllegalArgumentException JavaDoc("No project associated with " + artifact); // NOI18N
424
}
425                 File JavaDoc forProjDir = FileUtil.toFile(forProj.getProjectDirectory());
426                 assert forProjDir != null : forProj.getProjectDirectory();
427                 String JavaDoc projName = getUsableReferenceID(ProjectUtils.getInformation(forProj).getName());
428                 String JavaDoc forProjName = findReferenceID(projName, "project.", forProjDir.getAbsolutePath());
429                 if (forProjName == null) {
430                     return false;
431                 }
432                 RawReference ref = getRawReference(forProjName, getUsableReferenceID(artifact.getID()));
433                 if (ref == null) {
434                     return false;
435                 }
436                 File JavaDoc script = h.resolveFile(eval.evaluate(ref.getScriptLocationValue()));
437                 if (!artifact.getType().equals(ref.getArtifactType()) ||
438                         !artifact.getID().equals(ref.getID()) ||
439                         !artifact.getScriptLocation().equals(script) ||
440                         !artifact.getProperties().equals(ref.getProperties()) ||
441                         !artifact.getTargetName().equals(ref.getTargetName()) ||
442                         !artifact.getCleanTargetName().equals(ref.getCleanTargetName())) {
443                     return false;
444                 }
445                 
446                 String JavaDoc reference = "reference." + forProjName + '.' + getUsableReferenceID(artifact.getID()); // NOI18N
447
if (index > 0) {
448                     reference += "."+index;
449                 }
450                 return eval.getProperty(reference) != null;
451             }
452         });
453     }
454     
455     /**
456      * Add a raw reference to a foreign project artifact.
457      * Does not check if such a project already exists; does not create a project
458      * property to refer to it; does not do any backreference usage notifications.
459      * <p>
460      * If the reference already exists (keyed by foreign project name and target name),
461      * nothing is done, unless some other field (script location, clean target name,
462      * or artifact type) needed to be updated, in which case the new information
463      * replaces the old.
464      * <p>
465      * Note that since {@link RawReference} is just a descriptor, it is not guaranteed
466      * that after adding one {@link #getRawReferences} or {@link #getRawReference}
467      * would return the identical object.
468      * <p>
469      * Acquires write access.
470      * @param ref a raw reference descriptor
471      * @return true if a reference was actually added or modified,
472      * false if it already existed and was not modified
473      */

474     public boolean addRawReference(final RawReference ref) {
475         return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean JavaDoc>() {
476             public Boolean JavaDoc run() {
477                 try {
478                     return addRawReference0(ref);
479                 } catch (IllegalArgumentException JavaDoc e) {
480                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
481                     return false;
482                 }
483             }
484         });
485     }
486     
487     private boolean addRawReference0(final RawReference ref) throws IllegalArgumentException JavaDoc {
488         Element JavaDoc references = loadReferences();
489         if (references == null) {
490             references = XMLUtil.createDocument("ignore", null, null, null).createElementNS(ref.getNS(), REFS_NAME); // NOI18N
491
}
492         boolean modified = false;
493         if (references.getNamespaceURI().equals(REFS_NS) && ref.getNS().equals(REFS_NS2)) {
494             // upgrade all references to version /2 here:
495
references = upgradeTo20(references);
496             removeOldReferences();
497             modified = true;
498         }
499         modified = updateRawReferenceElement(ref, references);
500         if (modified) {
501             storeReferences(references);
502         }
503         return modified;
504     }
505     
506     private Element JavaDoc upgradeTo20(Element JavaDoc references) {
507         Element JavaDoc references20 = XMLUtil.createDocument("ignore", null, null, null).createElementNS(REFS_NS2, REFS_NAME); // NOI18N
508
RawReference rr[] = getRawReferences(references);
509         for (int i=0; i<rr.length; i++) {
510             rr[i].upgrade();
511             updateRawReferenceElement(rr[i], references20);
512         }
513         return references20;
514     }
515     
516     private static boolean updateRawReferenceElement(RawReference ref, Element JavaDoc references) throws IllegalArgumentException JavaDoc {
517         // Linear search; always keeping references sorted first by foreign project
518
// name, then by target name.
519
Element JavaDoc nextRefEl = null;
520         Iterator JavaDoc<Element JavaDoc> it = Util.findSubElements(references).iterator();
521         while (it.hasNext()) {
522             Element JavaDoc testRefEl = it.next();
523             RawReference testRef = RawReference.create(testRefEl);
524             if (testRef.getForeignProjectName().compareTo(ref.getForeignProjectName()) > 0) {
525                 // gone too far, go back
526
nextRefEl = testRefEl;
527                 break;
528             }
529             if (testRef.getForeignProjectName().equals(ref.getForeignProjectName())) {
530                 if (testRef.getID().compareTo(ref.getID()) > 0) {
531                     // again, gone too far, go back
532
nextRefEl = testRefEl;
533                     break;
534                 }
535                 if (testRef.getID().equals(ref.getID())) {
536                     // Key match, check if it needs to be updated.
537
if (testRef.getArtifactType().equals(ref.getArtifactType()) &&
538                             testRef.getScriptLocationValue().equals(ref.getScriptLocationValue()) &&
539                             testRef.getProperties().equals(ref.getProperties()) &&
540                             testRef.getTargetName().equals(ref.getTargetName()) &&
541                             testRef.getCleanTargetName().equals(ref.getCleanTargetName())) {
542                         // Match on other fields. Return without changing anything.
543
return false;
544                     }
545                     // Something needs updating.
546
// Delete the old ref and set nextRef to the next item in line.
547
references.removeChild(testRefEl);
548                     if (it.hasNext()) {
549                         nextRefEl = it.next();
550                     } else {
551                         nextRefEl = null;
552                     }
553                     break;
554                 }
555             }
556         }
557         // Need to insert a new record before nextRef.
558
Element JavaDoc newRefEl = ref.toXml(references.getNamespaceURI(), references.getOwnerDocument());
559         // Note: OK if nextRefEl == null, that means insert as last child.
560
references.insertBefore(newRefEl, nextRefEl);
561         return true;
562     }
563     
564     /**
565      * Remove a reference to an artifact coming from a foreign project.
566      * <p>
567      * The property giving the location of the artifact is removed if it existed.
568      * <p>
569      * If this was the last reference to the foreign project, its location
570      * property is removed as well.
571      * <p>
572      * If the reference does not exist, nothing is done.
573      * <p>
574      * Acquires write access.
575      * @param foreignProjectName the local name of the foreign project
576      * (usually its code name)
577      * @param id the ID of the build artifact (usually build target name)
578      * @return true if a reference or some property was actually removed,
579      * false if the reference was not there and no property was removed
580      * @deprecated use {@link #destroyReference} instead; was unused anyway
581      */

582     @Deprecated JavaDoc
583     public boolean removeReference(final String JavaDoc foreignProjectName, final String JavaDoc id) {
584         return removeReference(foreignProjectName, id, false, null);
585     }
586     
587     /**
588      * Checks whether this is last reference and therefore the artifact can
589      * be removed from project.xml or not
590      */

591     private boolean isLastReference(String JavaDoc ref) {
592        Object JavaDoc ret[] = findArtifactAndLocation(ref);
593        if (ret[0] == null || ret[1] == null) {
594            return true;
595        }
596        RakeArtifact aa = (RakeArtifact)ret[0];
597        URI JavaDoc uri = (URI JavaDoc)ret[1];
598        URI JavaDoc uris[] = aa.getArtifactLocations();
599        boolean lastReference = true;
600        // are there any other referenced jars or not:
601
for (int i=0; i<uris.length; i++) {
602            if (uris[i].equals(uri)) {
603                continue;
604            }
605            if (isReferenced(aa, uris[i])) {
606                lastReference = false;
607                break;
608            }
609        }
610        return lastReference;
611     }
612     
613     private boolean removeReference(final String JavaDoc foreignProjectName, final String JavaDoc id, final boolean escaped, final String JavaDoc reference) {
614         return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean JavaDoc>() {
615             public Boolean JavaDoc run() {
616                 boolean success = false;
617                 try {
618                     if (isLastReference("${"+reference+"}")) {
619                         success = removeRawReference0(foreignProjectName, id, escaped);
620                     }
621                 } catch (IllegalArgumentException JavaDoc e) {
622                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
623                     return false;
624                 }
625                 // Note: try to delete obsoleted properties from both project.properties
626
// and private.properties, just in case.
627
String JavaDoc[] PROPS_PATHS = {
628                     RakeProjectHelper.PROJECT_PROPERTIES_PATH,
629                     RakeProjectHelper.PRIVATE_PROPERTIES_PATH,
630                 };
631                 // if raw reference was removed then try to clean also project reference property:
632
if (success) {
633                     // Check whether there are any other references using foreignProjectName.
634
// If not, we can delete ${project.foreignProjectName}.
635
RawReference[] refs = new RawReference[0];
636                     Element JavaDoc references = loadReferences();
637                     if (references != null) {
638                         refs = getRawReferences(references);
639                     }
640                     boolean deleteProjProp = true;
641                     for (int i = 0; i < refs.length; i++) {
642                         if (refs[i].getForeignProjectName().equals(foreignProjectName)) {
643                             deleteProjProp = false;
644                             break;
645                         }
646                     }
647                     if (deleteProjProp) {
648                         String JavaDoc projProp = "project." + foreignProjectName; // NOI18N
649
for (int i = 0; i < PROPS_PATHS.length; i++) {
650                             EditableProperties props = h.getProperties(PROPS_PATHS[i]);
651                             if (props.containsKey(projProp)) {
652                                 props.remove(projProp);
653                                 h.putProperties(PROPS_PATHS[i], props);
654                                 success = true;
655                             }
656                         }
657                     }
658                 }
659                 
660                 String JavaDoc refProp = reference;
661                 if (refProp == null) {
662                     refProp = "reference." + foreignProjectName + '.' + getUsableReferenceID(id); // NOI18N
663
}
664                 // remove also build script property if exist any:
665
String JavaDoc buildScriptProperty = "build.script.reference." + foreignProjectName;
666                 for (String JavaDoc path : PROPS_PATHS) {
667                     EditableProperties props = h.getProperties(path);
668                     if (props.containsKey(refProp)) {
669                         props.remove(refProp);
670                         h.putProperties(path, props);
671                         success = true;
672                     }
673                     if (props.containsKey(buildScriptProperty)) {
674                         props.remove(buildScriptProperty);
675                         h.putProperties(path, props);
676                         success = true;
677                     }
678                 }
679                 return success;
680             }
681         });
682     }
683     
684     /**
685      * Remove reference to a file.
686      * <p>
687      * If the reference does not exist, nothing is done.
688      * <p>
689      * Acquires write access.
690      * @param fileReference file reference as created by
691      * {@link #createForeignFileReference(File, String)}
692      * @return true if the reference was actually removed; otherwise false
693      * @deprecated use {@link #destroyReference} instead; was unused anyway
694      */

695     @Deprecated JavaDoc
696     public boolean removeReference(final String JavaDoc fileReference) {
697         return removeFileReference(fileReference);
698     }
699     
700     private boolean removeFileReference(final String JavaDoc fileReference) {
701         return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean JavaDoc>() {
702             public Boolean JavaDoc run() {
703                 boolean success = false;
704                 // Note: try to delete obsoleted properties from both project.properties
705
// and private.properties, just in case.
706
String JavaDoc[] PROPS_PATHS = {
707                     RakeProjectHelper.PROJECT_PROPERTIES_PATH,
708                     RakeProjectHelper.PRIVATE_PROPERTIES_PATH,
709                 };
710                 String JavaDoc refProp = fileReference;
711                 if (refProp.startsWith("${") && refProp.endsWith("}")) {
712                     refProp = refProp.substring(2, refProp.length()-1);
713                 }
714                 for (String JavaDoc path : PROPS_PATHS) {
715                     EditableProperties props = h.getProperties(path);
716                     if (props.containsKey(refProp)) {
717                         props.remove(refProp);
718                         h.putProperties(path, props);
719                         success = true;
720                     }
721                 }
722                 return success;
723             }
724         });
725     }
726     
727     /**
728      * Remove a raw reference to an artifact coming from a foreign project.
729      * Does not attempt to manipulate backreferences in the foreign project
730      * nor project properties.
731      * <p>
732      * If the reference does not exist, nothing is done.
733      * <p>
734      * Acquires write access.
735      * @param foreignProjectName the local name of the foreign project
736      * (usually its code name)
737      * @param id the ID of the build artifact (usually build target name)
738      * @return true if a reference was actually removed, false if it was not there
739      */

740     public boolean removeRawReference(final String JavaDoc foreignProjectName, final String JavaDoc id) {
741         return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean JavaDoc>() {
742             public Boolean JavaDoc run() {
743                 try {
744                     return removeRawReference0(foreignProjectName, id, false);
745                 } catch (IllegalArgumentException JavaDoc e) {
746                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
747                     return false;
748                 }
749             }
750         });
751     }
752     
753     private boolean removeRawReference0(final String JavaDoc foreignProjectName, final String JavaDoc id, boolean escaped) throws IllegalArgumentException JavaDoc {
754         Element JavaDoc references = loadReferences();
755         if (references == null) {
756             return false;
757         }
758         boolean success = removeRawReferenceElement(foreignProjectName, id, references, escaped);
759         if (success) {
760             storeReferences(references);
761         }
762         return success;
763     }
764     
765     private static boolean removeRawReferenceElement(String JavaDoc foreignProjectName, String JavaDoc id, Element JavaDoc references, boolean escaped) throws IllegalArgumentException JavaDoc {
766         // As with addRawReference, do a linear search through.
767
for (Element JavaDoc testRefEl : Util.findSubElements(references)) {
768             RawReference testRef = RawReference.create(testRefEl);
769             String JavaDoc refID = testRef.getID();
770             String JavaDoc refName = testRef.getForeignProjectName();
771             if (escaped) {
772                 refID = getUsableReferenceID(testRef.getID());
773                 refName = getUsableReferenceID(testRef.getForeignProjectName());
774             }
775             if (refName.compareTo(foreignProjectName) > 0) {
776                 // searched past it
777
return false;
778             }
779             if (refName.equals(foreignProjectName)) {
780                 if (refID.compareTo(id) > 0) {
781                     // again, searched past it
782
return false;
783                 }
784                 if (refID.equals(id)) {
785                     // Key match, remove it.
786
references.removeChild(testRefEl);
787                     return true;
788                 }
789             }
790         }
791         // Searched through to the end and did not find it.
792
return false;
793     }
794
795     /**
796      * Get a list of raw references from this project to others.
797      * If necessary, you may use {@link RawReference#toRakeArtifact} to get
798      * live information from each reference, such as its associated project.
799      * <p>
800      * Acquires read access.
801      * @return a (possibly empty) list of raw references from this project
802      */

803     public RawReference[] getRawReferences() {
804         return ProjectManager.mutex().readAccess(new Mutex.Action<RawReference[]>() {
805             public RawReference[] run() {
806                 Element JavaDoc references = loadReferences();
807                 if (references != null) {
808                     try {
809                         return getRawReferences(references);
810                     } catch (IllegalArgumentException JavaDoc e) {
811                         ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
812                     }
813                 }
814                 return new RawReference[0];
815             }
816         });
817     }
818     
819     private static RawReference[] getRawReferences(Element JavaDoc references) throws IllegalArgumentException JavaDoc {
820         List JavaDoc<Element JavaDoc> subEls = Util.findSubElements(references);
821         List JavaDoc<RawReference> refs = new ArrayList JavaDoc<RawReference>(subEls.size());
822         for (Element JavaDoc subEl : subEls) {
823             refs.add(RawReference.create(subEl));
824         }
825         return refs.toArray(new RawReference[refs.size()]);
826     }
827     
828     /**
829      * Get a particular raw reference from this project to another.
830      * If necessary, you may use {@link RawReference#toRakeArtifact} to get
831      * live information from each reference, such as its associated project.
832      * <p>
833      * Acquires read access.
834      * @param foreignProjectName the local name of the foreign project
835      * (usually its code name)
836      * @param id the ID of the build artifact (usually the build target name)
837      * @return the specified raw reference from this project,
838      * or null if none such could be found
839      */

840     public RawReference getRawReference(final String JavaDoc foreignProjectName, final String JavaDoc id) {
841         return getRawReference(foreignProjectName, id, false);
842     }
843     
844     // not private only to allow unit testing
845
RawReference getRawReference(final String JavaDoc foreignProjectName, final String JavaDoc id, final boolean escaped) {
846         return ProjectManager.mutex().readAccess(new Mutex.Action<RawReference>() {
847             public RawReference run() {
848                 Element JavaDoc references = loadReferences();
849                 if (references != null) {
850                     try {
851                         return getRawReference(foreignProjectName, id, references, escaped);
852                     } catch (IllegalArgumentException JavaDoc e) {
853                         ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
854                     }
855                 }
856                 return null;
857             }
858         });
859     }
860     
861     private static RawReference getRawReference(String JavaDoc foreignProjectName, String JavaDoc id, Element JavaDoc references, boolean escaped) throws IllegalArgumentException JavaDoc {
862         for (Element JavaDoc subEl : Util.findSubElements(references)) {
863             RawReference ref = RawReference.create(subEl);
864             String JavaDoc refID = ref.getID();
865             String JavaDoc refName = ref.getForeignProjectName();
866             if (escaped) {
867                 refID = getUsableReferenceID(ref.getID());
868                 refName = getUsableReferenceID(ref.getForeignProjectName());
869             }
870             if (refName.equals(foreignProjectName) && refID.equals(id)) {
871                 return ref;
872             }
873         }
874         return null;
875     }
876     
877     /**
878      * Create an Ant-interpretable string referring to a file on disk.
879      * If the file refers to a known Ant artifact according to
880      * {@link RakeArtifactQuery#findArtifactFromFile}, of the expected type
881      * and associated with a particular project,
882      * the behavior is identical to {@link #createForeignFileReference(RakeArtifact)}.
883      * Otherwise, a reference for the file is created. The file path will
884      * be relative in case {@link CollocationQuery#areCollocated} says that
885      * the file is collocated with this project's main directory, else it
886      * will be an absolute path.
887      * <p>
888      * Acquires write access.
889      * @param file a file to refer to (need not currently exist)
890      * @param expectedArtifactType the required {@link RakeArtifact#getType}
891      * @return a string which can refer to that file somehow
892      */

893     public String JavaDoc createForeignFileReference(final File JavaDoc file, final String JavaDoc expectedArtifactType) {
894         if (!file.equals(FileUtil.normalizeFile(file))) {
895             throw new IllegalArgumentException JavaDoc("Parameter file was not "+ // NOI18N
896
"normalized. Was "+file+" instead of "+FileUtil.normalizeFile(file)); // NOI18N
897
}
898         return ProjectManager.mutex().writeAccess(new Mutex.Action<String JavaDoc>() {
899             public String JavaDoc run() {
900                 RakeArtifact art = RakeArtifactQuery.findArtifactFromFile(file);
901                 if (art != null && art.getType().equals(expectedArtifactType) && art.getProject() != null) {
902                     try {
903                         return createForeignFileReference(art);
904                     } catch (IllegalArgumentException JavaDoc iae) {
905                         throw new AssertionError JavaDoc(iae);
906                     }
907                 } else {
908                     String JavaDoc propertiesFile;
909                     String JavaDoc path;
910                     File JavaDoc myProjDir = FileUtil.toFile(RakeBasedProjectFactorySingleton.getProjectFor(h).getProjectDirectory());
911                     String JavaDoc fileID = file.getName();
912                     // if the file is folder then add to ID string also parent folder name,
913
// i.e. if external source folder name is "src" the ID will
914
// be a bit more selfdescribing, e.g. project-src in case
915
// of ID for ant/project/src directory.
916
if (file.isDirectory() && file.getParentFile() != null) {
917                         fileID = file.getParentFile().getName()+"-"+file.getName();
918                     }
919                     fileID = PropertyUtils.getUsablePropertyName(fileID);
920                     String JavaDoc prop = findReferenceID(fileID, "file.reference.", file.getAbsolutePath()); // NOI18N
921
if (prop == null) {
922                         prop = generateUniqueID(fileID, "file.reference.", file.getAbsolutePath()); // NOI18N
923
}
924                     setPathProperty(myProjDir, file, "file.reference." + prop);
925                     return "${file.reference." + prop + '}'; // NOI18N
926
}
927             }
928         });
929     }
930     
931     /**
932      * Test whether file does not lie under an extra base folder and if it does
933      * then return string in form of "${extra.base}/remaining/path"; or null.
934      */

935     private String JavaDoc relativizeFileToExtraBaseFolders(File JavaDoc f) {
936         File JavaDoc base = FileUtil.toFile(h.getProjectDirectory());
937         String JavaDoc fileToRelativize = f.getAbsolutePath();
938         for (String JavaDoc prop : extraBaseDirectories) {
939             String JavaDoc path = eval.getProperty(prop);
940             File JavaDoc extraBase = PropertyUtils.resolveFile(base, path);
941             path = extraBase.getAbsolutePath();
942             if (!path.endsWith(File.separator)) {
943                 path += File.separator;
944             }
945             if (fileToRelativize.startsWith(path)) {
946                 return "${"+prop+"}/"+fileToRelativize.substring(path.length()).replace('\\', '/'); // NOI18N
947
}
948         }
949         return null;
950     }
951
952     /**
953      * Add extra folder which can be used as base directory (in addition to
954      * project base folder) for creating references. Duplicate property names
955      * are not allowed. Any newly created reference to a file lying under an
956      * extra base directory will be based on that property and will be stored in
957      * shared project properties.
958      * <p>Acquires write access.
959      * @param propertyName property name which value is path to folder which
960      * can be used as alternative project's base directory; cannot be null;
961      * property must exist
962      * @throws IllegalArgumentException if propertyName is null or such a
963      * property does not exist
964      * @since 1.4
965      */

966     public void addExtraBaseDirectory(final String JavaDoc propertyName) {
967         if (propertyName == null || eval.getProperty(propertyName) == null) {
968             throw new IllegalArgumentException JavaDoc("propertyName is null or such a property does not exist: "+propertyName); // NOI18N
969
}
970         ProjectManager.mutex().writeAccess(new Runnable JavaDoc() {
971                 public void run() {
972                     if (!extraBaseDirectories.add(propertyName)) {
973                         throw new IllegalArgumentException JavaDoc("Already extra base directory property: "+propertyName); // NOI18N
974
}
975                 }
976             });
977     }
978     
979     /**
980      * Remove extra base directory. The base directory property had to be added
981      * by {@link #addExtraBaseDirectory} method call. At the time when this
982      * method is called the property must still exist and must be valid. This
983      * method will replace all references of the extra base directory property
984      * with its current value and if needed it may move such a property from
985      * shared project properties into the private properties.
986      * <p>Acquires write access.
987      * @param propertyName property name which was added by
988      * {@link #addExtraBaseDirectory} method.
989      * @throws IllegalArgumentException if given property is not extra base
990      * directory
991      * @since 1.4
992      */

993     public void removeExtraBaseDirectory(final String JavaDoc propertyName) {
994         ProjectManager.mutex().writeAccess(new Runnable JavaDoc() {
995                 public void run() {
996                     if (!extraBaseDirectories.remove(propertyName)) {
997                         throw new IllegalArgumentException JavaDoc("Non-existing extra base directory property: "+propertyName); // NOI18N
998
}
999                     // substitute all references of removed extra base folder property with its value
1000
String JavaDoc tag = "${"+propertyName+"}"; // NOI18N
1001
// was extra base property defined in shared file or not:
1002
boolean shared = h.getProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH).containsKey(propertyName);
1003                    String JavaDoc value = eval.getProperty(propertyName);
1004                    EditableProperties propProj = h.getProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH);
1005                    EditableProperties propPriv = h.getProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH);
1006                    boolean modifiedProj = false;
1007                    boolean modifiedPriv = false;
1008                    Iterator JavaDoc<Map.Entry JavaDoc<String JavaDoc,String JavaDoc>> it = propProj.entrySet().iterator();
1009                    while (it.hasNext()) {
1010                        Map.Entry JavaDoc<String JavaDoc,String JavaDoc> entry = it.next();
1011                        String JavaDoc val = entry.getValue();
1012                        int index;
1013                        if ((index = val.indexOf(tag)) != -1) {
1014                            val = val.substring(0, index) +value + val.substring(index+tag.length());
1015                            if (shared) {
1016                                // substitute extra base folder property with its value
1017
entry.setValue(val);
1018                            } else {
1019                                // move property to private properties file
1020
it.remove();
1021                                propPriv.put(entry.getKey(), val);
1022                                modifiedPriv = true;
1023                            }
1024                            modifiedProj = true;
1025                        }
1026                    }
1027                    if (modifiedProj) {
1028                        h.putProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH, propProj);
1029                    }
1030                    if (modifiedPriv) {
1031                        h.putProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH, propPriv);
1032                    }
1033                }
1034            });
1035    }
1036    
1037    /**
1038     * Find reference ID (e.g. something you can then pass to RawReference
1039     * as foreignProjectName) for the given property base name, prefix and path.
1040     * @param property project name or jar filename
1041     * @param prefix prefix used for reference, i.e. "project." for project
1042     * reference or "file.reference." for file reference
1043     * @param path absolute filename the reference points to
1044     * @return found reference ID or null
1045     */

1046    private String JavaDoc findReferenceID(String JavaDoc property, String JavaDoc prefix, String JavaDoc path) {
1047        Map JavaDoc<String JavaDoc,String JavaDoc> m = h.getStandardPropertyEvaluator().getProperties();
1048        for (Map.Entry JavaDoc<String JavaDoc,String JavaDoc> e : m.entrySet()) {
1049            String JavaDoc key = e.getKey();
1050            if (key.startsWith(prefix+property)) {
1051                String JavaDoc v = h.resolvePath(e.getValue());
1052                if (path.equals(v)) {
1053                    return key.substring(prefix.length());
1054                }
1055            }
1056        }
1057        return null;
1058    }
1059    
1060    /**
1061     * Generate unique reference ID for the given property base name, prefix
1062     * and path. See also {@link #findReferenceID(String, String, String)}.
1063     * @param property project name or jar filename
1064     * @param prefix prefix used for reference, i.e. "project." for project
1065     * reference or "file.reference." for file reference
1066     * @param path absolute filename the reference points to
1067     * @return generated unique reference ID
1068     */

1069    private String JavaDoc generateUniqueID(String JavaDoc property, String JavaDoc prefix, String JavaDoc value) {
1070        PropertyEvaluator pev = h.getStandardPropertyEvaluator();
1071        if (pev.getProperty(prefix+property) == null) {
1072            return property;
1073        }
1074        int i = 1;
1075        while (pev.getProperty(prefix+property+"-"+i) != null) {
1076            i++;
1077        }
1078        return property+"-"+i;
1079    }
1080    
1081    /**
1082     * Create an Ant-interpretable string referring to a known build artifact file.
1083     * Simply calls {@link #addReference} and returns an Ant string which will
1084     * refer to that artifact correctly.
1085     * <p>
1086     * Acquires write access.
1087     * @param artifact a known build artifact to refer to
1088     * @return a string which can refer to that artifact file somehow
1089     * @throws IllegalArgumentException if the artifact is not associated with a project
1090     * @deprecated use {@link #addReference(RakeArtifact, URI)} instead
1091     */

1092    @Deprecated JavaDoc
1093    public String JavaDoc createForeignFileReference(RakeArtifact artifact) throws IllegalArgumentException JavaDoc {
1094        Object JavaDoc ret[] = addReference0(artifact, artifact.getArtifactLocations()[0]);
1095        return (String JavaDoc)ret[1];
1096    }
1097
1098    /**
1099     * Project reference ID cannot contain dot character.
1100     * File reference can.
1101     */

1102    private static String JavaDoc getUsableReferenceID(String JavaDoc ID) {
1103        return PropertyUtils.getUsablePropertyName(ID).replace('.', '_');
1104    }
1105    
1106    
1107    private static final Pattern JavaDoc FOREIGN_FILE_REFERENCE = Pattern.compile("\\$\\{reference\\.([^.${}]+)\\.([^.${}]+)\\.([\\d&&[^.${}]]+)\\}"); // NOI18N
1108
private static final Pattern JavaDoc FOREIGN_FILE_REFERENCE_OLD = Pattern.compile("\\$\\{reference\\.([^.${}]+)\\.([^.${}]+)\\}"); // NOI18N
1109
private static final Pattern JavaDoc FOREIGN_PLAIN_FILE_REFERENCE = Pattern.compile("\\$\\{file\\.reference\\.([^${}]+)\\}"); // NOI18N
1110

1111    /**
1112     * Try to find an <code>RakeArtifact</code> object corresponding to a given
1113     * foreign file reference.
1114     * If the supplied string is not a recognized reference to a build
1115     * artifact, returns null.
1116     * <p>Acquires read access.
1117     * @param reference a reference string as present in an Ant property
1118     * @return a corresponding Ant artifact object if there is one, else null
1119     * @deprecated use {@link #findArtifactAndLocation} instead
1120     */

1121    @Deprecated JavaDoc
1122    public RakeArtifact getForeignFileReferenceAsArtifact(final String JavaDoc reference) {
1123        Object JavaDoc ret[] = findArtifactAndLocation(reference);
1124        return (RakeArtifact)ret[0];
1125    }
1126    
1127    /**
1128     * Try to find an <code>RakeArtifact</code> object and location corresponding
1129     * to a given reference. If the supplied string is not a recognized
1130     * reference to a build artifact, returns null.
1131     * <p>
1132     * Acquires read access.
1133     * @param reference a reference string as present in an Ant property and as
1134     * created by {@link #addReference(RakeArtifact, URI)}
1135     * @return always returns array of two items. The items may be null. First
1136     * one is instance of RakeArtifact and second is instance of URI and is
1137     * RakeArtifact's location
1138     * @since 1.5
1139     */

1140    public Object JavaDoc[] findArtifactAndLocation(final String JavaDoc reference) {
1141        return ProjectManager.mutex().readAccess(new Mutex.Action<Object JavaDoc[]>() {
1142            public Object JavaDoc[] run() {
1143                RakeArtifact aa = null;
1144                Matcher JavaDoc m = FOREIGN_FILE_REFERENCE.matcher(reference);
1145                boolean matches = m.matches();
1146                int index = 0;
1147                if (!matches) {
1148                    m = FOREIGN_FILE_REFERENCE_OLD.matcher(reference);
1149                    matches = m.matches();
1150                } else {
1151                    try {
1152                        index = Integer.parseInt(m.group(3));
1153                    } catch (NumberFormatException JavaDoc ex) {
1154                        ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL,
1155                            "Could not parse reference ("+reference+") for the jar index. " + // NOI18N
1156
"Expected number: "+m.group(3)); // NOI18N
1157
matches = false;
1158                    }
1159                }
1160                if (matches) {
1161                    RawReference ref = getRawReference(m.group(1), m.group(2), true);
1162                    if (ref != null) {
1163                        aa = ref.toRakeArtifact(ReferenceHelper.this);
1164                    }
1165                }
1166                if (aa == null) {
1167                    return new Object JavaDoc[] {null, null};
1168                }
1169                if (index >= aa.getArtifactLocations().length) {
1170                    // #55413: we no longer have that many items...treat it as dead.
1171
return new Object JavaDoc[] {null, null};
1172                }
1173                URI JavaDoc uri = aa.getArtifactLocations()[index];
1174                return new Object JavaDoc[] {aa, uri};
1175            }
1176        });
1177    }
1178    
1179    /**
1180     * Remove a reference to a foreign file from the project.
1181     * See {@link #destroyReference} for more information.
1182     * @param reference an Ant-interpretable foreign file reference as created e.g.
1183     * by {@link #createForeignFileReference(File,String)} or
1184     * by {@link #createForeignFileReference(RakeArtifact)}
1185     * @deprecated use {@link #destroyReference} instead which does exactly
1186     * the same but has more appropriate name
1187     */

1188    @Deprecated JavaDoc
1189    public void destroyForeignFileReference(String JavaDoc reference) {
1190        destroyReference(reference);
1191    }
1192    
1193    /**
1194     * Remove a reference to a foreign file from the project.
1195     * If the passed string consists of an Ant property reference corresponding to
1196     * a known inter-project reference created by
1197     * {@link #addReference(RakeArtifact, URI)} or file reference created by
1198     * {@link #createForeignFileReference(File, String)}, that reference is removed.
1199     * Since this would break any other identical foreign
1200     * file references present in the project, you should first confirm that this
1201     * reference was the last one of its kind (by string match).
1202     * <p>
1203     * If the passed string is anything else (i.e. a plain file path, relative or
1204     * absolute), nothing is done.
1205     * <p>
1206     * Acquires write access.
1207     * @param reference an Ant-interpretable foreign file reference as created e.g.
1208     * by {@link #createForeignFileReference(File,String)} or
1209     * by {@link #createForeignFileReference(RakeArtifact)}
1210     * @return true if reference was really destroyed or not
1211     * @since 1.5
1212     */

1213    public boolean destroyReference(String JavaDoc reference) {
1214        Matcher JavaDoc m = FOREIGN_FILE_REFERENCE.matcher(reference);
1215        boolean matches = m.matches();
1216        if (!matches) {
1217            m = FOREIGN_FILE_REFERENCE_OLD.matcher(reference);
1218            matches = m.matches();
1219        }
1220        if (matches) {
1221            String JavaDoc forProjName = m.group(1);
1222            String JavaDoc id = m.group(2);
1223            return removeReference(forProjName, id, true, reference.substring(2, reference.length()-1));
1224        }
1225        m = FOREIGN_PLAIN_FILE_REFERENCE.matcher(reference);
1226        if (m.matches()) {
1227            return removeFileReference(reference);
1228        }
1229        return false;
1230    }
1231    
1232    /**
1233     * Create an object permitting this project to represent subprojects.
1234     * Would be placed into the project's lookup.
1235     * @return a subproject provider object suitable for the project lookup
1236     * @see Project#getLookup
1237     */

1238    public SubprojectProvider createSubprojectProvider() {
1239        return new SubprojectProviderImpl(this);
1240    }
1241    
1242    /**
1243     * Access from SubprojectProviderImpl.
1244     */

1245    RakeProjectHelper getRakeProjectHelper() {
1246        return h;
1247    }
1248    
1249    /**Tries to fix references after copy/rename/move operation on the project.
1250     * Handles relative/absolute paths.
1251     *
1252     * @param originalPath the project folder of the original project
1253     * @see org.netbeans.spi.project.CopyOperationImplementation
1254     * @see org.netbeans.spi.project.MoveOperationImplementation
1255     * @since 1.9
1256     */

1257    public void fixReferences(File JavaDoc originalPath) {
1258        String JavaDoc[] prefixesToFix = new String JavaDoc[] {"file.reference.", "project."};
1259        EditableProperties pub = h.getProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH);
1260        EditableProperties priv = h.getProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH);
1261        
1262        File JavaDoc projectDir = FileUtil.toFile(h.getProjectDirectory());
1263        
1264        List JavaDoc<String JavaDoc> pubRemove = new ArrayList JavaDoc<String JavaDoc>();
1265        List JavaDoc<String JavaDoc> privRemove = new ArrayList JavaDoc<String JavaDoc>();
1266        Map JavaDoc<String JavaDoc,String JavaDoc> pubAdd = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
1267        Map JavaDoc<String JavaDoc,String JavaDoc> privAdd = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
1268        
1269        for (Map.Entry JavaDoc<String JavaDoc,String JavaDoc> e : pub.entrySet()) {
1270            String JavaDoc key = e.getKey();
1271            boolean cont = false;
1272            
1273            for (String JavaDoc prefix : prefixesToFix) {
1274                if (key.startsWith(prefix)) {
1275                    cont = true;
1276                    break;
1277                }
1278            }
1279            if (!cont)
1280                continue;
1281            
1282            String JavaDoc value = e.getValue();
1283            
1284            File JavaDoc absolutePath = FileUtil.normalizeFile(PropertyUtils.resolveFile(originalPath, value));
1285            
1286            //TODO: extra base dir relativization:
1287
if (!CollocationQuery.areCollocated(absolutePath, projectDir)) {
1288                pubRemove.add(key);
1289                privAdd.put(key, absolutePath.getAbsolutePath());
1290            }
1291        }
1292        
1293        for (Map.Entry JavaDoc<String JavaDoc,String JavaDoc> e : pub.entrySet()) {
1294            String JavaDoc key = e.getKey();
1295            boolean cont = false;
1296            
1297            for (String JavaDoc prefix : prefixesToFix) {
1298                if (key.startsWith(prefix)) {
1299                    cont = true;
1300                    break;
1301                }
1302            }
1303            if (!cont)
1304                continue;
1305            
1306            String JavaDoc value = e.getValue();
1307            
1308            File JavaDoc absolutePath = FileUtil.normalizeFile(PropertyUtils.resolveFile(originalPath, value));
1309            
1310        if (absolutePath.getAbsolutePath().startsWith(originalPath.getAbsolutePath())) {
1311        //#65141: in private.properties, a full path into originalPath may be given, fix:
1312
String JavaDoc relative = PropertyUtils.relativizeFile(originalPath, absolutePath);
1313        
1314        absolutePath = new File JavaDoc(projectDir, relative);
1315        
1316        privRemove.add(key);
1317        privAdd.put(key, absolutePath.getAbsolutePath());
1318        }
1319        
1320            //TODO: extra base dir relativization:
1321
if (CollocationQuery.areCollocated(absolutePath, projectDir)) {
1322                pubAdd.put(key, PropertyUtils.relativizeFile(projectDir, absolutePath));
1323            }
1324        }
1325        
1326        for (String JavaDoc s : pubRemove) {
1327            pub.remove(s);
1328        }
1329        
1330        for (String JavaDoc s : privRemove) {
1331            priv.remove(s);
1332        }
1333        
1334        pub.putAll(pubAdd);
1335        priv.putAll(privAdd);
1336        
1337        h.putProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH, pub);
1338        h.putProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH, priv);
1339    }
1340    
1341    /**
1342     * A raw reference descriptor representing a link to a foreign project
1343     * and some build artifact used from it.
1344     * This class corresponds directly to what it stored in <code>project.xml</code>
1345     * to refer to a target in a foreign project.
1346     * See {@link RakeArtifact} for the precise meaning of several of the fields in this class.
1347     */

1348    public static final class RawReference {
1349        
1350        private final String JavaDoc foreignProjectName;
1351        private final String JavaDoc artifactType;
1352        private URI JavaDoc scriptLocation;
1353        // introduced in /2 version
1354
private String JavaDoc newScriptLocation;
1355        private final String JavaDoc targetName;
1356        private final String JavaDoc cleanTargetName;
1357        private final String JavaDoc artifactID;
1358        private final Properties JavaDoc props;
1359        
1360        /**
1361         * Create a raw reference descriptor.
1362         * As this is basically just a struct, does no real work.
1363         * @param foreignProjectName the name of the foreign project (usually its code name)
1364         * @param artifactType the {@link RakeArtifact#getType type} of the build artifact
1365         * @param scriptLocation the relative URI to the build script from the project directory
1366         * @param targetName the Ant target name
1367         * @param cleanTargetName the Ant clean target name
1368         * @param artifactID the {@link RakeArtifact#getID ID} of the build artifact
1369         * @throws IllegalArgumentException if the script location is given an absolute URI
1370         */

1371        public RawReference(String JavaDoc foreignProjectName, String JavaDoc artifactType, URI JavaDoc scriptLocation, String JavaDoc targetName, String JavaDoc cleanTargetName, String JavaDoc artifactID) throws IllegalArgumentException JavaDoc {
1372           this(foreignProjectName, artifactType, scriptLocation, null, targetName, cleanTargetName, artifactID, new Properties JavaDoc());
1373        }
1374        
1375        /**
1376         * Create a raw reference descriptor.
1377         * As this is basically just a struct, does no real work.
1378         * @param foreignProjectName the name of the foreign project (usually its code name)
1379         * @param artifactType the {@link RakeArtifact#getType type} of the build artifact
1380         * @param newScriptLocation absolute path to the build script; can contain Ant-like properties
1381         * @param targetName the Ant target name
1382         * @param cleanTargetName the Ant clean target name
1383         * @param artifactID the {@link RakeArtifact#getID ID} of the build artifact
1384         * @param props optional properties to be used for target execution; never null
1385         * @throws IllegalArgumentException if the script location is given an absolute URI
1386         * @since 1.5
1387         */

1388        public RawReference(String JavaDoc foreignProjectName, String JavaDoc artifactType, String JavaDoc newScriptLocation, String JavaDoc targetName, String JavaDoc cleanTargetName, String JavaDoc artifactID, Properties JavaDoc props) throws IllegalArgumentException JavaDoc {
1389           this(foreignProjectName, artifactType, null, newScriptLocation, targetName, cleanTargetName, artifactID, props);
1390        }
1391        
1392        private RawReference(String JavaDoc foreignProjectName, String JavaDoc artifactType, URI JavaDoc scriptLocation, String JavaDoc newScriptLocation, String JavaDoc targetName, String JavaDoc cleanTargetName, String JavaDoc artifactID, Properties JavaDoc props) throws IllegalArgumentException JavaDoc {
1393            this.foreignProjectName = foreignProjectName;
1394            this.artifactType = artifactType;
1395            if (scriptLocation != null && scriptLocation.isAbsolute()) {
1396                throw new IllegalArgumentException JavaDoc("Cannot use an absolute URI " + scriptLocation + " for script location"); // NOI18N
1397
}
1398            this.scriptLocation = scriptLocation;
1399            this.newScriptLocation = newScriptLocation;
1400            this.targetName = targetName;
1401            this.cleanTargetName = cleanTargetName;
1402            this.artifactID = artifactID;
1403            this.props = props;
1404        }
1405        
1406        private static final List JavaDoc/*<String>*/ SUB_ELEMENT_NAMES = Arrays.asList(new String JavaDoc[] {
1407            "foreign-project", // NOI18N
1408
"artifact-type", // NOI18N
1409
"script", // NOI18N
1410
"target", // NOI18N
1411
"clean-target", // NOI18N
1412
"id", // NOI18N
1413
});
1414        
1415        /**
1416         * Create a RawReference by parsing an XML &lt;reference&gt; fragment.
1417         * @throws IllegalArgumentException if anything is missing or duplicated or malformed etc.
1418         */

1419        static RawReference create(Element JavaDoc xml) throws IllegalArgumentException JavaDoc {
1420            if (REFS_NS.equals(xml.getNamespaceURI())) {
1421                return create1(xml);
1422            } else {
1423                return create2(xml);
1424            }
1425        }
1426        
1427        private static RawReference create1(Element JavaDoc xml) throws IllegalArgumentException JavaDoc {
1428            if (!REF_NAME.equals(xml.getLocalName()) || !REFS_NS.equals(xml.getNamespaceURI())) {
1429                throw new IllegalArgumentException JavaDoc("bad element name: " + xml); // NOI18N
1430
}
1431            NodeList JavaDoc nl = xml.getElementsByTagNameNS("*", "*"); // NOI18N
1432
if (nl.getLength() != 6) {
1433                throw new IllegalArgumentException JavaDoc("missing or extra data: " + xml); // NOI18N
1434
}
1435            String JavaDoc[] values = new String JavaDoc[nl.getLength()];
1436            for (int i = 0; i < nl.getLength(); i++) {
1437                Element JavaDoc el = (Element JavaDoc)nl.item(i);
1438                if (!REFS_NS.equals(el.getNamespaceURI())) {
1439                    throw new IllegalArgumentException JavaDoc("bad subelement ns: " + el); // NOI18N
1440
}
1441                String JavaDoc elName = el.getLocalName();
1442                int idx = SUB_ELEMENT_NAMES.indexOf(elName);
1443                if (idx == -1) {
1444                    throw new IllegalArgumentException JavaDoc("bad subelement name: " + elName); // NOI18N
1445
}
1446                String JavaDoc val = Util.findText(el);
1447                if (val == null) {
1448                    throw new IllegalArgumentException JavaDoc("empty subelement: " + el); // NOI18N
1449
}
1450                if (values[idx] != null) {
1451                    throw new IllegalArgumentException JavaDoc("duplicate " + elName + ": " + values[idx] + " and " + val); // NOI18N
1452
}
1453                values[idx] = val;
1454            }
1455            assert !Arrays.asList(values).contains(null);
1456            URI JavaDoc scriptLocation = URI.create(values[2]); // throws IllegalArgumentException
1457
return new RawReference(values[0], values[1], scriptLocation, values[3], values[4], values[5]);
1458        }
1459        
1460        private static RawReference create2(Element JavaDoc xml) throws IllegalArgumentException JavaDoc {
1461            if (!REF_NAME.equals(xml.getLocalName()) || !REFS_NS2.equals(xml.getNamespaceURI())) {
1462                throw new IllegalArgumentException JavaDoc("bad element name: " + xml); // NOI18N
1463
}
1464            List JavaDoc nl = Util.findSubElements(xml);
1465            if (nl.size() < 6) {
1466                throw new IllegalArgumentException JavaDoc("missing or extra data: " + xml); // NOI18N
1467
}
1468            String JavaDoc[] values = new String JavaDoc[6];
1469            for (int i = 0; i < 6; i++) {
1470                Element JavaDoc el = (Element JavaDoc)nl.get(i);
1471                if (!REFS_NS2.equals(el.getNamespaceURI())) {
1472                    throw new IllegalArgumentException JavaDoc("bad subelement ns: " + el); // NOI18N
1473
}
1474                String JavaDoc elName = el.getLocalName();
1475                int idx = SUB_ELEMENT_NAMES.indexOf(elName);
1476                if (idx == -1) {
1477                    throw new IllegalArgumentException JavaDoc("bad subelement name: " + elName); // NOI18N
1478
}
1479                String JavaDoc val = Util.findText(el);
1480                if (val == null) {
1481                    throw new IllegalArgumentException JavaDoc("empty subelement: " + el); // NOI18N
1482
}
1483                if (values[idx] != null) {
1484                    throw new IllegalArgumentException JavaDoc("duplicate " + elName + ": " + values[idx] + " and " + val); // NOI18N
1485
}
1486                values[idx] = val;
1487            }
1488            Properties JavaDoc props = new Properties JavaDoc();
1489            if (nl.size() == 7) {
1490                Element JavaDoc el = (Element JavaDoc)nl.get(6);
1491                if (!REFS_NS2.equals(el.getNamespaceURI())) {
1492                    throw new IllegalArgumentException JavaDoc("bad subelement ns: " + el); // NOI18N
1493
}
1494                if (!"properties".equals(el.getLocalName())) { // NOI18N
1495
throw new IllegalArgumentException JavaDoc("bad subelement. expected 'properties': " + el); // NOI18N
1496
}
1497                for (Element JavaDoc el2 : Util.findSubElements(el)) {
1498                    String JavaDoc key = el2.getAttribute("name");
1499                    String JavaDoc value = Util.findText(el2);
1500                    // #53553: NPE
1501
if (value == null) {
1502                        value = ""; // NOI18N
1503
}
1504                    props.setProperty(key, value);
1505                }
1506            }
1507            assert !Arrays.asList(values).contains(null);
1508            return new RawReference(values[0], values[1], values[2], values[3], values[4], values[5], props);
1509        }
1510        
1511        /**
1512         * Write a RawReference as an XML &lt;reference&gt; fragment.
1513         */

1514        Element JavaDoc toXml(String JavaDoc namespace, Document JavaDoc ownerDocument) {
1515            Element JavaDoc el = ownerDocument.createElementNS(namespace, REF_NAME);
1516            String JavaDoc[] values = {
1517                foreignProjectName,
1518                artifactType,
1519                newScriptLocation != null ? newScriptLocation : scriptLocation.toString(),
1520                targetName,
1521                cleanTargetName,
1522                artifactID,
1523            };
1524            for (int i = 0; i < 6; i++) {
1525                Element JavaDoc subel = ownerDocument.createElementNS(namespace, (String JavaDoc)SUB_ELEMENT_NAMES.get(i));
1526                subel.appendChild(ownerDocument.createTextNode(values[i]));
1527                el.appendChild(subel);
1528            }
1529            if (props.keySet().size() > 0) {
1530                assert namespace.equals(REFS_NS2) : "can happen only in /2"; // NOI18N
1531
Element JavaDoc propEls = ownerDocument.createElementNS(namespace, "properties"); // NOI18N
1532
el.appendChild(propEls);
1533                for (String JavaDoc key : new TreeSet JavaDoc<String JavaDoc>(NbCollections.checkedSetByFilter(props.keySet(), String JavaDoc.class, true))) {
1534                    Element JavaDoc propEl = ownerDocument.createElementNS(namespace, "property"); // NOI18N
1535
propEl.appendChild(ownerDocument.createTextNode(props.getProperty(key)));
1536                    propEl.setAttribute("name", key); // NOI18N
1537
propEls.appendChild(propEl);
1538                }
1539            }
1540            return el;
1541        }
1542        
1543        private String JavaDoc getNS() {
1544            if (newScriptLocation != null) {
1545                return REFS_NS2;
1546            } else {
1547                return REFS_NS;
1548            }
1549        }
1550        
1551        /**
1552         * Get the name of the foreign project as referred to from this project.
1553         * Usually this will be the code name of the foreign project, but it may
1554         * instead be a uniquified name.
1555         * The name can be used in project properties and the build script to refer
1556         * to the foreign project from among subprojects.
1557         * @return the foreign project name
1558         */

1559        public String JavaDoc getForeignProjectName() {
1560            return foreignProjectName;
1561        }
1562        
1563        /**
1564         * Get the type of the foreign project's build artifact.
1565         * For example, <a HREF="@JAVA/PROJECT@/org/netbeans/api/java/project/JavaProjectConstants.html#ARTIFACT_TYPE_JAR"><code>JavaProjectConstants.ARTIFACT_TYPE_JAR</code></a>.
1566         * @return the artifact type
1567         */

1568        public String JavaDoc getArtifactType() {
1569            return artifactType;
1570        }
1571        
1572        /**
1573         * Get the location of the foreign project's build script relative to the
1574         * project directory.
1575         * This is the script which would be called to build the desired artifact.
1576         * @return the script location
1577         * @deprecated use {@link #getScriptLocationValue} instead; may return null now
1578         */

1579        @Deprecated JavaDoc
1580        public URI JavaDoc getScriptLocation() {
1581            return scriptLocation;
1582        }
1583        
1584        /**
1585         * Get absolute path location of the foreign project's build script.
1586         * This is the script which would be called to build the desired artifact.
1587         * @return absolute path possibly containing Ant properties
1588         */

1589        public String JavaDoc getScriptLocationValue() {
1590            if (newScriptLocation != null) {
1591                return newScriptLocation;
1592            } else {
1593                return "${project."+foreignProjectName+"}/"+scriptLocation.toString();
1594            }
1595        }
1596        
1597        /**
1598         * Get the Ant target name to build the artifact.
1599         * @return the target name
1600         */

1601        public String JavaDoc getTargetName() {
1602            return targetName;
1603        }
1604        
1605        /**
1606         * Get the Ant target name to clean the artifact.
1607         * @return the clean target name
1608         */

1609        public String JavaDoc getCleanTargetName() {
1610            return cleanTargetName;
1611        }
1612        
1613        /**
1614         * Get the ID of the foreign project's build artifact.
1615         * See also {@link RakeArtifact#getID}.
1616         * @return the artifact identifier
1617         */

1618        public String JavaDoc getID() {
1619            return artifactID;
1620        }
1621        
1622        public Properties JavaDoc getProperties() {
1623            return props;
1624        }
1625        
1626        /**
1627         * Attempt to convert this reference to a live artifact object.
1628         * This involves finding the referenced foreign project on disk
1629         * (among standard project and private properties) and asking it
1630         * for the artifact named by the given target.
1631         * Given that object, you can find important further information
1632         * such as the location of the actual artifact on disk.
1633         * <p>
1634         * Note that non-key attributes of the returned artifact (i.e.
1635         * type, script location, and clean target name) might not match
1636         * those in this raw reference.
1637         * <p>
1638         * Acquires read access.
1639         * @param helper an associated reference helper used to resolve the foreign
1640         * project location
1641         * @return the actual Ant artifact object, or null if it could not be located
1642         */

1643        public RakeArtifact toRakeArtifact(final ReferenceHelper helper) {
1644            return ProjectManager.mutex().readAccess(new Mutex.Action<RakeArtifact>() {
1645                public RakeArtifact run() {
1646                    RakeProjectHelper h = helper.h;
1647                    String JavaDoc path = helper.eval.getProperty("project." + foreignProjectName); // NOI18N
1648
if (path == null) {
1649                        // Undefined foreign project.
1650
return null;
1651                    }
1652                    FileObject foreignProjectDir = h.resolveFileObject(path);
1653                    if (foreignProjectDir == null) {
1654                        // Nonexistent foreign project dir.
1655
return null;
1656                    }
1657                    Project p;
1658                    try {
1659                        p = ProjectManager.getDefault().findProject(foreignProjectDir);
1660                    } catch (IOException JavaDoc e) {
1661                        // Could not load it.
1662
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
1663                        return null;
1664                    }
1665                    if (p == null) {
1666                        // Was not a project dir.
1667
return null;
1668                    }
1669                    return RakeArtifactQuery.findArtifactByID(p, artifactID);
1670                }
1671            });
1672        }
1673        
1674        private void upgrade() {
1675            assert newScriptLocation == null && scriptLocation != null : "was already upgraded "+this;
1676            newScriptLocation = "${project."+foreignProjectName+"}/" +scriptLocation.toString(); // NOI18N
1677
scriptLocation = null;
1678        }
1679        
1680        public String JavaDoc toString() {
1681            return "ReferenceHelper.RawReference<" + foreignProjectName + "," +
1682                artifactType + "," + newScriptLocation != null ? newScriptLocation : scriptLocation +
1683                "," + targetName + "," + cleanTargetName + "," + artifactID + ">"; // NOI18N
1684
}
1685        
1686    }
1687    
1688}
1689
Popular Tags