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