Source Code Cross Referenced for ReferenceHelper.java in  » IDE-Netbeans » project.ant » org » netbeans » spi » project » support » ant » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » project.ant » org.netbeans.spi.project.support.ant 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.netbeans.spi.project.support.ant;
0043:
0044:        import java.io.File;
0045:        import java.io.IOException;
0046:        import java.net.MalformedURLException;
0047:        import java.net.URI;
0048:        import java.net.URISyntaxException;
0049:        import java.util.ArrayList;
0050:        import java.util.Arrays;
0051:        import java.util.HashMap;
0052:        import java.util.HashSet;
0053:        import java.util.Iterator;
0054:        import java.util.List;
0055:        import java.util.Map;
0056:        import java.util.Properties;
0057:        import java.util.Set;
0058:        import java.util.TreeSet;
0059:        import java.util.logging.Logger;
0060:        import java.util.regex.Matcher;
0061:        import java.util.regex.Pattern;
0062:        import org.netbeans.api.project.Project;
0063:        import org.netbeans.api.project.ProjectManager;
0064:        import org.netbeans.api.project.ProjectUtils;
0065:        import org.netbeans.api.project.ant.AntArtifact;
0066:        import org.netbeans.api.project.ant.AntArtifactQuery;
0067:        import org.netbeans.api.project.libraries.Library;
0068:        import org.netbeans.api.project.libraries.LibraryChooser;
0069:        import org.netbeans.api.project.libraries.LibraryManager;
0070:        import org.netbeans.api.queries.CollocationQuery;
0071:        import org.netbeans.modules.project.ant.AntBasedProjectFactorySingleton;
0072:        import org.netbeans.modules.project.ant.ProjectLibraryProvider;
0073:        import org.netbeans.modules.project.ant.Util;
0074:        import org.netbeans.spi.project.AuxiliaryConfiguration;
0075:        import org.netbeans.spi.project.SubprojectProvider;
0076:        import org.openide.ErrorManager;
0077:        import org.openide.filesystems.FileObject;
0078:        import org.openide.filesystems.FileUtil;
0079:        import org.openide.util.Mutex;
0080:        import org.openide.util.NbCollections;
0081:        import org.openide.util.Parameters;
0082:        import org.openide.xml.XMLUtil;
0083:        import org.w3c.dom.Document;
0084:        import org.w3c.dom.Element;
0085:        import org.w3c.dom.NodeList;
0086:
0087:        // XXX need a method to update non-key data in references e.g. during projectOpened()
0088:
0089:        /**
0090:         * Helps manage inter-project references.
0091:         * Normally you would create an instance of this object and keep it in your
0092:         * project object in order to support {@link SubprojectProvider} and various
0093:         * operations that change settings which might refer to build artifacts from
0094:         * other projects: e.g. when changing the classpath for a Java-based project
0095:         * you would want to use this helper to scan potential classpath entries for
0096:         * JARs coming from other projects that you would like to be able to build
0097:         * as dependencies before your project is built.
0098:         * <p>
0099:         * You probably only need the higher-level methods such as {@link #addReference}
0100:         * and {@link #removeReference(String,String)}; the lower-level methods such as {@link #addRawReference}
0101:         * are provided for completeness, but typical client code should not need them.
0102:         * <p>
0103:         * Only deals with references needed to support build artifacts coming from
0104:         * foreign projects. If for some reason you wish to store other kinds of
0105:         * references to foreign projects, you do not need this class; just store
0106:         * them however you wish, and be sure to create an appropriate {@link SubprojectProvider}.
0107:         * <p>
0108:         * Modification methods (add, remove) mark the project as modified but do not save it.
0109:         * @author Jesse Glick
0110:         */
0111:        public final class ReferenceHelper {
0112:
0113:            /**
0114:             * XML element name used to store references in <code>project.xml</code>.
0115:             */
0116:            static final String REFS_NAME = "references"; // NOI18N
0117:
0118:            /**
0119:             * XML element name used to store one reference in <code>project.xml</code>.
0120:             */
0121:            static final String REF_NAME = "reference"; // NOI18N
0122:
0123:            /**
0124:             * XML namespace used to store references in <code>project.xml</code>.
0125:             */
0126:            static final String REFS_NS = "http://www.netbeans.org/ns/ant-project-references/1"; // NOI18N
0127:
0128:            /**
0129:             * Newer version of {@link #REFS_NS} supporting Properties and with changed semantics of <script>.
0130:             */
0131:            static final String REFS_NS2 = "http://www.netbeans.org/ns/ant-project-references/2"; // NOI18N
0132:
0133:            /** Set of property names which values can be used as additional base
0134:             * directories. */
0135:            private Set<String> extraBaseDirectories = new HashSet<String>();
0136:
0137:            private final AntProjectHelper h;
0138:            final PropertyEvaluator eval;
0139:            private final AuxiliaryConfiguration aux;
0140:
0141:            /**
0142:             * Create a new reference helper.
0143:             * It needs an {@link AntProjectHelper} object in order to update references
0144:             * in <code>project.xml</code>,
0145:             * as well as set project or private properties referring to the locations
0146:             * of foreign projects on disk.
0147:             * <p>
0148:             * The property evaluator may be used in {@link #getForeignFileReferenceAsArtifact},
0149:             * {@link ReferenceHelper.RawReference#toAntArtifact}, or
0150:             * {@link #createSubprojectProvider}. Typically this would
0151:             * be {@link AntProjectHelper#getStandardPropertyEvaluator}. You can substitute
0152:             * a custom evaluator but be warned that this helper class assumes that
0153:             * {@link AntProjectHelper#PROJECT_PROPERTIES_PATH} and {@link AntProjectHelper#PRIVATE_PROPERTIES_PATH}
0154:             * have their customary meanings; specifically that they are both used when evaluating
0155:             * properties (such as the location of a foreign project) and that private properties
0156:             * can override public properties.
0157:             * @param helper an Ant project helper object representing this project's configuration
0158:             * @param aux an auxiliary configuration provider needed to store references
0159:             * @param eval a property evaluator
0160:             */
0161:            public ReferenceHelper(AntProjectHelper helper,
0162:                    AuxiliaryConfiguration aux, PropertyEvaluator eval) {
0163:                h = helper;
0164:                this .aux = aux;
0165:                this .eval = eval;
0166:            }
0167:
0168:            /**
0169:             * Load <references> from project.xml.
0170:             * @return can return null if there are no references stored yet
0171:             */
0172:            private Element loadReferences() {
0173:                assert ProjectManager.mutex().isReadAccess()
0174:                        || ProjectManager.mutex().isWriteAccess();
0175:                Element references = aux.getConfigurationFragment(REFS_NAME,
0176:                        REFS_NS2, true);
0177:                if (references == null) {
0178:                    references = aux.getConfigurationFragment(REFS_NAME,
0179:                            REFS_NS, true);
0180:                }
0181:                return references;
0182:            }
0183:
0184:            /**
0185:             * Store <references> to project.xml (i.e. to memory and mark project modified).
0186:             */
0187:            private void storeReferences(Element references) {
0188:                assert ProjectManager.mutex().isWriteAccess();
0189:                assert references != null
0190:                        && references.getLocalName().equals(REFS_NAME)
0191:                        && (REFS_NS.equals(references.getNamespaceURI()) || REFS_NS2
0192:                                .equals(references.getNamespaceURI()));
0193:                aux.putConfigurationFragment(references, true);
0194:            }
0195:
0196:            private void removeOldReferences() {
0197:                assert ProjectManager.mutex().isWriteAccess();
0198:                aux.removeConfigurationFragment(REFS_NAME, REFS_NS, true);
0199:            }
0200:
0201:            /**
0202:             * Add a reference to an artifact coming from a foreign project.
0203:             * <p>
0204:             * For more info see {@link #addReference(AntArtifact, URI)}.
0205:             * @param artifact the artifact to add
0206:             * @return true if a reference or some property was actually added or modified,
0207:             *         false if everything already existed and was not modified
0208:             * @throws IllegalArgumentException if the artifact is not associated with a project
0209:             * @deprecated to add reference use {@link #addReference(AntArtifact, URI)};
0210:             *   to check whether reference exist or not use {@link #isReferenced(AntArtifact, URI)}.
0211:             *   This method creates reference for the first artifact location only.
0212:             */
0213:            @Deprecated
0214:            public boolean addReference(final AntArtifact artifact)
0215:                    throws IllegalArgumentException {
0216:                Object ret[] = addReference0(artifact, artifact
0217:                        .getArtifactLocations()[0]);
0218:                return ((Boolean) ret[0]).booleanValue();
0219:            }
0220:
0221:            // @return array of two elements: [Boolean - any modification, String - reference]
0222:            private Object[] addReference0(final AntArtifact artifact,
0223:                    final URI location) throws IllegalArgumentException {
0224:                return ProjectManager.mutex().writeAccess(
0225:                        new Mutex.Action<Object[]>() {
0226:                            public Object[] run() {
0227:                                int index = findLocationIndex(artifact,
0228:                                        location);
0229:                                Project forProj = artifact.getProject();
0230:                                if (forProj == null) {
0231:                                    throw new IllegalArgumentException(
0232:                                            "No project associated with "
0233:                                                    + artifact); // NOI18N
0234:                                }
0235:                                // Set up the raw reference.
0236:                                File forProjDir = FileUtil.toFile(forProj
0237:                                        .getProjectDirectory());
0238:                                assert forProjDir != null : forProj
0239:                                        .getProjectDirectory();
0240:                                String projName = getUsableReferenceID(ProjectUtils
0241:                                        .getInformation(forProj).getName());
0242:                                String forProjName = findReferenceID(projName,
0243:                                        "project.", forProjDir
0244:                                                .getAbsolutePath());
0245:                                if (forProjName == null) {
0246:                                    forProjName = generateUniqueID(projName,
0247:                                            "project.", forProjDir
0248:                                                    .getAbsolutePath());
0249:                                }
0250:                                RawReference ref;
0251:                                File scriptFile = artifact.getScriptLocation();
0252:                                if (canUseVersion10(artifact, forProjDir)) {
0253:                                    String rel = PropertyUtils.relativizeFile(
0254:                                            forProjDir, scriptFile);
0255:                                    URI scriptLocation;
0256:                                    try {
0257:                                        scriptLocation = new URI(null, null,
0258:                                                rel, null);
0259:                                    } catch (URISyntaxException ex) {
0260:                                        scriptLocation = forProjDir.toURI()
0261:                                                .relativize(scriptFile.toURI());
0262:                                    }
0263:                                    ref = new RawReference(forProjName,
0264:                                            artifact.getType(), scriptLocation,
0265:                                            artifact.getTargetName(), artifact
0266:                                                    .getCleanTargetName(),
0267:                                            artifact.getID());
0268:                                } else {
0269:                                    String scriptLocation;
0270:                                    if (scriptFile.getAbsolutePath()
0271:                                            .startsWith(
0272:                                                    forProjDir
0273:                                                            .getAbsolutePath())) {
0274:                                        String rel = PropertyUtils
0275:                                                .relativizeFile(forProjDir,
0276:                                                        scriptFile);
0277:                                        assert rel != null : "Relativization must succeed for files: "
0278:                                                + forProjDir + " " + scriptFile;
0279:                                        scriptLocation = "${project."
0280:                                                + forProjName + "}/" + rel;
0281:                                    } else {
0282:                                        scriptLocation = "build.script.reference."
0283:                                                + forProjName;
0284:                                        setPathProperty(forProjDir, scriptFile,
0285:                                                scriptLocation);
0286:                                        scriptLocation = "${" + scriptLocation
0287:                                                + "}";
0288:                                    }
0289:                                    ref = new RawReference(forProjName,
0290:                                            artifact.getType(), scriptLocation,
0291:                                            artifact.getTargetName(), artifact
0292:                                                    .getCleanTargetName(),
0293:                                            artifact.getID(), artifact
0294:                                                    .getProperties());
0295:                                }
0296:                                boolean success = addRawReference0(ref);
0297:                                // Set up ${project.whatever}.
0298:                                FileObject myProjDirFO = AntBasedProjectFactorySingleton
0299:                                        .getProjectFor(h).getProjectDirectory();
0300:                                File myProjDir = FileUtil.toFile(myProjDirFO);
0301:                                if (setPathProperty(myProjDir, forProjDir,
0302:                                        "project." + forProjName)) {
0303:                                    success = true;
0304:                                }
0305:                                // Set up ${reference.whatever.whatever}.
0306:                                String propertiesFile;
0307:                                String forProjPathProp = "project."
0308:                                        + forProjName; // NOI18N
0309:                                URI artFile = location;
0310:                                String refPath;
0311:                                if (artFile.isAbsolute()) {
0312:                                    refPath = new File(artFile)
0313:                                            .getAbsolutePath();
0314:                                    propertiesFile = AntProjectHelper.PRIVATE_PROPERTIES_PATH;
0315:                                } else {
0316:                                    refPath = "${" + forProjPathProp + "}/"
0317:                                            + artFile.getPath(); // NOI18N
0318:                                    propertiesFile = AntProjectHelper.PROJECT_PROPERTIES_PATH;
0319:                                }
0320:                                EditableProperties props = h
0321:                                        .getProperties(propertiesFile);
0322:                                String refPathProp = "reference."
0323:                                        + forProjName
0324:                                        + '.'
0325:                                        + getUsableReferenceID(artifact.getID()); // NOI18N
0326:                                if (index > 0) {
0327:                                    refPathProp += "." + index;
0328:                                }
0329:                                if (!refPath.equals(props
0330:                                        .getProperty(refPathProp))) {
0331:                                    props.put(refPathProp, refPath);
0332:                                    h.putProperties(propertiesFile, props);
0333:                                    success = true;
0334:                                }
0335:                                return new Object[] { success,
0336:                                        "${" + refPathProp + "}" }; // NOI18N
0337:                            }
0338:                        });
0339:            }
0340:
0341:            private int findLocationIndex(final AntArtifact artifact,
0342:                    final URI location) throws IllegalArgumentException {
0343:                if (location == null) {
0344:                    throw new IllegalArgumentException(
0345:                            "location cannot be null");
0346:                }
0347:                URI uris[] = artifact.getArtifactLocations();
0348:                for (int i = 0; i < uris.length; i++) {
0349:                    if (uris[i].equals(location)) {
0350:                        return i;
0351:                    }
0352:                }
0353:                throw new IllegalArgumentException("location (" + location
0354:                        + ") must be in AntArtifact's locations (" + artifact
0355:                        + ")");
0356:            }
0357:
0358:            /**
0359:             * Test whether the artifact can be stored as /1 artifact or not.
0360:             */
0361:            private static boolean canUseVersion10(AntArtifact aa,
0362:                    File projectDirectory) {
0363:                // is there multiple outputs?
0364:                if (aa.getArtifactLocations().length > 1) {
0365:                    return false;
0366:                }
0367:                // has some properties?
0368:                if (aa.getProperties().keySet().size() > 0) {
0369:                    return false;
0370:                }
0371:                // does Ant script lies under project directory?
0372:                if (!aa.getScriptLocation().getAbsolutePath().startsWith(
0373:                        projectDirectory.getAbsolutePath())) {
0374:                    return false;
0375:                }
0376:                return true;
0377:            }
0378:
0379:            /**
0380:             * Helper method which checks collocation status of two files and based on
0381:             * that it will in private or project properties file set up property with
0382:             * the given name and with absolute or relative path value.
0383:             * @return was there any change or not
0384:             */
0385:            private boolean setPathProperty(File base, File path,
0386:                    String propertyName) {
0387:                String[] values;
0388:                String[] propertiesFiles;
0389:
0390:                String relativePath = relativizeFileToExtraBaseFolders(path);
0391:                // try relativize against external base dirs
0392:                if (relativePath != null) {
0393:                    propertiesFiles = new String[] { AntProjectHelper.PROJECT_PROPERTIES_PATH };
0394:                    values = new String[] { relativePath };
0395:                } else if (PropertyUtils.relativizeFile(base, path) != null) {
0396:                    //mkleint: removed CollocationQuery.areCollocated() reference
0397:                    // when AlwaysRelativeCQI gets removed the condition resolves to false more frequently.
0398:                    // that might not be desirable.
0399:
0400:                    // Fine, using a relative path to subproject.
0401:                    relativePath = PropertyUtils.relativizeFile(base, path);
0402:                    assert relativePath != null : "These dirs are not really collocated: "
0403:                            + base + " & " + path;
0404:                    values = new String[] { relativePath, };
0405:                    propertiesFiles = new String[] { AntProjectHelper.PROJECT_PROPERTIES_PATH, };
0406:                } else {
0407:                    // use an absolute path.
0408:                    propertiesFiles = new String[] { AntProjectHelper.PRIVATE_PROPERTIES_PATH };
0409:                    values = new String[] { path.getAbsolutePath() };
0410:                }
0411:                assert !Arrays.asList(values).contains(null) : "values="
0412:                        + Arrays.toString(values) + " base=" + base + " path="
0413:                        + path; // #119847
0414:                return setPathPropertyImpl(propertyName, values,
0415:                        propertiesFiles);
0416:            }
0417:
0418:            /**
0419:             * Helper method which in project properties file sets up property with
0420:             * the given name and with (possibly relative) path value.
0421:             * @return was there any change or not
0422:             */
0423:            private boolean setPathProperty(String path, String propertyName) {
0424:                String[] propertiesFiles = new String[] { AntProjectHelper.PROJECT_PROPERTIES_PATH };
0425:                String[] values = new String[] { path };
0426:                return setPathPropertyImpl(propertyName, values,
0427:                        propertiesFiles);
0428:            }
0429:
0430:            private boolean setPathPropertyImpl(String propertyName,
0431:                    String[] values, String[] propertiesFiles) {
0432:
0433:                boolean metadataChanged = false;
0434:                for (int i = 0; i < propertiesFiles.length; i++) {
0435:                    EditableProperties props = h
0436:                            .getProperties(propertiesFiles[i]);
0437:                    assert props != null : h.getProjectDirectory(); // #119847
0438:                    if (!values[i].equals(props.getProperty(propertyName))) {
0439:                        props.put(propertyName, values[i]);
0440:                        h.putProperties(propertiesFiles[i], props);
0441:                        metadataChanged = true;
0442:                    }
0443:                }
0444:
0445:                if (propertiesFiles.length == 1) {
0446:                    // check presence of this property in opposite property file and
0447:                    // remove it if necessary
0448:                    String propertiesFile = (propertiesFiles[0]
0449:                            .equals(AntProjectHelper.PROJECT_PROPERTIES_PATH) ? AntProjectHelper.PRIVATE_PROPERTIES_PATH
0450:                            : AntProjectHelper.PROJECT_PROPERTIES_PATH);
0451:                    EditableProperties props = h.getProperties(propertiesFile);
0452:                    if (props.remove(propertyName) != null) {
0453:                        h.putProperties(propertiesFile, props);
0454:                    }
0455:                }
0456:                return metadataChanged;
0457:            }
0458:
0459:            /**
0460:             * Add a reference to an artifact's location coming from a foreign project.
0461:             * <p>
0462:             * Records the name of the foreign project.
0463:             * Normally the foreign project name is that project's code name,
0464:             * but it may be uniquified if that name is already taken to refer
0465:             * to a different project with the same code name.
0466:             * <p>
0467:             * Adds a project property if necessary to refer to its location of the foreign
0468:             * project - a shared property if the foreign project
0469:             * is {@link CollocationQuery collocated} with this one, else a private property.
0470:             * This property is named <samp>project.<i>foreignProjectName</i></samp>.
0471:             * Example: <samp>project.mylib=../mylib</samp>
0472:             * <p>
0473:             * Adds a project property to refer to the artifact's location.
0474:             * This property is named <samp>reference.<i>foreignProjectName</i>.<i>targetName</i></samp>
0475:             * and will use <samp>${project.<i>foreignProjectName</i>}</samp> and be a shared
0476:             * property - unless the artifact location is an absolute URI, in which case the property
0477:             * will also be private.
0478:             * Example: <samp>reference.mylib.jar=${project.mylib}/dist/mylib.jar</samp>
0479:             * <p>
0480:             * Also records the artifact type, (relative) script path, and build and
0481:             * clean target names.
0482:             * <p>
0483:             * If the reference already exists (keyed by foreign project object
0484:             * and target name), nothing is done, unless some other field (script location,
0485:             * clean target name, or artifact type) needed to be updated, in which case
0486:             * the new information replaces the old. Similarly, the artifact location
0487:             * property is updated if necessary.
0488:             * <p>
0489:             * Acquires write access.
0490:             * @param artifact the artifact to add
0491:             * @param location the artifact's location to create reference to
0492:             * @return name of reference which was created or already existed
0493:             * @throws IllegalArgumentException if the artifact is not associated with a project
0494:             *   or if the location is not artifact's location
0495:             * @since 1.5
0496:             */
0497:            public String addReference(final AntArtifact artifact, URI location)
0498:                    throws IllegalArgumentException {
0499:                Object ret[] = addReference0(artifact, location);
0500:                return (String) ret[1];
0501:            }
0502:
0503:            /**
0504:             * Tests whether reference for artifact's location was already created by
0505:             * {@link #addReference(AntArtifact, URI)} for this project or not. This
0506:             * method returns false also in case when reference exist but needs to be
0507:             * updated.
0508:             * <p>
0509:             * Acquires read access.
0510:             * @param artifact the artifact to add
0511:             * @param location the artifact's location to create reference to
0512:             * @return true if already referenced
0513:             * @throws IllegalArgumentException if the artifact is not associated with a project
0514:             *   or if the location is not artifact's location
0515:             * @since 1.5
0516:             */
0517:            public boolean isReferenced(final AntArtifact artifact,
0518:                    final URI location) throws IllegalArgumentException {
0519:                return ProjectManager.mutex().readAccess(
0520:                        new Mutex.Action<Boolean>() {
0521:                            public Boolean run() {
0522:                                int index = findLocationIndex(artifact,
0523:                                        location);
0524:                                Project forProj = artifact.getProject();
0525:                                if (forProj == null) {
0526:                                    throw new IllegalArgumentException(
0527:                                            "No project associated with "
0528:                                                    + artifact); // NOI18N
0529:                                }
0530:                                File forProjDir = FileUtil.toFile(forProj
0531:                                        .getProjectDirectory());
0532:                                assert forProjDir != null : forProj
0533:                                        .getProjectDirectory();
0534:                                String projName = getUsableReferenceID(ProjectUtils
0535:                                        .getInformation(forProj).getName());
0536:                                String forProjName = findReferenceID(projName,
0537:                                        "project.", forProjDir
0538:                                                .getAbsolutePath());
0539:                                if (forProjName == null) {
0540:                                    return false;
0541:                                }
0542:                                RawReference ref = getRawReference(forProjName,
0543:                                        getUsableReferenceID(artifact.getID()));
0544:                                if (ref == null) {
0545:                                    return false;
0546:                                }
0547:                                File script = h.resolveFile(eval.evaluate(ref
0548:                                        .getScriptLocationValue()));
0549:                                if (!artifact.getType().equals(
0550:                                        ref.getArtifactType())
0551:                                        || !artifact.getID()
0552:                                                .equals(ref.getID())
0553:                                        || !artifact.getScriptLocation()
0554:                                                .equals(script)
0555:                                        || !artifact.getProperties().equals(
0556:                                                ref.getProperties())
0557:                                        || !artifact.getTargetName().equals(
0558:                                                ref.getTargetName())
0559:                                        || !artifact
0560:                                                .getCleanTargetName()
0561:                                                .equals(
0562:                                                        ref
0563:                                                                .getCleanTargetName())) {
0564:                                    return false;
0565:                                }
0566:
0567:                                String reference = "reference."
0568:                                        + forProjName
0569:                                        + '.'
0570:                                        + getUsableReferenceID(artifact.getID()); // NOI18N
0571:                                if (index > 0) {
0572:                                    reference += "." + index;
0573:                                }
0574:                                return eval.getProperty(reference) != null;
0575:                            }
0576:                        });
0577:            }
0578:
0579:            /**
0580:             * Add a raw reference to a foreign project artifact.
0581:             * Does not check if such a project already exists; does not create a project
0582:             * property to refer to it; does not do any backreference usage notifications.
0583:             * <p>
0584:             * If the reference already exists (keyed by foreign project name and target name),
0585:             * nothing is done, unless some other field (script location, clean target name,
0586:             * or artifact type) needed to be updated, in which case the new information
0587:             * replaces the old.
0588:             * <p>
0589:             * Note that since {@link RawReference} is just a descriptor, it is not guaranteed
0590:             * that after adding one {@link #getRawReferences} or {@link #getRawReference}
0591:             * would return the identical object.
0592:             * <p>
0593:             * Acquires write access.
0594:             * @param ref a raw reference descriptor
0595:             * @return true if a reference was actually added or modified,
0596:             *         false if it already existed and was not modified
0597:             */
0598:            public boolean addRawReference(final RawReference ref) {
0599:                return ProjectManager.mutex().writeAccess(
0600:                        new Mutex.Action<Boolean>() {
0601:                            public Boolean run() {
0602:                                try {
0603:                                    return addRawReference0(ref);
0604:                                } catch (IllegalArgumentException e) {
0605:                                    ErrorManager.getDefault().notify(
0606:                                            ErrorManager.INFORMATIONAL, e);
0607:                                    return false;
0608:                                }
0609:                            }
0610:                        });
0611:            }
0612:
0613:            private boolean addRawReference0(final RawReference ref)
0614:                    throws IllegalArgumentException {
0615:                Element references = loadReferences();
0616:                if (references == null) {
0617:                    references = XMLUtil.createDocument("ignore", null, null,
0618:                            null).createElementNS(ref.getNS(), REFS_NAME); // NOI18N
0619:                }
0620:                boolean modified = false;
0621:                if (references.getNamespaceURI().equals(REFS_NS)
0622:                        && ref.getNS().equals(REFS_NS2)) {
0623:                    // upgrade all references to version /2 here:
0624:                    references = upgradeTo20(references);
0625:                    removeOldReferences();
0626:                    modified = true;
0627:                } else if (references.getNamespaceURI().equals(REFS_NS2)
0628:                        && ref.getNS().equals(REFS_NS)) { // #91760
0629:                    ref.upgrade();
0630:                }
0631:                modified |= updateRawReferenceElement(ref, references);
0632:                if (modified) {
0633:                    storeReferences(references);
0634:                }
0635:                return modified;
0636:            }
0637:
0638:            private Element upgradeTo20(Element references) {
0639:                Element references20 = XMLUtil.createDocument("ignore", null,
0640:                        null, null).createElementNS(REFS_NS2, REFS_NAME); // NOI18N
0641:                RawReference rr[] = getRawReferences(references);
0642:                for (int i = 0; i < rr.length; i++) {
0643:                    rr[i].upgrade();
0644:                    updateRawReferenceElement(rr[i], references20);
0645:                }
0646:                return references20;
0647:            }
0648:
0649:            private static boolean updateRawReferenceElement(RawReference ref,
0650:                    Element references) throws IllegalArgumentException {
0651:                // Linear search; always keeping references sorted first by foreign project
0652:                // name, then by target name.
0653:                Element nextRefEl = null;
0654:                Iterator<Element> it = Util.findSubElements(references)
0655:                        .iterator();
0656:                while (it.hasNext()) {
0657:                    Element testRefEl = it.next();
0658:                    RawReference testRef = RawReference.create(testRefEl);
0659:                    if (testRef.getForeignProjectName().compareTo(
0660:                            ref.getForeignProjectName()) > 0) {
0661:                        // gone too far, go back
0662:                        nextRefEl = testRefEl;
0663:                        break;
0664:                    }
0665:                    if (testRef.getForeignProjectName().equals(
0666:                            ref.getForeignProjectName())) {
0667:                        if (testRef.getID().compareTo(ref.getID()) > 0) {
0668:                            // again, gone too far, go back
0669:                            nextRefEl = testRefEl;
0670:                            break;
0671:                        }
0672:                        if (testRef.getID().equals(ref.getID())) {
0673:                            // Key match, check if it needs to be updated.
0674:                            if (testRef.getArtifactType().equals(
0675:                                    ref.getArtifactType())
0676:                                    && testRef.getScriptLocationValue().equals(
0677:                                            ref.getScriptLocationValue())
0678:                                    && testRef.getProperties().equals(
0679:                                            ref.getProperties())
0680:                                    && testRef.getTargetName().equals(
0681:                                            ref.getTargetName())
0682:                                    && testRef.getCleanTargetName().equals(
0683:                                            ref.getCleanTargetName())) {
0684:                                // Match on other fields. Return without changing anything.
0685:                                return false;
0686:                            }
0687:                            // Something needs updating.
0688:                            // Delete the old ref and set nextRef to the next item in line.
0689:                            references.removeChild(testRefEl);
0690:                            if (it.hasNext()) {
0691:                                nextRefEl = it.next();
0692:                            } else {
0693:                                nextRefEl = null;
0694:                            }
0695:                            break;
0696:                        }
0697:                    }
0698:                }
0699:                // Need to insert a new record before nextRef.
0700:                Element newRefEl = ref.toXml(references.getNamespaceURI(),
0701:                        references.getOwnerDocument());
0702:                // Note: OK if nextRefEl == null, that means insert as last child.
0703:                references.insertBefore(newRefEl, nextRefEl);
0704:                return true;
0705:            }
0706:
0707:            /**
0708:             * Remove a reference to an artifact coming from a foreign project.
0709:             * <p>
0710:             * The property giving the location of the artifact is removed if it existed.
0711:             * <p>
0712:             * If this was the last reference to the foreign project, its location
0713:             * property is removed as well.
0714:             * <p>
0715:             * If the reference does not exist, nothing is done.
0716:             * <p>
0717:             * Acquires write access.
0718:             * @param foreignProjectName the local name of the foreign project
0719:             *                           (usually its code name)
0720:             * @param id the ID of the build artifact (usually build target name)
0721:             * @return true if a reference or some property was actually removed,
0722:             *         false if the reference was not there and no property was removed
0723:             * @deprecated use {@link #destroyReference} instead; was unused anyway
0724:             */
0725:            @Deprecated
0726:            public boolean removeReference(final String foreignProjectName,
0727:                    final String id) {
0728:                return removeReference(foreignProjectName, id, false, null);
0729:            }
0730:
0731:            /**
0732:             * Checks whether this is last reference and therefore the artifact can
0733:             * be removed from project.xml or not
0734:             */
0735:            private boolean isLastReference(String ref) {
0736:                Object ret[] = findArtifactAndLocation(ref);
0737:                if (ret[0] == null || ret[1] == null) {
0738:                    return true;
0739:                }
0740:                AntArtifact aa = (AntArtifact) ret[0];
0741:                URI uri = (URI) ret[1];
0742:                URI uris[] = aa.getArtifactLocations();
0743:                boolean lastReference = true;
0744:                // are there any other referenced jars or not:
0745:                for (int i = 0; i < uris.length; i++) {
0746:                    if (uris[i].equals(uri)) {
0747:                        continue;
0748:                    }
0749:                    if (isReferenced(aa, uris[i])) {
0750:                        lastReference = false;
0751:                        break;
0752:                    }
0753:                }
0754:                return lastReference;
0755:            }
0756:
0757:            private boolean removeReference(final String foreignProjectName,
0758:                    final String id, final boolean escaped,
0759:                    final String reference) {
0760:                return ProjectManager.mutex().writeAccess(
0761:                        new Mutex.Action<Boolean>() {
0762:                            public Boolean run() {
0763:                                boolean success = false;
0764:                                try {
0765:                                    if (isLastReference("${" + reference + "}")) {
0766:                                        success = removeRawReference0(
0767:                                                foreignProjectName, id, escaped);
0768:                                    }
0769:                                } catch (IllegalArgumentException e) {
0770:                                    ErrorManager.getDefault().notify(
0771:                                            ErrorManager.INFORMATIONAL, e);
0772:                                    return false;
0773:                                }
0774:                                // Note: try to delete obsoleted properties from both project.properties
0775:                                // and private.properties, just in case.
0776:                                String[] PROPS_PATHS = {
0777:                                        AntProjectHelper.PROJECT_PROPERTIES_PATH,
0778:                                        AntProjectHelper.PRIVATE_PROPERTIES_PATH, };
0779:                                // if raw reference was removed then try to clean also project reference property:
0780:                                if (success) {
0781:                                    // Check whether there are any other references using foreignProjectName.
0782:                                    // If not, we can delete ${project.foreignProjectName}.
0783:                                    RawReference[] refs = new RawReference[0];
0784:                                    Element references = loadReferences();
0785:                                    if (references != null) {
0786:                                        refs = getRawReferences(references);
0787:                                    }
0788:                                    boolean deleteProjProp = true;
0789:                                    for (int i = 0; i < refs.length; i++) {
0790:                                        if (refs[i].getForeignProjectName()
0791:                                                .equals(foreignProjectName)) {
0792:                                            deleteProjProp = false;
0793:                                            break;
0794:                                        }
0795:                                    }
0796:                                    if (deleteProjProp) {
0797:                                        String projProp = "project."
0798:                                                + foreignProjectName; // NOI18N
0799:                                        for (int i = 0; i < PROPS_PATHS.length; i++) {
0800:                                            EditableProperties props = h
0801:                                                    .getProperties(PROPS_PATHS[i]);
0802:                                            if (props.containsKey(projProp)) {
0803:                                                props.remove(projProp);
0804:                                                h.putProperties(PROPS_PATHS[i],
0805:                                                        props);
0806:                                                success = true;
0807:                                            }
0808:                                        }
0809:                                    }
0810:                                }
0811:
0812:                                String refProp = reference;
0813:                                if (refProp == null) {
0814:                                    refProp = "reference." + foreignProjectName
0815:                                            + '.' + getUsableReferenceID(id); // NOI18N
0816:                                }
0817:                                // remove also build script property if exist any:
0818:                                String buildScriptProperty = "build.script.reference."
0819:                                        + foreignProjectName;
0820:                                for (String path : PROPS_PATHS) {
0821:                                    EditableProperties props = h
0822:                                            .getProperties(path);
0823:                                    if (props.containsKey(refProp)) {
0824:                                        props.remove(refProp);
0825:                                        h.putProperties(path, props);
0826:                                        success = true;
0827:                                    }
0828:                                    if (props.containsKey(buildScriptProperty)) {
0829:                                        props.remove(buildScriptProperty);
0830:                                        h.putProperties(path, props);
0831:                                        success = true;
0832:                                    }
0833:                                }
0834:                                return success;
0835:                            }
0836:                        });
0837:            }
0838:
0839:            /**
0840:             * Remove reference to a file.
0841:             * <p>
0842:             * If the reference does not exist, nothing is done.
0843:             * <p>
0844:             * Acquires write access.
0845:             * @param fileReference file reference as created by 
0846:             *    {@link #createForeignFileReference(File, String)}
0847:             * @return true if the reference was actually removed; otherwise false
0848:             * @deprecated use {@link #destroyReference} instead; was unused anyway
0849:             */
0850:            @Deprecated
0851:            public boolean removeReference(final String fileReference) {
0852:                return removeFileReference(fileReference);
0853:            }
0854:
0855:            private boolean removeFileReference(final String fileReference) {
0856:                return ProjectManager.mutex().writeAccess(
0857:                        new Mutex.Action<Boolean>() {
0858:                            public Boolean run() {
0859:                                boolean success = false;
0860:                                // Note: try to delete obsoleted properties from both project.properties
0861:                                // and private.properties, just in case.
0862:                                String[] PROPS_PATHS = {
0863:                                        AntProjectHelper.PROJECT_PROPERTIES_PATH,
0864:                                        AntProjectHelper.PRIVATE_PROPERTIES_PATH, };
0865:                                String refProp = fileReference;
0866:                                if (refProp.startsWith("${")
0867:                                        && refProp.endsWith("}")) {
0868:                                    refProp = refProp.substring(2, refProp
0869:                                            .length() - 1);
0870:                                }
0871:                                for (String path : PROPS_PATHS) {
0872:                                    EditableProperties props = h
0873:                                            .getProperties(path);
0874:                                    if (props.containsKey(refProp)) {
0875:                                        props.remove(refProp);
0876:                                        h.putProperties(path, props);
0877:                                        success = true;
0878:                                    }
0879:                                }
0880:                                return success;
0881:                            }
0882:                        });
0883:            }
0884:
0885:            /**
0886:             * Remove a raw reference to an artifact coming from a foreign project.
0887:             * Does not attempt to manipulate backreferences in the foreign project
0888:             * nor project properties.
0889:             * <p>
0890:             * If the reference does not exist, nothing is done.
0891:             * <p>
0892:             * Acquires write access.
0893:             * @param foreignProjectName the local name of the foreign project
0894:             *                           (usually its code name)
0895:             * @param id the ID of the build artifact (usually build target name)
0896:             * @return true if a reference was actually removed, false if it was not there
0897:             */
0898:            public boolean removeRawReference(final String foreignProjectName,
0899:                    final String id) {
0900:                return ProjectManager.mutex().writeAccess(
0901:                        new Mutex.Action<Boolean>() {
0902:                            public Boolean run() {
0903:                                try {
0904:                                    return removeRawReference0(
0905:                                            foreignProjectName, id, false);
0906:                                } catch (IllegalArgumentException e) {
0907:                                    ErrorManager.getDefault().notify(
0908:                                            ErrorManager.INFORMATIONAL, e);
0909:                                    return false;
0910:                                }
0911:                            }
0912:                        });
0913:            }
0914:
0915:            private boolean removeRawReference0(
0916:                    final String foreignProjectName, final String id,
0917:                    boolean escaped) throws IllegalArgumentException {
0918:                Element references = loadReferences();
0919:                if (references == null) {
0920:                    return false;
0921:                }
0922:                boolean success = removeRawReferenceElement(foreignProjectName,
0923:                        id, references, escaped);
0924:                if (success) {
0925:                    storeReferences(references);
0926:                }
0927:                return success;
0928:            }
0929:
0930:            private static boolean removeRawReferenceElement(
0931:                    String foreignProjectName, String id, Element references,
0932:                    boolean escaped) throws IllegalArgumentException {
0933:                // As with addRawReference, do a linear search through.
0934:                for (Element testRefEl : Util.findSubElements(references)) {
0935:                    RawReference testRef = RawReference.create(testRefEl);
0936:                    String refID = testRef.getID();
0937:                    String refName = testRef.getForeignProjectName();
0938:                    if (escaped) {
0939:                        refID = getUsableReferenceID(testRef.getID());
0940:                        refName = getUsableReferenceID(testRef
0941:                                .getForeignProjectName());
0942:                    }
0943:                    if (refName.compareTo(foreignProjectName) > 0) {
0944:                        // searched past it
0945:                        return false;
0946:                    }
0947:                    if (refName.equals(foreignProjectName)) {
0948:                        if (refID.compareTo(id) > 0) {
0949:                            // again, searched past it
0950:                            return false;
0951:                        }
0952:                        if (refID.equals(id)) {
0953:                            // Key match, remove it.
0954:                            references.removeChild(testRefEl);
0955:                            return true;
0956:                        }
0957:                    }
0958:                }
0959:                // Searched through to the end and did not find it.
0960:                return false;
0961:            }
0962:
0963:            /**
0964:             * Get a list of raw references from this project to others.
0965:             * If necessary, you may use {@link RawReference#toAntArtifact} to get
0966:             * live information from each reference, such as its associated project.
0967:             * <p>
0968:             * Acquires read access.
0969:             * @return a (possibly empty) list of raw references from this project
0970:             */
0971:            public RawReference[] getRawReferences() {
0972:                return ProjectManager.mutex().readAccess(
0973:                        new Mutex.Action<RawReference[]>() {
0974:                            public RawReference[] run() {
0975:                                Element references = loadReferences();
0976:                                if (references != null) {
0977:                                    try {
0978:                                        return getRawReferences(references);
0979:                                    } catch (IllegalArgumentException e) {
0980:                                        ErrorManager.getDefault().notify(
0981:                                                ErrorManager.INFORMATIONAL, e);
0982:                                    }
0983:                                }
0984:                                return new RawReference[0];
0985:                            }
0986:                        });
0987:            }
0988:
0989:            private static RawReference[] getRawReferences(Element references)
0990:                    throws IllegalArgumentException {
0991:                List<Element> subEls = Util.findSubElements(references);
0992:                List<RawReference> refs = new ArrayList<RawReference>(subEls
0993:                        .size());
0994:                for (Element subEl : subEls) {
0995:                    refs.add(RawReference.create(subEl));
0996:                }
0997:                return refs.toArray(new RawReference[refs.size()]);
0998:            }
0999:
1000:            /**
1001:             * Get a particular raw reference from this project to another.
1002:             * If necessary, you may use {@link RawReference#toAntArtifact} to get
1003:             * live information from each reference, such as its associated project.
1004:             * <p>
1005:             * Acquires read access.
1006:             * @param foreignProjectName the local name of the foreign project
1007:             *                           (usually its code name)
1008:             * @param id the ID of the build artifact (usually the build target name)
1009:             * @return the specified raw reference from this project,
1010:             *         or null if none such could be found
1011:             */
1012:            public RawReference getRawReference(
1013:                    final String foreignProjectName, final String id) {
1014:                return getRawReference(foreignProjectName, id, false);
1015:            }
1016:
1017:            // not private only to allow unit testing
1018:            RawReference getRawReference(final String foreignProjectName,
1019:                    final String id, final boolean escaped) {
1020:                return ProjectManager.mutex().readAccess(
1021:                        new Mutex.Action<RawReference>() {
1022:                            public RawReference run() {
1023:                                Element references = loadReferences();
1024:                                if (references != null) {
1025:                                    try {
1026:                                        return getRawReference(
1027:                                                foreignProjectName, id,
1028:                                                references, escaped);
1029:                                    } catch (IllegalArgumentException e) {
1030:                                        ErrorManager.getDefault().notify(
1031:                                                ErrorManager.INFORMATIONAL, e);
1032:                                    }
1033:                                }
1034:                                return null;
1035:                            }
1036:                        });
1037:            }
1038:
1039:            private static RawReference getRawReference(
1040:                    String foreignProjectName, String id, Element references,
1041:                    boolean escaped) throws IllegalArgumentException {
1042:                for (Element subEl : Util.findSubElements(references)) {
1043:                    RawReference ref = RawReference.create(subEl);
1044:                    String refID = ref.getID();
1045:                    String refName = ref.getForeignProjectName();
1046:                    if (escaped) {
1047:                        refID = getUsableReferenceID(ref.getID());
1048:                        refName = getUsableReferenceID(ref
1049:                                .getForeignProjectName());
1050:                    }
1051:                    if (refName.equals(foreignProjectName) && refID.equals(id)) {
1052:                        return ref;
1053:                    }
1054:                }
1055:                return null;
1056:            }
1057:
1058:            /**
1059:             * Create an Ant-interpretable string referring to a file on disk.
1060:             * If the file refers to a known Ant artifact according to
1061:             * {@link AntArtifactQuery#findArtifactFromFile}, of the expected type
1062:             * and associated with a particular project,
1063:             * the behavior is identical to {@link #createForeignFileReference(AntArtifact)}.
1064:             * Otherwise, a reference for the file is created. The file path will
1065:             * be relative in case {@link CollocationQuery#areCollocated} says that
1066:             * the file is collocated with this project's main directory, else it
1067:             * will be an absolute path.
1068:             * <p>
1069:             * Acquires write access.
1070:             * @param file a file to refer to (need not currently exist)
1071:             * @param expectedArtifactType the required {@link AntArtifact#getType}
1072:             * @return a string which can refer to that file somehow
1073:             */
1074:            public String createForeignFileReference(final File file,
1075:                    final String expectedArtifactType) {
1076:                if (!file.equals(FileUtil.normalizeFile(file))) {
1077:                    throw new IllegalArgumentException(
1078:                            "Parameter file was not "
1079:                                    + // NOI18N
1080:                                    "normalized. Was " + file + " instead of "
1081:                                    + FileUtil.normalizeFile(file)); // NOI18N
1082:                }
1083:                return createForeignFileReferenceImpl(file.getAbsolutePath(),
1084:                        expectedArtifactType, true);
1085:            }
1086:
1087:            /**
1088:             * Create an Ant-interpretable string referring to a file on disk. Compared
1089:             * to {@link #createForeignFileReference} the filepath does not have to be 
1090:             * normalized (ie. it can be relative path to project base folder), no 
1091:             * relativization or absolutization of path is done and
1092:             * reference to file is always stored in project properties.
1093:             * If the file refers to a known Ant artifact according to
1094:             * {@link AntArtifactQuery#findArtifactFromFile}, of the expected type
1095:             * and associated with a particular project,
1096:             * the behavior is identical to {@link #createForeignFileReference(AntArtifact)}.
1097:             * <p>
1098:             * Acquires write access.
1099:             * @param path a file path to refer to (need not currently exist)
1100:             * @param expectedArtifactType the required {@link AntArtifact#getType}
1101:             * @return a string which can refer to that file somehow
1102:             *
1103:             * @since org.netbeans.modules.project.ant/1 1.19
1104:             */
1105:            public String createForeignFileReferenceAsIs(final String filepath,
1106:                    final String expectedArtifactType) {
1107:                return createForeignFileReferenceImpl(filepath,
1108:                        expectedArtifactType, false);
1109:            }
1110:
1111:            private String createForeignFileReferenceImpl(final String path,
1112:                    final String expectedArtifactType,
1113:                    final boolean performHeuristics) {
1114:                FileObject myProjDirFO = h.getProjectDirectory();
1115:                File myProjDir = FileUtil.toFile(myProjDirFO);
1116:                final File normalizedFile = FileUtil
1117:                        .normalizeFile(PropertyUtils.resolveFile(myProjDir,
1118:                                path));
1119:                return ProjectManager.mutex().writeAccess(
1120:                        new Mutex.Action<String>() {
1121:                            public String run() {
1122:                                AntArtifact art = AntArtifactQuery
1123:                                        .findArtifactFromFile(normalizedFile);
1124:                                if (art != null
1125:                                        && art.getType().equals(
1126:                                                expectedArtifactType)
1127:                                        && art.getProject() != null) {
1128:                                    try {
1129:                                        return createForeignFileReference(art);
1130:                                    } catch (IllegalArgumentException iae) {
1131:                                        throw new AssertionError(iae);
1132:                                    }
1133:                                } else {
1134:                                    File myProjDir = FileUtil
1135:                                            .toFile(AntBasedProjectFactorySingleton
1136:                                                    .getProjectFor(h)
1137:                                                    .getProjectDirectory());
1138:                                    String fileID = normalizedFile.getName();
1139:                                    // if the file is folder then add to ID string also parent folder name,
1140:                                    // i.e. if external source folder name is "src" the ID will
1141:                                    // be a bit more selfdescribing, e.g. project-src in case
1142:                                    // of ID for ant/project/src directory.
1143:                                    if (normalizedFile.isDirectory()
1144:                                            && normalizedFile.getParentFile() != null) {
1145:                                        fileID = normalizedFile.getParentFile()
1146:                                                .getName()
1147:                                                + "-"
1148:                                                + normalizedFile.getName();
1149:                                    }
1150:                                    fileID = PropertyUtils
1151:                                            .getUsablePropertyName(fileID);
1152:                                    String prop = findReferenceID(fileID,
1153:                                            "file.reference.", normalizedFile
1154:                                                    .getAbsolutePath()); // NOI18N
1155:                                    if (prop == null) {
1156:                                        prop = generateUniqueID(fileID,
1157:                                                "file.reference.",
1158:                                                normalizedFile
1159:                                                        .getAbsolutePath()); // NOI18N
1160:                                    }
1161:                                    if (performHeuristics) {
1162:                                        setPathProperty(myProjDir,
1163:                                                normalizedFile,
1164:                                                "file.reference." + prop);
1165:                                    } else {
1166:                                        setPathProperty(path, "file.reference."
1167:                                                + prop);
1168:                                    }
1169:                                    return "${file.reference." + prop + '}'; // NOI18N
1170:                                }
1171:                            }
1172:                        });
1173:            }
1174:
1175:            /**
1176:             * Create an Ant-interpretable string referring to a file on disk. Compared
1177:             * to {@link #createForeignFileReference} the file path does not have to be 
1178:             * normalized (ie. it can be relative path to project base folder), no 
1179:             * relativization or absolutization of path is done and
1180:             * reference to file is always stored in project properties.
1181:             * <p>
1182:             * Acquires write access.
1183:             * @param path a file path to refer to (need not currently exist)
1184:             * @param property name of the property
1185:             * @return a string which can refer to that file somehow
1186:             *
1187:             * @since org.netbeans.modules.project.ant/1 1.19
1188:             */
1189:            public String createExtraForeignFileReferenceAsIs(
1190:                    final String path, final String property) {
1191:                return ProjectManager.mutex().writeAccess(
1192:                        new Mutex.Action<String>() {
1193:                            public String run() {
1194:                                setPathProperty(path, property);
1195:                                return "${" + property + '}'; // NOI18N
1196:                            }
1197:                        });
1198:            }
1199:
1200:            /**
1201:             * Test whether file does not lie under an extra base folder and if it does
1202:             * then return string in form of "${extra.base}/remaining/path"; or null.
1203:             */
1204:            private String relativizeFileToExtraBaseFolders(File f) {
1205:                File base = FileUtil.toFile(h.getProjectDirectory());
1206:                String fileToRelativize = f.getAbsolutePath();
1207:                for (String prop : extraBaseDirectories) {
1208:                    String path = eval.getProperty(prop);
1209:                    File extraBase = PropertyUtils.resolveFile(base, path);
1210:                    path = extraBase.getAbsolutePath();
1211:                    if (!path.endsWith(File.separator)) {
1212:                        path += File.separator;
1213:                    }
1214:                    if (fileToRelativize.startsWith(path)) {
1215:                        return "${"
1216:                                + prop
1217:                                + "}/"
1218:                                + fileToRelativize.substring(path.length())
1219:                                        .replace('\\', '/'); // NOI18N
1220:                    }
1221:                }
1222:                return null;
1223:            }
1224:
1225:            /**
1226:             * Add extra folder which can be used as base directory (in addition to
1227:             * project base folder) for creating references. Duplicate property names
1228:             * are ignored. Any newly created reference to a file lying under an
1229:             * extra base directory will be based on that property and will be stored in
1230:             * shared project properties.
1231:             * <p>Acquires write access.
1232:             * @param propertyName property name which value is path to folder which
1233:             *  can be used as alternative project's base directory; cannot be null;
1234:             *  property must exist
1235:             * @throws IllegalArgumentException if propertyName is null or such a 
1236:             *   property does not exist
1237:             * @since 1.4
1238:             */
1239:            public void addExtraBaseDirectory(final String propertyName) {
1240:                if (propertyName == null
1241:                        || eval.getProperty(propertyName) == null) {
1242:                    throw new IllegalArgumentException(
1243:                            "propertyName is null or such a property does not exist: "
1244:                                    + propertyName); // NOI18N
1245:                }
1246:                ProjectManager.mutex().writeAccess(new Runnable() {
1247:                    public void run() {
1248:                        extraBaseDirectories.add(propertyName);
1249:                    }
1250:                });
1251:            }
1252:
1253:            /**
1254:             * Remove extra base directory. The base directory property had to be added
1255:             * by {@link #addExtraBaseDirectory} method call. At the time when this
1256:             * method is called the property must still exist and must be valid. This
1257:             * method will replace all references of the extra base directory property
1258:             * with its current value and if needed it may move such a property from
1259:             * shared project properties into the private properties.
1260:             * <p>Acquires write access.
1261:             * @param propertyName property name which was added by 
1262:             * {@link #addExtraBaseDirectory} method.
1263:             * @throws IllegalArgumentException if given property is not extra base 
1264:             *   directory
1265:             * @since 1.4
1266:             */
1267:            public void removeExtraBaseDirectory(final String propertyName) {
1268:                ProjectManager.mutex().writeAccess(new Runnable() {
1269:                    public void run() {
1270:                        if (!extraBaseDirectories.remove(propertyName)) {
1271:                            throw new IllegalArgumentException(
1272:                                    "Non-existing extra base directory property: "
1273:                                            + propertyName); // NOI18N
1274:                        }
1275:                        // substitute all references of removed extra base folder property with its value
1276:                        String tag = "${" + propertyName + "}"; // NOI18N
1277:                        // was extra base property defined in shared file or not:
1278:                        boolean shared = h.getProperties(
1279:                                AntProjectHelper.PROJECT_PROPERTIES_PATH)
1280:                                .containsKey(propertyName);
1281:                        String value = eval.getProperty(propertyName);
1282:                        EditableProperties propProj = h
1283:                                .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
1284:                        EditableProperties propPriv = h
1285:                                .getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
1286:                        boolean modifiedProj = false;
1287:                        boolean modifiedPriv = false;
1288:                        Iterator<Map.Entry<String, String>> it = propProj
1289:                                .entrySet().iterator();
1290:                        while (it.hasNext()) {
1291:                            Map.Entry<String, String> entry = it.next();
1292:                            String val = entry.getValue();
1293:                            int index;
1294:                            if ((index = val.indexOf(tag)) != -1) {
1295:                                val = val.substring(0, index) + value
1296:                                        + val.substring(index + tag.length());
1297:                                if (shared) {
1298:                                    // substitute extra base folder property with its value
1299:                                    entry.setValue(val);
1300:                                } else {
1301:                                    // move property to private properties file
1302:                                    it.remove();
1303:                                    propPriv.put(entry.getKey(), val);
1304:                                    modifiedPriv = true;
1305:                                }
1306:                                modifiedProj = true;
1307:                            }
1308:                        }
1309:                        if (modifiedProj) {
1310:                            h.putProperties(
1311:                                    AntProjectHelper.PROJECT_PROPERTIES_PATH,
1312:                                    propProj);
1313:                        }
1314:                        if (modifiedPriv) {
1315:                            h.putProperties(
1316:                                    AntProjectHelper.PRIVATE_PROPERTIES_PATH,
1317:                                    propPriv);
1318:                        }
1319:                    }
1320:                });
1321:            }
1322:
1323:            /**
1324:             * Find reference ID (e.g. something you can then pass to RawReference 
1325:             * as foreignProjectName) for the given property base name, prefix and path.
1326:             * @param property project name or jar filename
1327:             * @param prefix prefix used for reference, i.e. "project." for project 
1328:             *    reference or "file.reference." for file reference
1329:             * @param path absolute filename the reference points to
1330:             * @return found reference ID or null
1331:             */
1332:            private String findReferenceID(String property, String prefix,
1333:                    String path) {
1334:                Map<String, String> m = h.getStandardPropertyEvaluator()
1335:                        .getProperties();
1336:                for (Map.Entry<String, String> e : m.entrySet()) {
1337:                    String key = e.getKey();
1338:                    if (key.startsWith(prefix + property)) {
1339:                        String v = h.resolvePath(e.getValue());
1340:                        if (path.equals(v)) {
1341:                            return key.substring(prefix.length());
1342:                        }
1343:                    }
1344:                }
1345:                return null;
1346:            }
1347:
1348:            /**
1349:             * Generate unique reference ID for the given property base name, prefix 
1350:             * and path. See also {@link #findReferenceID(String, String, String)}.
1351:             * @param property project name or jar filename
1352:             * @param prefix prefix used for reference, i.e. "project." for project 
1353:             *    reference or "file.reference." for file reference
1354:             * @param path absolute filename the reference points to
1355:             * @return generated unique reference ID
1356:             */
1357:            private String generateUniqueID(String property, String prefix,
1358:                    String value) {
1359:                PropertyEvaluator pev = h.getStandardPropertyEvaluator();
1360:                if (pev.getProperty(prefix + property) == null) {
1361:                    return property;
1362:                }
1363:                int i = 1;
1364:                while (pev.getProperty(prefix + property + "-" + i) != null) {
1365:                    i++;
1366:                }
1367:                return property + "-" + i;
1368:            }
1369:
1370:            /**
1371:             * Create an Ant-interpretable string referring to a known build artifact file.
1372:             * Simply calls {@link #addReference} and returns an Ant string which will
1373:             * refer to that artifact correctly.
1374:             * <p>
1375:             * Acquires write access.
1376:             * @param artifact a known build artifact to refer to
1377:             * @return a string which can refer to that artifact file somehow
1378:             * @throws IllegalArgumentException if the artifact is not associated with a project
1379:             * @deprecated use {@link #addReference(AntArtifact, URI)} instead
1380:             */
1381:            @Deprecated
1382:            public String createForeignFileReference(AntArtifact artifact)
1383:                    throws IllegalArgumentException {
1384:                Object ret[] = addReference0(artifact, artifact
1385:                        .getArtifactLocations()[0]);
1386:                return (String) ret[1];
1387:            }
1388:
1389:            /**
1390:             * Project reference ID cannot contain dot character.
1391:             * File reference can.
1392:             */
1393:            private static String getUsableReferenceID(String ID) {
1394:                return PropertyUtils.getUsablePropertyName(ID)
1395:                        .replace('.', '_');
1396:            }
1397:
1398:            private static final Pattern FOREIGN_FILE_REFERENCE = Pattern
1399:                    .compile("\\$\\{reference\\.([^.${}]+)\\.([^.${}]+)\\.([\\d&&[^.${}]]+)\\}"); // NOI18N
1400:            private static final Pattern FOREIGN_FILE_REFERENCE_OLD = Pattern
1401:                    .compile("\\$\\{reference\\.([^.${}]+)\\.([^.${}]+)\\}"); // NOI18N
1402:            private static final Pattern FOREIGN_PLAIN_FILE_REFERENCE = Pattern
1403:                    .compile("\\$\\{file\\.reference\\.([^${}]+)\\}"); // NOI18N
1404:            private static final Pattern LIBRARY_REFERENCE = Pattern
1405:                    .compile("\\$\\{libs\\.([^${}]+)\\.[^${}]+\\}"); // NOI18N
1406:
1407:            /**
1408:             * Try to find an <code>AntArtifact</code> object corresponding to a given
1409:             * foreign file reference.
1410:             * If the supplied string is not a recognized reference to a build
1411:             * artifact, returns null.
1412:             * <p>Acquires read access.
1413:             * @param reference a reference string as present in an Ant property
1414:             * @return a corresponding Ant artifact object if there is one, else null
1415:             * @deprecated use {@link #findArtifactAndLocation} instead
1416:             */
1417:            @Deprecated
1418:            public AntArtifact getForeignFileReferenceAsArtifact(
1419:                    final String reference) {
1420:                Object ret[] = findArtifactAndLocation(reference);
1421:                return (AntArtifact) ret[0];
1422:            }
1423:
1424:            /**
1425:             * Try to find an <code>AntArtifact</code> object and location corresponding
1426:             * to a given reference. If the supplied string is not a recognized
1427:             * reference to a build artifact, returns an array of nulls.
1428:             * <p>
1429:             * Acquires read access.
1430:             * @param reference a reference string as present in an Ant property and as
1431:             *   created by {@link #addReference(AntArtifact, URI)}
1432:             * @return always returns array of two items. The items may be both null. First
1433:             *   one is instance of AntArtifact and second is instance of URI and is
1434:             *   AntArtifact's location
1435:             * @since 1.5
1436:             */
1437:            public Object[] findArtifactAndLocation(final String reference) {
1438:                return ProjectManager.mutex().readAccess(
1439:                        new Mutex.Action<Object[]>() {
1440:                            public Object[] run() {
1441:                                AntArtifact aa = null;
1442:                                Matcher m = FOREIGN_FILE_REFERENCE
1443:                                        .matcher(reference);
1444:                                boolean matches = m.matches();
1445:                                int index = 0;
1446:                                if (!matches) {
1447:                                    m = FOREIGN_FILE_REFERENCE_OLD
1448:                                            .matcher(reference);
1449:                                    matches = m.matches();
1450:                                } else {
1451:                                    try {
1452:                                        index = Integer.parseInt(m.group(3));
1453:                                    } catch (NumberFormatException ex) {
1454:                                        ErrorManager
1455:                                                .getDefault()
1456:                                                .log(
1457:                                                        ErrorManager.INFORMATIONAL,
1458:                                                        "Could not parse reference ("
1459:                                                                + reference
1460:                                                                + ") for the jar index. "
1461:                                                                + // NOI18N
1462:                                                                "Expected number: "
1463:                                                                + m.group(3)); // NOI18N
1464:                                        matches = false;
1465:                                    }
1466:                                }
1467:                                if (matches) {
1468:                                    RawReference ref = getRawReference(m
1469:                                            .group(1), m.group(2), true);
1470:                                    if (ref != null) {
1471:                                        aa = ref
1472:                                                .toAntArtifact(ReferenceHelper.this );
1473:                                    }
1474:                                }
1475:                                if (aa == null) {
1476:                                    return new Object[] { null, null };
1477:                                }
1478:                                if (index >= aa.getArtifactLocations().length) {
1479:                                    // #55413: we no longer have that many items...treat it as dead.
1480:                                    return new Object[] { null, null };
1481:                                }
1482:                                URI uri = aa.getArtifactLocations()[index];
1483:                                return new Object[] { aa, uri };
1484:                            }
1485:                        });
1486:            }
1487:
1488:            /**
1489:             * Remove a reference to a foreign file from the project.
1490:             * See {@link #destroyReference} for more information.
1491:             * @param reference an Ant-interpretable foreign file reference as created e.g.
1492:             *                  by {@link #createForeignFileReference(File,String)} or
1493:             *                  by {@link #createForeignFileReference(AntArtifact)}
1494:             * @deprecated use {@link #destroyReference} instead which does exactly 
1495:             *   the same but has more appropriate name
1496:             */
1497:            @Deprecated
1498:            public void destroyForeignFileReference(String reference) {
1499:                destroyReference(reference);
1500:            }
1501:
1502:            /**
1503:             * Remove a reference to a foreign file from the project.
1504:             * If the passed string consists of an Ant property reference corresponding to
1505:             * a known inter-project reference created by 
1506:             * {@link #addReference(AntArtifact, URI)} or file reference created by
1507:             * {@link #createForeignFileReference(File, String)}, that reference is removed.
1508:             * Since this would break any other identical foreign
1509:             * file references present in the project, you should first confirm that this
1510:             * reference was the last one of its kind (by string match).
1511:             * <p>
1512:             * If the passed string is anything else (i.e. a plain file path, relative or
1513:             * absolute), nothing is done.
1514:             * <p>
1515:             * Acquires write access.
1516:             * @param reference an Ant-interpretable foreign file reference as created e.g.
1517:             *                  by {@link #createForeignFileReference(File,String)} or
1518:             *                  by {@link #createForeignFileReference(AntArtifact)}
1519:             * @return true if reference was really destroyed or not
1520:             * @since 1.5
1521:             */
1522:            public boolean destroyReference(String reference) {
1523:                Matcher m = FOREIGN_FILE_REFERENCE.matcher(reference);
1524:                boolean matches = m.matches();
1525:                if (!matches) {
1526:                    m = FOREIGN_FILE_REFERENCE_OLD.matcher(reference);
1527:                    matches = m.matches();
1528:                }
1529:                if (matches) {
1530:                    String forProjName = m.group(1);
1531:                    String id = m.group(2);
1532:                    return removeReference(forProjName, id, true, reference
1533:                            .substring(2, reference.length() - 1));
1534:                }
1535:                m = FOREIGN_PLAIN_FILE_REFERENCE.matcher(reference);
1536:                if (m.matches()) {
1537:                    return removeFileReference(reference);
1538:                }
1539:                return false;
1540:            }
1541:
1542:            /**
1543:             * Create an object permitting this project to represent subprojects.
1544:             * Would be placed into the project's lookup.
1545:             * @return a subproject provider object suitable for the project lookup
1546:             * @see Project#getLookup
1547:             */
1548:            public SubprojectProvider createSubprojectProvider() {
1549:                return new SubprojectProviderImpl(this );
1550:            }
1551:
1552:            /**
1553:             * Access from SubprojectProviderImpl.
1554:             */
1555:            AntProjectHelper getAntProjectHelper() {
1556:                return h;
1557:            }
1558:
1559:            /**Tries to fix references after copy/rename/move operation on the project.
1560:             * Handles relative/absolute paths.
1561:             *
1562:             * @param originalPath the project folder of the original project
1563:             * @see org.netbeans.spi.project.CopyOperationImplementation
1564:             * @see org.netbeans.spi.project.MoveOperationImplementation
1565:             * @since 1.9
1566:             */
1567:            public void fixReferences(File originalPath) {
1568:                String[] prefixesToFix = new String[] { "file.reference.",
1569:                        "project." };
1570:                EditableProperties pub = h
1571:                        .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
1572:                EditableProperties priv = h
1573:                        .getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
1574:
1575:                File projectDir = FileUtil.toFile(h.getProjectDirectory());
1576:
1577:                List<String> pubRemove = new ArrayList<String>();
1578:                List<String> privRemove = new ArrayList<String>();
1579:                Map<String, String> pubAdd = new HashMap<String, String>();
1580:                Map<String, String> privAdd = new HashMap<String, String>();
1581:
1582:                for (Map.Entry<String, String> e : pub.entrySet()) {
1583:                    String key = e.getKey();
1584:                    boolean cont = false;
1585:
1586:                    for (String prefix : prefixesToFix) {
1587:                        if (key.startsWith(prefix)) {
1588:                            cont = true;
1589:                            break;
1590:                        }
1591:                    }
1592:                    if (!cont)
1593:                        continue;
1594:
1595:                    String value = e.getValue();
1596:
1597:                    File absolutePath = FileUtil.normalizeFile(PropertyUtils
1598:                            .resolveFile(originalPath, value));
1599:
1600:                    //TODO: extra base dir relativization:
1601:
1602:                    //mkleint: removed CollocationQuery.areCollocated() reference
1603:                    // when AlwaysRelativeCQI gets removed the condition resolves to false more frequently.
1604:                    // that might not be desirable.
1605:                    String rel = PropertyUtils.relativizeFile(projectDir,
1606:                            absolutePath);
1607:                    if (rel == null) {
1608:                        pubRemove.add(key);
1609:                        privAdd.put(key, absolutePath.getAbsolutePath());
1610:                    }
1611:                }
1612:
1613:                for (Map.Entry<String, String> e : pub.entrySet()) {
1614:                    String key = e.getKey();
1615:                    boolean cont = false;
1616:
1617:                    for (String prefix : prefixesToFix) {
1618:                        if (key.startsWith(prefix)) {
1619:                            cont = true;
1620:                            break;
1621:                        }
1622:                    }
1623:                    if (!cont)
1624:                        continue;
1625:
1626:                    String value = e.getValue();
1627:
1628:                    File absolutePath = FileUtil.normalizeFile(PropertyUtils
1629:                            .resolveFile(originalPath, value));
1630:
1631:                    if (absolutePath.getAbsolutePath().startsWith(
1632:                            originalPath.getAbsolutePath())) {
1633:                        //#65141: in private.properties, a full path into originalPath may be given, fix:
1634:                        String relative = PropertyUtils.relativizeFile(
1635:                                originalPath, absolutePath);
1636:
1637:                        absolutePath = FileUtil.normalizeFile(new File(
1638:                                projectDir, relative));
1639:
1640:                        privRemove.add(key);
1641:                        privAdd.put(key, absolutePath.getAbsolutePath());
1642:                    }
1643:
1644:                    //TODO: extra base dir relativization:
1645:
1646:                    //mkleint: removed CollocationQuery.areCollocated() reference
1647:                    // when AlwaysRelativeCQI gets removed the condition resolves to false more frequently.
1648:                    // that might not be desirable.            
1649:                    String rel = PropertyUtils.relativizeFile(projectDir,
1650:                            absolutePath);
1651:                    if (rel != null) {
1652:                        pubAdd.put(key, rel);
1653:                    }
1654:                }
1655:
1656:                for (String s : pubRemove) {
1657:                    pub.remove(s);
1658:                }
1659:
1660:                for (String s : privRemove) {
1661:                    priv.remove(s);
1662:                }
1663:
1664:                pub.putAll(pubAdd);
1665:                priv.putAll(privAdd);
1666:
1667:                h.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, pub);
1668:                h.putProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH, priv);
1669:            }
1670:
1671:            /**
1672:             * Create a reference to one volume of a library.
1673:             * @param library a library
1674:             * @param volumeType a legal volume type for that library
1675:             * @return substitutable Ant text suitable for inclusion in a properties file when also loading {@link AntProjectHelper#getProjectLibrariesPropertyProvider}
1676:             * @see #findLibrary
1677:             * @since org.netbeans.modules.project.ant/1 1.19
1678:             */
1679:            public String createLibraryReference(Library library,
1680:                    String volumeType) {
1681:                if (library.getManager() == LibraryManager.getDefault()) {
1682:                    if (h.isSharableProject()) {
1683:                        throw new IllegalArgumentException(
1684:                                "Project ["
1685:                                        + // NOI18N
1686:                                        h.getProjectDirectory()
1687:                                        + "] is sharable and cannot reference global library "
1688:                                        + library.getName()); // NOI18N
1689:                    }
1690:                } else {
1691:                    if (!ProjectLibraryProvider.isReachableLibrary(library, h)) {
1692:                        throw new IllegalArgumentException("Project ["
1693:                                + // NOI18N
1694:                                h.getProjectDirectory()
1695:                                + "] cannot reference a library from "
1696:                                + library.getManager().getLocation()); // NOI18N
1697:                    }
1698:                }
1699:                return "${libs." + library.getName() + "." + volumeType + "}"; // NOI18N
1700:            }
1701:
1702:            /**
1703:             * Gets a library manager corresponding to library definition file referred to from this project.
1704:             * There is no guarantee that the manager is the same object from call to call
1705:             * even if the location remain the same; in particular, it is <em>not</em> guaranteed that
1706:             * the manager match that returned from {@link Library#getManager} for libraries added
1707:             * from {@link #createLibraryReference}.
1708:             * @return a library manager associated with project's libraries or null if project is 
1709:             *  not shared (will not include {@link LibraryManager#getDefault})
1710:             * @see #createLibraryReference
1711:             * @see #findLibrary
1712:             * @since org.netbeans.modules.project.ant/1 1.19
1713:             */
1714:            public LibraryManager getProjectLibraryManager() {
1715:                return ProjectLibraryProvider.getProjectLibraryManager(h);
1716:            }
1717:
1718:            /**
1719:             * Gets a library manager of the given project.
1720:             * There is no guarantee that the manager is the same object from call to call
1721:             * even if the project is the same; in particular, it is <em>not</em> guaranteed that
1722:             * the manager match that returned from {@link Library#getManager} for libraries added
1723:             * from {@link #createLibraryReference}.
1724:             * @return a library manager associated with project's libraries or null if project is 
1725:             *  not shared (will not include {@link LibraryManager#getDefault})
1726:             *  {@link LibraryManager#getDefault})
1727:             * @since org.netbeans.modules.project.ant/1 1.19
1728:             */
1729:            public static LibraryManager getProjectLibraryManager(Project p) {
1730:                AuxiliaryConfiguration aux = p.getLookup().lookup(
1731:                        AuxiliaryConfiguration.class);
1732:                if (aux != null) {
1733:                    File libFile = ProjectLibraryProvider.getLibrariesLocation(
1734:                            aux, FileUtil.toFile(p.getProjectDirectory()));
1735:                    if (libFile != null) {
1736:                        try {
1737:                            return LibraryManager.forLocation(libFile.toURI()
1738:                                    .toURL());
1739:                        } catch (MalformedURLException e) {
1740:                            // ok, no project manager
1741:                            Logger.getLogger(ReferenceHelper.class.getName())
1742:                                    .info(
1743:                                            "library manager cannot be found for "
1744:                                                    + libFile + ". "
1745:                                                    + e.toString()); //NOI18N
1746:                        }
1747:                    }
1748:                }
1749:                return null;
1750:            }
1751:
1752:            /**
1753:             * Copy global IDE library to sharable libraries definition associated with
1754:             * this project. Does nothing if project is not sharable. 
1755:             * When a library with same name already exists in sharable location, the new one 
1756:             * is copied with generated unique name.
1757:             * 
1758:             * <p>Library creation is done under write access of ProjectManager.mutex().
1759:             * 
1760:             * @param lib global library; cannot be null
1761:             * @return newly created sharable version of library in case of sharable
1762:             *  project or given global library in case of non-sharable project
1763:             * @throws java.io.IOException if there was problem copying files
1764:             * @since org.netbeans.modules.project.ant/1 1.19
1765:             */
1766:            public Library copyLibrary(Library lib) throws IOException {
1767:                Parameters.notNull("lib", lib);
1768:                if (lib.getManager() != LibraryManager.getDefault()) {
1769:                    throw new IllegalArgumentException(
1770:                            "cannot copy non-global library "
1771:                                    + lib.getManager().getLocation()); // NOI18N
1772:                }
1773:                if (!h.isSharableProject()) {
1774:                    return lib;
1775:                }
1776:                File mainPropertiesFile = h.resolveFile(h
1777:                        .getLibrariesLocation());
1778:                return ProjectLibraryProvider.copyLibrary(lib,
1779:                        mainPropertiesFile.toURI().toURL(), true);
1780:            }
1781:
1782:            /**
1783:             * Returns library import handler which imports global library to sharable
1784:             * one. See {@link LibraryChooser#showDialog} for usage of this handler.
1785:             * @return copy handler
1786:             * @since org.netbeans.modules.project.ant/1 1.19
1787:             */
1788:            public LibraryChooser.LibraryImportHandler getLibraryChooserImportHandler() {
1789:                return new LibraryChooser.LibraryImportHandler() {
1790:                    public Library importLibrary(Library library)
1791:                            throws IOException {
1792:                        return copyLibrary(library);
1793:                    }
1794:                };
1795:            }
1796:
1797:            /**
1798:             * Tries to find a library by name in library manager associated with the project.
1799:             * It is <em>not</em> guaranteed that any returned library is an identical object to one which passed in to {@link #createLibraryReference}.
1800:             * @param name either a bare {@link Library#getName}, or a reference as created by {@link #createLibraryReference}
1801:             * @return the first library to be found matching that name, or null if not found
1802:             * @since org.netbeans.modules.project.ant/1 1.19
1803:             */
1804:            public Library findLibrary(String name) {
1805:                Matcher m = LIBRARY_REFERENCE.matcher(name);
1806:                if (m.matches()) {
1807:                    name = m.group(1);
1808:                }
1809:                LibraryManager mgr = getProjectLibraryManager();
1810:                if (mgr == null) {
1811:                    return LibraryManager.getDefault().getLibrary(name);
1812:                } else {
1813:                    return mgr.getLibrary(name);
1814:                }
1815:            }
1816:
1817:            /**
1818:             * A raw reference descriptor representing a link to a foreign project
1819:             * and some build artifact used from it.
1820:             * This class corresponds directly to what it stored in <code>project.xml</code>
1821:             * to refer to a target in a foreign project.
1822:             * See {@link AntArtifact} for the precise meaning of several of the fields in this class.
1823:             */
1824:            public static final class RawReference {
1825:
1826:                private final String foreignProjectName;
1827:                private final String artifactType;
1828:                private URI scriptLocation;
1829:                // introduced in /2 version
1830:                private String newScriptLocation;
1831:                private final String targetName;
1832:                private final String cleanTargetName;
1833:                private final String artifactID;
1834:                private final Properties props;
1835:
1836:                /**
1837:                 * Create a raw reference descriptor.
1838:                 * As this is basically just a struct, does no real work.
1839:                 * @param foreignProjectName the name of the foreign project (usually its code name)
1840:                 * @param artifactType the {@link AntArtifact#getType type} of the build artifact
1841:                 * @param scriptLocation the relative URI to the build script from the project directory
1842:                 * @param targetName the Ant target name
1843:                 * @param cleanTargetName the Ant clean target name
1844:                 * @param artifactID the {@link AntArtifact#getID ID} of the build artifact
1845:                 * @throws IllegalArgumentException if the script location is given an absolute URI
1846:                 */
1847:                public RawReference(String foreignProjectName,
1848:                        String artifactType, URI scriptLocation,
1849:                        String targetName, String cleanTargetName,
1850:                        String artifactID) throws IllegalArgumentException {
1851:                    this (foreignProjectName, artifactType, scriptLocation,
1852:                            null, targetName, cleanTargetName, artifactID,
1853:                            new Properties());
1854:                }
1855:
1856:                /**
1857:                 * Create a raw reference descriptor.
1858:                 * As this is basically just a struct, does no real work.
1859:                 * @param foreignProjectName the name of the foreign project (usually its code name)
1860:                 * @param artifactType the {@link AntArtifact#getType type} of the build artifact
1861:                 * @param newScriptLocation absolute path to the build script; can contain Ant-like properties
1862:                 * @param targetName the Ant target name
1863:                 * @param cleanTargetName the Ant clean target name
1864:                 * @param artifactID the {@link AntArtifact#getID ID} of the build artifact
1865:                 * @param props optional properties to be used for target execution; never null
1866:                 * @throws IllegalArgumentException if the script location is given an absolute URI
1867:                 * @since 1.5
1868:                 */
1869:                public RawReference(String foreignProjectName,
1870:                        String artifactType, String newScriptLocation,
1871:                        String targetName, String cleanTargetName,
1872:                        String artifactID, Properties props)
1873:                        throws IllegalArgumentException {
1874:                    this (foreignProjectName, artifactType, null,
1875:                            newScriptLocation, targetName, cleanTargetName,
1876:                            artifactID, props);
1877:                }
1878:
1879:                private RawReference(String foreignProjectName,
1880:                        String artifactType, URI scriptLocation,
1881:                        String newScriptLocation, String targetName,
1882:                        String cleanTargetName, String artifactID,
1883:                        Properties props) throws IllegalArgumentException {
1884:                    this .foreignProjectName = foreignProjectName;
1885:                    this .artifactType = artifactType;
1886:                    if (scriptLocation != null && scriptLocation.isAbsolute()) {
1887:                        throw new IllegalArgumentException(
1888:                                "Cannot use an absolute URI " + scriptLocation
1889:                                        + " for script location"); // NOI18N
1890:                    }
1891:                    this .scriptLocation = scriptLocation;
1892:                    this .newScriptLocation = newScriptLocation;
1893:                    this .targetName = targetName;
1894:                    this .cleanTargetName = cleanTargetName;
1895:                    this .artifactID = artifactID;
1896:                    this .props = props;
1897:                }
1898:
1899:                private static final List/*<String>*/SUB_ELEMENT_NAMES = Arrays
1900:                        .asList(new String[] { "foreign-project", // NOI18N
1901:                                "artifact-type", // NOI18N
1902:                                "script", // NOI18N
1903:                                "target", // NOI18N
1904:                                "clean-target", // NOI18N
1905:                                "id", // NOI18N
1906:                        });
1907:
1908:                /**
1909:                 * Create a RawReference by parsing an XML &lt;reference&gt; fragment.
1910:                 * @throws IllegalArgumentException if anything is missing or duplicated or malformed etc.
1911:                 */
1912:                static RawReference create(Element xml)
1913:                        throws IllegalArgumentException {
1914:                    if (REFS_NS.equals(xml.getNamespaceURI())) {
1915:                        return create1(xml);
1916:                    } else {
1917:                        return create2(xml);
1918:                    }
1919:                }
1920:
1921:                private static RawReference create1(Element xml)
1922:                        throws IllegalArgumentException {
1923:                    if (!REF_NAME.equals(xml.getLocalName())
1924:                            || !REFS_NS.equals(xml.getNamespaceURI())) {
1925:                        throw new IllegalArgumentException("bad element name: "
1926:                                + xml); // NOI18N
1927:                    }
1928:                    NodeList nl = xml.getElementsByTagNameNS("*", "*"); // NOI18N
1929:                    if (nl.getLength() != 6) {
1930:                        throw new IllegalArgumentException(
1931:                                "missing or extra data: " + xml); // NOI18N
1932:                    }
1933:                    String[] values = new String[nl.getLength()];
1934:                    for (int i = 0; i < nl.getLength(); i++) {
1935:                        Element el = (Element) nl.item(i);
1936:                        if (!REFS_NS.equals(el.getNamespaceURI())) {
1937:                            throw new IllegalArgumentException(
1938:                                    "bad subelement ns: " + el); // NOI18N
1939:                        }
1940:                        String elName = el.getLocalName();
1941:                        int idx = SUB_ELEMENT_NAMES.indexOf(elName);
1942:                        if (idx == -1) {
1943:                            throw new IllegalArgumentException(
1944:                                    "bad subelement name: " + elName); // NOI18N
1945:                        }
1946:                        String val = Util.findText(el);
1947:                        if (val == null) {
1948:                            throw new IllegalArgumentException(
1949:                                    "empty subelement: " + el); // NOI18N
1950:                        }
1951:                        if (values[idx] != null) {
1952:                            throw new IllegalArgumentException("duplicate "
1953:                                    + elName + ": " + values[idx] + " and "
1954:                                    + val); // NOI18N
1955:                        }
1956:                        values[idx] = val;
1957:                    }
1958:                    assert !Arrays.asList(values).contains(null);
1959:                    URI scriptLocation = URI.create(values[2]); // throws IllegalArgumentException
1960:                    return new RawReference(values[0], values[1],
1961:                            scriptLocation, values[3], values[4], values[5]);
1962:                }
1963:
1964:                private static RawReference create2(Element xml)
1965:                        throws IllegalArgumentException {
1966:                    if (!REF_NAME.equals(xml.getLocalName())
1967:                            || !REFS_NS2.equals(xml.getNamespaceURI())) {
1968:                        throw new IllegalArgumentException("bad element name: "
1969:                                + xml); // NOI18N
1970:                    }
1971:                    List nl = Util.findSubElements(xml);
1972:                    if (nl.size() < 6) {
1973:                        throw new IllegalArgumentException(
1974:                                "missing or extra data: " + xml); // NOI18N
1975:                    }
1976:                    String[] values = new String[6];
1977:                    for (int i = 0; i < 6; i++) {
1978:                        Element el = (Element) nl.get(i);
1979:                        if (!REFS_NS2.equals(el.getNamespaceURI())) {
1980:                            throw new IllegalArgumentException(
1981:                                    "bad subelement ns: " + el); // NOI18N
1982:                        }
1983:                        String elName = el.getLocalName();
1984:                        int idx = SUB_ELEMENT_NAMES.indexOf(elName);
1985:                        if (idx == -1) {
1986:                            throw new IllegalArgumentException(
1987:                                    "bad subelement name: " + elName); // NOI18N
1988:                        }
1989:                        String val = Util.findText(el);
1990:                        if (val == null) {
1991:                            throw new IllegalArgumentException(
1992:                                    "empty subelement: " + el); // NOI18N
1993:                        }
1994:                        if (values[idx] != null) {
1995:                            throw new IllegalArgumentException("duplicate "
1996:                                    + elName + ": " + values[idx] + " and "
1997:                                    + val); // NOI18N
1998:                        }
1999:                        values[idx] = val;
2000:                    }
2001:                    Properties props = new Properties();
2002:                    if (nl.size() == 7) {
2003:                        Element el = (Element) nl.get(6);
2004:                        if (!REFS_NS2.equals(el.getNamespaceURI())) {
2005:                            throw new IllegalArgumentException(
2006:                                    "bad subelement ns: " + el); // NOI18N
2007:                        }
2008:                        if (!"properties".equals(el.getLocalName())) { // NOI18N
2009:                            throw new IllegalArgumentException(
2010:                                    "bad subelement. expected 'properties': "
2011:                                            + el); // NOI18N
2012:                        }
2013:                        for (Element el2 : Util.findSubElements(el)) {
2014:                            String key = el2.getAttribute("name");
2015:                            String value = Util.findText(el2);
2016:                            // #53553: NPE
2017:                            if (value == null) {
2018:                                value = ""; // NOI18N
2019:                            }
2020:                            props.setProperty(key, value);
2021:                        }
2022:                    }
2023:                    assert !Arrays.asList(values).contains(null);
2024:                    return new RawReference(values[0], values[1], values[2],
2025:                            values[3], values[4], values[5], props);
2026:                }
2027:
2028:                /**
2029:                 * Write a RawReference as an XML &lt;reference&gt; fragment.
2030:                 */
2031:                Element toXml(String namespace, Document ownerDocument) {
2032:                    Element el = ownerDocument.createElementNS(namespace,
2033:                            REF_NAME);
2034:                    String[] values = {
2035:                            foreignProjectName,
2036:                            artifactType,
2037:                            newScriptLocation != null ? newScriptLocation
2038:                                    : scriptLocation.toString(), targetName,
2039:                            cleanTargetName, artifactID, };
2040:                    for (int i = 0; i < 6; i++) {
2041:                        Element subel = ownerDocument.createElementNS(
2042:                                namespace, (String) SUB_ELEMENT_NAMES.get(i));
2043:                        subel.appendChild(ownerDocument
2044:                                .createTextNode(values[i]));
2045:                        el.appendChild(subel);
2046:                    }
2047:                    if (props.keySet().size() > 0) {
2048:                        assert namespace.equals(REFS_NS2) : "can happen only in /2"; // NOI18N
2049:                        Element propEls = ownerDocument.createElementNS(
2050:                                namespace, "properties"); // NOI18N
2051:                        el.appendChild(propEls);
2052:                        for (String key : new TreeSet<String>(NbCollections
2053:                                .checkedSetByFilter(props.keySet(),
2054:                                        String.class, true))) {
2055:                            Element propEl = ownerDocument.createElementNS(
2056:                                    namespace, "property"); // NOI18N
2057:                            propEl.appendChild(ownerDocument
2058:                                    .createTextNode(props.getProperty(key)));
2059:                            propEl.setAttribute("name", key); // NOI18N
2060:                            propEls.appendChild(propEl);
2061:                        }
2062:                    }
2063:                    return el;
2064:                }
2065:
2066:                private String getNS() {
2067:                    if (newScriptLocation != null) {
2068:                        return REFS_NS2;
2069:                    } else {
2070:                        return REFS_NS;
2071:                    }
2072:                }
2073:
2074:                /**
2075:                 * Get the name of the foreign project as referred to from this project.
2076:                 * Usually this will be the code name of the foreign project, but it may
2077:                 * instead be a uniquified name.
2078:                 * The name can be used in project properties and the build script to refer
2079:                 * to the foreign project from among subprojects.
2080:                 * @return the foreign project name
2081:                 */
2082:                public String getForeignProjectName() {
2083:                    return foreignProjectName;
2084:                }
2085:
2086:                /**
2087:                 * Get the type of the foreign project's build artifact.
2088:                 * For example, <a href="@JAVA/PROJECT@/org/netbeans/api/java/project/JavaProjectConstants.html#ARTIFACT_TYPE_JAR"><code>JavaProjectConstants.ARTIFACT_TYPE_JAR</code></a>.
2089:                 * @return the artifact type
2090:                 */
2091:                public String getArtifactType() {
2092:                    return artifactType;
2093:                }
2094:
2095:                /**
2096:                 * Get the location of the foreign project's build script relative to the
2097:                 * project directory.
2098:                 * This is the script which would be called to build the desired artifact.
2099:                 * @return the script location
2100:                 * @deprecated use {@link #getScriptLocationValue} instead; may return null now
2101:                 */
2102:                @Deprecated
2103:                public URI getScriptLocation() {
2104:                    return scriptLocation;
2105:                }
2106:
2107:                /**
2108:                 * Get absolute path location of the foreign project's build script.
2109:                 * This is the script which would be called to build the desired artifact.
2110:                 * @return absolute path possibly containing Ant properties
2111:                 */
2112:                public String getScriptLocationValue() {
2113:                    if (newScriptLocation != null) {
2114:                        return newScriptLocation;
2115:                    } else {
2116:                        return "${project." + foreignProjectName + "}/"
2117:                                + scriptLocation.toString();
2118:                    }
2119:                }
2120:
2121:                /**
2122:                 * Get the Ant target name to build the artifact.
2123:                 * @return the target name
2124:                 */
2125:                public String getTargetName() {
2126:                    return targetName;
2127:                }
2128:
2129:                /**
2130:                 * Get the Ant target name to clean the artifact.
2131:                 * @return the clean target name
2132:                 */
2133:                public String getCleanTargetName() {
2134:                    return cleanTargetName;
2135:                }
2136:
2137:                /**
2138:                 * Get the ID of the foreign project's build artifact.
2139:                 * See also {@link AntArtifact#getID}.
2140:                 * @return the artifact identifier
2141:                 */
2142:                public String getID() {
2143:                    return artifactID;
2144:                }
2145:
2146:                /**
2147:                 * Get an extra properties used for target execution.
2148:                 * @return a set of properties (may be empty but not null)
2149:                 */
2150:                public Properties getProperties() {
2151:                    return props;
2152:                }
2153:
2154:                /**
2155:                 * Attempt to convert this reference to a live artifact object.
2156:                 * This involves finding the referenced foreign project on disk
2157:                 * (among standard project and private properties) and asking it
2158:                 * for the artifact named by the given target.
2159:                 * Given that object, you can find important further information
2160:                 * such as the location of the actual artifact on disk.
2161:                 * <p>
2162:                 * Note that non-key attributes of the returned artifact (i.e.
2163:                 * type, script location, and clean target name) might not match
2164:                 * those in this raw reference.
2165:                 * <p>
2166:                 * Acquires read access.
2167:                 * @param helper an associated reference helper used to resolve the foreign
2168:                 *               project location
2169:                 * @return the actual Ant artifact object, or null if it could not be located
2170:                 */
2171:                public AntArtifact toAntArtifact(final ReferenceHelper helper) {
2172:                    return ProjectManager.mutex().readAccess(
2173:                            new Mutex.Action<AntArtifact>() {
2174:                                public AntArtifact run() {
2175:                                    AntProjectHelper h = helper.h;
2176:                                    String path = helper.eval
2177:                                            .getProperty("project."
2178:                                                    + foreignProjectName); // NOI18N
2179:                                    if (path == null) {
2180:                                        // Undefined foreign project.
2181:                                        return null;
2182:                                    }
2183:                                    FileObject foreignProjectDir = h
2184:                                            .resolveFileObject(path);
2185:                                    if (foreignProjectDir == null) {
2186:                                        // Nonexistent foreign project dir.
2187:                                        return null;
2188:                                    }
2189:                                    Project p;
2190:                                    try {
2191:                                        p = ProjectManager.getDefault()
2192:                                                .findProject(foreignProjectDir);
2193:                                    } catch (IOException e) {
2194:                                        // Could not load it.
2195:                                        ErrorManager.getDefault().notify(
2196:                                                ErrorManager.INFORMATIONAL, e);
2197:                                        return null;
2198:                                    }
2199:                                    if (p == null) {
2200:                                        // Was not a project dir.
2201:                                        return null;
2202:                                    }
2203:                                    return AntArtifactQuery.findArtifactByID(p,
2204:                                            artifactID);
2205:                                }
2206:                            });
2207:                }
2208:
2209:                private void upgrade() {
2210:                    assert newScriptLocation == null && scriptLocation != null : "was already upgraded "
2211:                            + this ;
2212:                    newScriptLocation = "${project." + foreignProjectName
2213:                            + "}/" + scriptLocation.toString(); // NOI18N
2214:                    scriptLocation = null;
2215:                }
2216:
2217:                public @Override
2218:                String toString() {
2219:                    return "ReferenceHelper.RawReference<" + foreignProjectName
2220:                            + "," + artifactType + "," + newScriptLocation != null ? newScriptLocation
2221:                            : scriptLocation + "," + targetName + ","
2222:                                    + cleanTargetName + "," + artifactID + ">"; // NOI18N
2223:                }
2224:
2225:            }
2226:
2227:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.