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.apisupport.project;
0043:
0044: import java.beans.PropertyChangeEvent;
0045: import java.beans.PropertyChangeListener;
0046: import java.beans.PropertyChangeSupport;
0047: import java.io.File;
0048: import java.io.IOException;
0049: import java.net.URI;
0050: import java.net.URL;
0051: import java.util.Arrays;
0052: import java.util.Enumeration;
0053: import java.util.HashMap;
0054: import java.util.Iterator;
0055: import java.util.Map;
0056: import java.util.WeakHashMap;
0057: import java.util.jar.Manifest;
0058: import java.util.logging.Level;
0059: import java.util.logging.Logger;
0060: import javax.swing.Icon;
0061: import javax.swing.ImageIcon;
0062: import org.netbeans.api.java.classpath.ClassPath;
0063: import org.netbeans.api.java.classpath.GlobalPathRegistry;
0064: import org.netbeans.api.java.project.JavaProjectConstants;
0065: import org.netbeans.api.project.FileOwnerQuery;
0066: import org.netbeans.api.project.Project;
0067: import org.netbeans.api.project.ProjectManager;
0068: import org.netbeans.api.project.ProjectInformation;
0069: import org.netbeans.modules.apisupport.project.spi.NbModuleProvider.NbModuleType;
0070: import org.netbeans.modules.apisupport.project.metainf.ServiceNodeHandler;
0071: import org.netbeans.modules.apisupport.project.queries.ModuleProjectClassPathExtender;
0072: import org.netbeans.modules.apisupport.project.ui.customizer.CustomizerProviderImpl;
0073: import org.netbeans.modules.apisupport.project.ui.customizer.SingleModuleProperties;
0074: import org.netbeans.spi.project.AuxiliaryConfiguration;
0075: import org.netbeans.spi.project.support.ant.AntProjectEvent;
0076: import org.netbeans.spi.project.support.ant.AntProjectHelper;
0077: import org.netbeans.spi.project.support.ant.AntProjectListener;
0078: import org.netbeans.spi.project.support.ant.EditableProperties;
0079: import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
0080: import org.netbeans.spi.project.support.ant.ProjectXmlSavedHook;
0081: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
0082: import org.netbeans.spi.project.support.ant.SourcesHelper;
0083: import org.netbeans.spi.project.ui.PrivilegedTemplates;
0084: import org.netbeans.spi.project.ui.ProjectOpenedHook;
0085: import org.netbeans.spi.queries.FileBuiltQueryImplementation;
0086: import org.openide.ErrorManager;
0087: import org.openide.filesystems.FileChangeAdapter;
0088: import org.openide.filesystems.FileEvent;
0089: import org.openide.filesystems.FileObject;
0090: import org.openide.filesystems.FileUtil;
0091: import org.openide.util.Lookup;
0092: import org.openide.util.Mutex;
0093: import org.openide.util.NbBundle;
0094: import org.openide.util.Utilities;
0095: import org.openide.util.lookup.Lookups;
0096: import org.w3c.dom.Element;
0097: import org.netbeans.modules.apisupport.project.queries.AccessibilityQueryImpl;
0098: import org.netbeans.modules.apisupport.project.queries.UnitTestForSourceQueryImpl;
0099: import org.netbeans.modules.apisupport.project.queries.SourceLevelQueryImpl;
0100: import org.netbeans.modules.apisupport.project.queries.AntArtifactProviderImpl;
0101: import org.netbeans.modules.apisupport.project.queries.ClassPathProviderImpl;
0102: import org.netbeans.modules.apisupport.project.queries.FileEncodingQueryImpl;
0103: import org.netbeans.modules.apisupport.project.queries.JavadocForBinaryImpl;
0104: import org.netbeans.modules.apisupport.project.queries.SourceForBinaryImpl;
0105: import org.netbeans.modules.apisupport.project.queries.SubprojectProviderImpl;
0106: import org.netbeans.modules.apisupport.project.queries.TemplateAttributesProvider;
0107: import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
0108: import org.netbeans.modules.apisupport.project.universe.NbPlatform;
0109: import org.netbeans.modules.apisupport.project.universe.ModuleList;
0110: import org.netbeans.modules.apisupport.project.ui.ModuleActions;
0111: import org.netbeans.modules.apisupport.project.ui.ModuleLogicalView;
0112: import org.netbeans.modules.apisupport.project.ui.ModuleOperations;
0113: import org.netbeans.modules.apisupport.project.universe.LocalizedBundleInfo;
0114: import org.netbeans.modules.apisupport.project.universe.ModuleEntry;
0115: import org.netbeans.spi.project.support.LookupProviderSupport;
0116: import org.netbeans.spi.project.ui.RecommendedTemplates;
0117: import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
0118: import org.openide.modules.SpecificationVersion;
0119: import org.openide.util.Exceptions;
0120:
0121: /**
0122: * A NetBeans module project.
0123: * @author Jesse Glick
0124: */
0125: public final class NbModuleProject implements Project {
0126:
0127: public static final String NB_PROJECT_ICON_PATH = "org/netbeans/modules/apisupport/project/resources/module.png"; // NOI18N
0128:
0129: private static final Icon NB_PROJECT_ICON = new ImageIcon(Utilities
0130: .loadImage(NB_PROJECT_ICON_PATH));
0131:
0132: public static final String SOURCES_TYPE_JAVAHELP = "javahelp"; // NOI18N
0133:
0134: private final AntProjectHelper helper;
0135: private final Evaluator eval;
0136: private final Lookup lookup;
0137: private Map<FileObject, Element> extraCompilationUnits;
0138: private final GeneratedFilesHelper genFilesHelper;
0139: private final NbModuleProviderImpl typeProvider;
0140:
0141: NbModuleProject(AntProjectHelper helper) throws IOException {
0142: AuxiliaryConfiguration aux = helper
0143: .createAuxiliaryConfiguration();
0144: for (int v = 4; v < 10; v++) {
0145: if (aux
0146: .getConfigurationFragment("data",
0147: "http://www.netbeans.org/ns/nb-module-project/"
0148: + v, true) != null) { // NOI18N
0149: throw Exceptions
0150: .attachLocalizedMessage(
0151: new IOException("too new"), // NOI18N
0152: NbBundle
0153: .getMessage(
0154: NbModuleProject.class,
0155: "NbModuleProject.too_new",
0156: FileUtil
0157: .getFileDisplayName(helper
0158: .getProjectDirectory())));
0159: }
0160: }
0161: this .helper = helper;
0162: genFilesHelper = new GeneratedFilesHelper(helper);
0163: Util.err.log("Loading project in " + getProjectDirectory());
0164: if (getCodeNameBase() == null) {
0165: throw new IOException("Misconfigured project in "
0166: + FileUtil
0167: .getFileDisplayName(getProjectDirectory())
0168: + " has no defined <code-name-base>"); // NOI18N
0169: }
0170: typeProvider = new NbModuleProviderImpl();
0171: if (typeProvider.getModuleType() == NbModuleProvider.NETBEANS_ORG
0172: && ModuleList
0173: .findNetBeansOrg(getProjectDirectoryFile()) == null) {
0174: // #69097: preferable to throwing an assertion error later...
0175: throw new IOException(
0176: "netbeans.org-type module not in a complete netbeans.org source root: "
0177: + this ); // NOI18N
0178: }
0179: eval = new Evaluator(this , typeProvider);
0180: FileBuiltQueryImplementation fileBuilt;
0181: // XXX could add globs for other package roots too
0182: if (supportsUnitTests()) {
0183: fileBuilt = helper.createGlobFileBuiltQuery(eval,
0184: new String[] { "${src.dir}/*.java", // NOI18N
0185: "${test.unit.src.dir}/*.java", // NOI18N
0186: }, new String[] { "${build.classes.dir}/*.class", // NOI18N
0187: "${build.test.unit.classes.dir}/*.class", // NOI18N
0188: });
0189: } else {
0190: fileBuilt = helper.createGlobFileBuiltQuery(eval,
0191: new String[] { "${src.dir}/*.java", // NOI18N
0192: }, new String[] { "${build.classes.dir}/*.class", // NOI18N
0193: });
0194: }
0195: final SourcesHelper sourcesHelper = new SourcesHelper(helper,
0196: eval);
0197: // Temp build dir is always internal; NBM build products go elsewhere, but
0198: // difficult to predict statically exactly what they are!
0199: // XXX would be good to mark at least the module JAR as owned by this project
0200: // (currently FOQ/SH do not support that)
0201: sourcesHelper.addPrincipalSourceRoot("${src.dir}", NbBundle
0202: .getMessage(NbModuleProject.class,
0203: "LBL_source_packages"), null, null); // #56457
0204: sourcesHelper.addPrincipalSourceRoot("${test.unit.src.dir}",
0205: NbBundle.getMessage(NbModuleProject.class,
0206: "LBL_unit_test_packages"), null, null); // #68727
0207: sourcesHelper.addTypedSourceRoot("${src.dir}",
0208: JavaProjectConstants.SOURCES_TYPE_JAVA, NbBundle
0209: .getMessage(NbModuleProject.class,
0210: "LBL_source_packages"), null, null);
0211: // XXX other principal source roots, as needed...
0212: sourcesHelper.addTypedSourceRoot("${test.unit.src.dir}",
0213: JavaProjectConstants.SOURCES_TYPE_JAVA, NbBundle
0214: .getMessage(NbModuleProject.class,
0215: "LBL_unit_test_packages"), null, null);
0216: sourcesHelper.addTypedSourceRoot(
0217: "${test.qa-functional.src.dir}",
0218: JavaProjectConstants.SOURCES_TYPE_JAVA, NbBundle
0219: .getMessage(NbModuleProject.class,
0220: "LBL_functional_test_packages"), null,
0221: null);
0222: sourcesHelper.addTypedSourceRoot(
0223: "${test.qa-performance.src.dir}",
0224: JavaProjectConstants.SOURCES_TYPE_JAVA, NbBundle
0225: .getMessage(NbModuleProject.class,
0226: "LBL_performance_test_packages"), null,
0227: null);
0228: // #42332: also any other misc. test dirs (just add source roots, no CP etc. for now)
0229: FileObject testDir = helper.getProjectDirectory()
0230: .getFileObject("test"); // NOI18N
0231: if (testDir != null) {
0232: Enumeration<? extends FileObject> kids = testDir
0233: .getChildren(false);
0234: while (kids.hasMoreElements()) {
0235: FileObject testSubdir = (FileObject) kids.nextElement();
0236: if (!testSubdir.isFolder()) {
0237: continue;
0238: }
0239: String name = testSubdir.getNameExt();
0240: if (testDir.getFileObject("build-" + name + ".xml") == null) { // NOI18N
0241: continue;
0242: }
0243: if (name.equals("unit") || name.equals("qa-functional")
0244: || name.equals("qa-performance")) { // NOI18N
0245: // Already handled specially.
0246: continue;
0247: }
0248: sourcesHelper.addTypedSourceRoot("test/" + name
0249: + "/src",
0250: JavaProjectConstants.SOURCES_TYPE_JAVA,
0251: NbBundle.getMessage(NbModuleProject.class,
0252: "LBL_unknown_test_packages", name),
0253: null, null);
0254: }
0255: }
0256: if (helper.resolveFileObject("javahelp/manifest.mf") == null) { // NOI18N
0257: // Special hack for core - ignore core/javahelp
0258: sourcesHelper.addTypedSourceRoot("javahelp",
0259: SOURCES_TYPE_JAVAHELP, NbBundle.getMessage(
0260: NbModuleProject.class,
0261: "LBL_javahelp_packages"), null, null);
0262: }
0263: Iterator it = getExtraCompilationUnits().entrySet().iterator();
0264: while (it.hasNext()) {
0265: Map.Entry entry = (Map.Entry) it.next();
0266: Element ecu = (Element) entry.getValue();
0267: Element pkgrootEl = Util.findElement(ecu, "package-root",
0268: NbModuleProjectType.NAMESPACE_SHARED); // NOI18N
0269: String pkgrootS = Util.findText(pkgrootEl);
0270: FileObject pkgroot = (FileObject) entry.getKey();
0271: sourcesHelper.addTypedSourceRoot(pkgrootS,
0272: JavaProjectConstants.SOURCES_TYPE_JAVA, /* XXX should schema incl. display name? */
0273: pkgroot.getNameExt(), null, null);
0274: }
0275: // #56457: support external source roots too.
0276: ProjectManager.mutex().postWriteRequest(new Runnable() {
0277: public void run() {
0278: sourcesHelper
0279: .registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT);
0280: }
0281: });
0282: Lookup baseLookup = Lookups.fixed(this , new Info(), aux, helper
0283: .createCacheDirectoryProvider(), new SavedHook(),
0284: UILookupMergerSupport
0285: .createProjectOpenHookMerger(new OpenedHook()),
0286: new ModuleActions(this ),
0287: new ClassPathProviderImpl(this ),
0288: new SourceForBinaryImpl(this ),
0289: new JavadocForBinaryImpl(this ),
0290: new UnitTestForSourceQueryImpl(this ),
0291: new ModuleLogicalView(this ),
0292: new SubprojectProviderImpl(this ), fileBuilt,
0293: new AccessibilityQueryImpl(this ),
0294: new SourceLevelQueryImpl(this ), helper
0295: .createSharabilityQuery(evaluator(),
0296: new String[0], new String[] {
0297: // currently these are hardcoded
0298: "build", // NOI18N
0299: }), sourcesHelper.createSources(),
0300: new AntArtifactProviderImpl(this , helper, evaluator()),
0301: new CustomizerProviderImpl(this , getHelper(),
0302: evaluator()), new SuiteProviderImpl(),
0303: typeProvider, new PrivilegedTemplatesImpl(),
0304: new ModuleProjectClassPathExtender(this ),
0305: new LocalizedBundleInfoProvider(),
0306: new ModuleOperations(this ), new ServiceNodeHandler(
0307: this , typeProvider), LookupProviderSupport
0308: .createSourcesMerger(), UILookupMergerSupport
0309: .createPrivilegedTemplatesMerger(),
0310: UILookupMergerSupport
0311: .createRecommendedTemplatesMerger(),
0312: new TemplateAttributesProvider(getHelper(),
0313: getModuleType() == NbModuleType.NETBEANS_ORG),
0314: new FileEncodingQueryImpl());
0315: lookup = LookupProviderSupport
0316: .createCompositeLookup(baseLookup,
0317: "Projects/org-netbeans-modules-apisupport-project/Lookup"); //NOI18N
0318: }
0319:
0320: public @Override
0321: String toString() {
0322: return "NbModuleProject[" + getProjectDirectory() + "]"; // NOI18N
0323: }
0324:
0325: public Lookup getLookup() {
0326: return lookup;
0327: }
0328:
0329: public FileObject getProjectDirectory() {
0330: return helper.getProjectDirectory();
0331: }
0332:
0333: public File getProjectDirectoryFile() {
0334: return FileUtil.toFile(getProjectDirectory());
0335: }
0336:
0337: /**
0338: * Get the minimum harness version required to work with this module.
0339: */
0340: public int getMinimumHarnessVersion() {
0341: if (helper.createAuxiliaryConfiguration()
0342: .getConfigurationFragment(
0343: NbModuleProjectType.NAME_SHARED,
0344: NbModuleProjectType.NAMESPACE_SHARED_2, true) != null) {
0345: return NbPlatform.HARNESS_VERSION_50;
0346: } else {
0347: return NbPlatform.HARNESS_VERSION_55u1;
0348: }
0349: }
0350:
0351: /**
0352: * Replacement for {@link AntProjectHelper#getPrimaryConfigurationData}
0353: * taking into account the /2 -> /3 upgrade.
0354: */
0355: public Element getPrimaryConfigurationData() {
0356: return ProjectManager.mutex().readAccess(
0357: new Mutex.Action<Element>() {
0358: public Element run() {
0359: AuxiliaryConfiguration ac = helper
0360: .createAuxiliaryConfiguration();
0361: Element data = ac.getConfigurationFragment(
0362: NbModuleProjectType.NAME_SHARED,
0363: NbModuleProjectType.NAMESPACE_SHARED_2,
0364: true);
0365: if (data != null) {
0366: return Util
0367: .translateXML(
0368: data,
0369: NbModuleProjectType.NAMESPACE_SHARED);
0370: } else {
0371: return helper
0372: .getPrimaryConfigurationData(true);
0373: }
0374: }
0375: });
0376: }
0377:
0378: /**
0379: * Replacement for {@link AntProjectHelper#putPrimaryConfigurationData}
0380: * taking into account the /2 -> /3 upgrade.
0381: */
0382: public void putPrimaryConfigurationData(final Element data) {
0383: ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
0384: public Void run() {
0385: AuxiliaryConfiguration ac = helper
0386: .createAuxiliaryConfiguration();
0387: if (ac.getConfigurationFragment(
0388: NbModuleProjectType.NAME_SHARED,
0389: NbModuleProjectType.NAMESPACE_SHARED_2, true) != null) {
0390: ac.putConfigurationFragment(Util.translateXML(data,
0391: NbModuleProjectType.NAMESPACE_SHARED_2),
0392: true);
0393: } else {
0394: helper.putPrimaryConfigurationData(data, true);
0395: }
0396: return null;
0397: }
0398: });
0399: }
0400:
0401: /** Returns a relative path to a project's source directory. */
0402: public String getSourceDirectoryPath() {
0403: return evaluator().getProperty("src.dir"); // NOI18N
0404: }
0405:
0406: private NbModuleProvider.NbModuleType getModuleType() {
0407: Element data = getPrimaryConfigurationData();
0408: if (Util.findElement(data, "suite-component",
0409: NbModuleProjectType.NAMESPACE_SHARED) != null) { // NOI18N
0410: return NbModuleProvider.SUITE_COMPONENT;
0411: } else if (Util.findElement(data, "standalone",
0412: NbModuleProjectType.NAMESPACE_SHARED) != null) { // NOI18N
0413: return NbModuleProvider.STANDALONE;
0414: } else {
0415: return NbModuleProvider.NETBEANS_ORG;
0416: }
0417: }
0418:
0419: public FileObject getManifestFile() {
0420: return helper.resolveFileObject(evaluator().getProperty(
0421: "manifest.mf")); // NOI18N
0422: }
0423:
0424: public Manifest getManifest() {
0425: return Util.getManifest(getManifestFile());
0426: }
0427:
0428: public AntProjectHelper getHelper() {
0429: return helper;
0430: }
0431:
0432: public PropertyEvaluator evaluator() {
0433: return eval;
0434: }
0435:
0436: private final Map<String, FileObject> directoryCache = new WeakHashMap<String, FileObject>();
0437:
0438: private FileObject getDir(String prop) {
0439: // XXX also add a PropertyChangeListener to eval and clear the cache of changed props
0440: if (directoryCache.containsKey(prop)) {
0441: return directoryCache.get(prop);
0442: } else {
0443: String v = evaluator().getProperty(prop);
0444: assert v != null : "No value for " + prop;
0445: FileObject f = helper.resolveFileObject(v);
0446: directoryCache.put(prop, f);
0447: return f;
0448: }
0449: }
0450:
0451: public FileObject getSourceDirectory() {
0452: return getDir("src.dir"); // NOI18N
0453: }
0454:
0455: public FileObject getTestSourceDirectory() {
0456: return getDir("test.unit.src.dir"); // NOI18N
0457: }
0458:
0459: public FileObject getFunctionalTestSourceDirectory() {
0460: return getDir("test.qa-functional.src.dir"); // NOI18N
0461: }
0462:
0463: public FileObject getPerformanceTestSourceDirectory() {
0464: return getDir("test.qa-performance.src.dir"); // NOI18N
0465: }
0466:
0467: public File getClassesDirectory() {
0468: String classesDir = evaluator()
0469: .getProperty("build.classes.dir"); // NOI18N
0470: return helper.resolveFile(classesDir);
0471: }
0472:
0473: public File getTestClassesDirectory() {
0474: String testClassesDir = evaluator().getProperty(
0475: "build.test.unit.classes.dir"); // NOI18N
0476: return helper.resolveFile(testClassesDir);
0477: }
0478:
0479: public FileObject getJavaHelpDirectory() {
0480: if (helper.resolveFileObject("javahelp/manifest.mf") != null) { // NOI18N
0481: // Special hack for core.
0482: return null;
0483: }
0484: return helper.resolveFileObject("javahelp"); // NOI18N
0485: }
0486:
0487: public File getModuleJarLocation() {
0488: // XXX could use ModuleList here instead
0489: return helper.resolveFile(evaluator().evaluate(
0490: "${cluster}/${module.jar}")); // NOI18N
0491: }
0492:
0493: public String getCodeNameBase() {
0494: Element config = getPrimaryConfigurationData();
0495: Element cnb = Util.findElement(config, "code-name-base",
0496: NbModuleProjectType.NAMESPACE_SHARED); // NOI18N
0497: if (cnb != null) {
0498: return Util.findText(cnb);
0499: } else {
0500: return null;
0501: }
0502: }
0503:
0504: public String getSpecVersion() {
0505: //TODO shall we check for illegal cases like "none-defined" or "both-defined" here?
0506: Manifest m = getManifest();
0507: if (m != null) {
0508: String manVersion = m.getMainAttributes().getValue(
0509: "OpenIDE-Module-Specification-Version"); //NOI18N
0510: if (manVersion != null) {
0511: return stripExcessZeros(manVersion);
0512: }
0513: }
0514: return stripExcessZeros(evaluator().getProperty(
0515: SingleModuleProperties.SPEC_VERSION_BASE));
0516: }
0517:
0518: private static String stripExcessZeros(String spec) { // #72826
0519: return spec != null ? spec.replaceAll("(\\.[0-9]+)\\.0$", "$1")
0520: : null; // NOI18N
0521: }
0522:
0523: /**
0524: * Slash-separated path inside netbeans.org sources, or null for external modules.
0525: */
0526: public String getPathWithinNetBeansOrg() {
0527: FileObject nbroot = getNbrootFileObject(null);
0528: if (nbroot != null) {
0529: return FileUtil.getRelativePath(nbroot,
0530: getProjectDirectory());
0531: } else {
0532: return null;
0533: }
0534: }
0535:
0536: private File getNbroot() {
0537: return getNbroot(null);
0538: }
0539:
0540: private File getNbroot(PropertyEvaluator eval) {
0541: File dir = getProjectDirectoryFile();
0542: File nbroot = ModuleList.findNetBeansOrg(dir);
0543: if (nbroot != null) {
0544: return nbroot;
0545: } else {
0546: // OK, not it.
0547: NbPlatform platform = getPlatform(eval);
0548: if (platform != null) {
0549: URL[] roots = platform.getSourceRoots();
0550: for (int i = 0; i < roots.length; i++) {
0551: if (roots[i].getProtocol().equals("file")) { // NOI18N
0552: File f = new File(URI.create(roots[i]
0553: .toExternalForm()));
0554: if (ModuleList.isNetBeansOrg(f)) {
0555: return f;
0556: }
0557: }
0558: }
0559: }
0560: // Did not find it.
0561: return null;
0562: }
0563: }
0564:
0565: public File getNbrootFile(String path) {
0566: return getNbrootFile(path, null);
0567: }
0568:
0569: File getNbrootFile(String path, PropertyEvaluator eval) {
0570: File nbroot = getNbroot(eval);
0571: if (nbroot != null) {
0572: return new File(nbroot, path.replace('/',
0573: File.separatorChar));
0574: } else {
0575: return null;
0576: }
0577: }
0578:
0579: public FileObject getNbrootFileObject(String path) {
0580: File f = path != null ? getNbrootFile(path) : getNbroot();
0581: if (f != null) {
0582: return FileUtil.toFileObject(f);
0583: } else {
0584: return null;
0585: }
0586: }
0587:
0588: public ModuleList getModuleList() throws IOException {
0589: NbPlatform p = getPlatform(false);
0590: if (p == null) {
0591: // #67148: have to use something... (and getEntry(codeNameBase) will certainly fail!)
0592: NbPlatform p2 = NbPlatform.getDefaultPlatform();
0593: return ModuleList.getModuleList(getProjectDirectoryFile(),
0594: p2 != null ? p2.getDestDir() : null);
0595: }
0596: ModuleList ml;
0597: try {
0598: ml = ModuleList.getModuleList(getProjectDirectoryFile(), p
0599: .getDestDir());
0600: } catch (IOException x) {
0601: // #69029: maybe invalidated platform? Try the default platform instead.
0602: Logger.getLogger(NbModuleProject.class.getName()).log(
0603: Level.FINE, null, x);
0604: NbPlatform p2 = NbPlatform.getDefaultPlatform();
0605: return ModuleList.getModuleList(getProjectDirectoryFile(),
0606: p2 != null ? p2.getDestDir() : null);
0607: }
0608: if (ml.getEntry(getCodeNameBase()) == null) {
0609: ModuleList.refresh();
0610: ml = ModuleList.getModuleList(getProjectDirectoryFile());
0611: if (ml.getEntry(getCodeNameBase()) == null) {
0612: // XXX try to give better diagnostics - as examples are discovered
0613: Util.err
0614: .log(
0615: ErrorManager.WARNING,
0616: "Project in "
0617: + FileUtil
0618: .getFileDisplayName(getProjectDirectory())
0619: + " does not appear to be listed in its own module list; some sort of misconfiguration (e.g. not listed in its own suite)"); // NOI18N
0620: }
0621: }
0622: return ml;
0623: /*
0624: } catch (IOException e) {
0625: // #60094: see if we can fix it quietly by resetting platform to default.
0626: FileObject platformPropertiesFile = null;
0627: if (typeProvider.getModuleType() == NbModuleProvider.STANDALONE) {
0628: platformPropertiesFile = getProjectDirectory().getFileObject("nbproject/platform.properties"); // NOI18N
0629: } else if (typeProvider.getModuleType() == NbModuleProvider.SUITE_COMPONENT) {
0630: PropertyEvaluator baseEval = PropertyUtils.sequentialPropertyEvaluator(
0631: getHelper().getStockPropertyPreprovider(),
0632: new PropertyProvider[] {
0633: getHelper().getPropertyProvider("nbproject/private/suite-private.properties"), // NOI18N
0634: getHelper().getPropertyProvider("nbproject/suite.properties"), // NOI18N
0635: });
0636: String suiteDirS = baseEval.getProperty("suite.dir"); // NOI18N
0637: if (suiteDirS != null) {
0638: FileObject suiteDir = getHelper().resolveFileObject(suiteDirS);
0639: if (suiteDir != null) {
0640: platformPropertiesFile = suiteDir.getFileObject("nbproject/platform.properties"); // NOI18N
0641: }
0642: }
0643: }
0644: if (platformPropertiesFile != null) {
0645: try {
0646: EditableProperties ep = Util.loadProperties(platformPropertiesFile);
0647: if (!NbPlatform.PLATFORM_ID_DEFAULT.equals(ep.getProperty("nbplatform.active"))) { // NOI18N
0648: ep.setProperty("nbplatform.active", NbPlatform.PLATFORM_ID_DEFAULT); // NOI18N
0649: Util.storeProperties(platformPropertiesFile, ep);
0650: } else {
0651: // That wasn't it, never mind.
0652: throw e;
0653: }
0654: } catch (IOException e2) {
0655: Util.err.notify(ErrorManager.INFORMATIONAL, e2);
0656: // Well, throw original exception.
0657: throw e;
0658: }
0659: // Try again!
0660: return ModuleList.getModuleList(getProjectDirectoryFile());
0661: }
0662: throw e;
0663: }
0664: */
0665: }
0666:
0667: /**
0668: * Get the platform which this project is currently associated with.
0669: * @param fallback if true, fall back to the default platform if necessary
0670: * @return the current platform; or null if fallback is false and there is no
0671: * platform specified, or an invalid platform is specified, or even if
0672: * fallback is true but even the default platform is not available
0673: */
0674: public NbPlatform getPlatform(boolean fallback) {
0675: NbPlatform p = getPlatform(null);
0676: if (fallback && (p == null || !p.isValid())) {
0677: p = NbPlatform.getDefaultPlatform();
0678: }
0679: return p;
0680: }
0681:
0682: private NbPlatform getPlatform(PropertyEvaluator eval) {
0683: File file = getPlatformFile(eval);
0684: if (file == null) {
0685: return null;
0686: }
0687: return NbPlatform.getPlatformByDestDir(file);
0688: }
0689:
0690: private File getPlatformFile(PropertyEvaluator eval) {
0691: if (eval == null) {
0692: eval = evaluator();
0693: }
0694: String prop = eval.getProperty("netbeans.dest.dir"); // NOI18N
0695: if (prop == null) {
0696: return null;
0697: }
0698: return getHelper().resolveFile(prop);
0699: }
0700:
0701: /**
0702: * Check whether Javadoc generation is possible.
0703: */
0704: public boolean supportsJavadoc() {
0705: if (evaluator().getProperty("module.javadoc.packages") != null) {
0706: return true;
0707: }
0708: Element config = getPrimaryConfigurationData();
0709: Element pubPkgs = Util.findElement(config, "public-packages",
0710: NbModuleProjectType.NAMESPACE_SHARED); // NOI18N
0711: if (pubPkgs == null) {
0712: // Try <friend-packages> too.
0713: pubPkgs = Util.findElement(config, "friend-packages",
0714: NbModuleProjectType.NAMESPACE_SHARED); // NOI18N
0715: }
0716: return pubPkgs != null
0717: && !Util.findSubElements(pubPkgs).isEmpty();
0718: }
0719:
0720: public boolean supportsUnitTests() {
0721: return getTestSourceDirectory() != null;
0722: }
0723:
0724: /**
0725: * Find marked extra compilation units.
0726: * Gives a map from the package root to the defining XML element.
0727: */
0728: public Map<FileObject, Element> getExtraCompilationUnits() {
0729: if (extraCompilationUnits == null) {
0730: extraCompilationUnits = new HashMap<FileObject, Element>();
0731: for (Element ecu : Util
0732: .findSubElements(getPrimaryConfigurationData())) {
0733: if (ecu.getLocalName().equals("extra-compilation-unit")) { // NOI18N
0734: Element pkgrootEl = Util.findElement(ecu,
0735: "package-root",
0736: NbModuleProjectType.NAMESPACE_SHARED); // NOI18N
0737: String pkgrootS = Util.findText(pkgrootEl);
0738: String pkgrootEval = evaluator().evaluate(pkgrootS);
0739: FileObject pkgroot = getHelper().resolveFileObject(
0740: pkgrootEval);
0741: if (pkgroot == null) {
0742: Util.err.log(ErrorManager.WARNING,
0743: "Could not find package-root "
0744: + pkgrootEval + " for "
0745: + getCodeNameBase());
0746: continue;
0747: }
0748: extraCompilationUnits.put(pkgroot, ecu);
0749: }
0750: }
0751: }
0752: return extraCompilationUnits;
0753: }
0754:
0755: /** Get the Java source level used for this module. Default is 1.4. */
0756: public String getJavacSource() {
0757: String javacSource = evaluator().getProperty("javac.source");
0758: assert javacSource != null;
0759: return javacSource;
0760: }
0761:
0762: private ClassPath[] boot, source, compile;
0763:
0764: private final class OpenedHook extends ProjectOpenedHook {
0765: OpenedHook() {
0766: }
0767:
0768: protected void projectOpened() {
0769: open();
0770: }
0771:
0772: protected void projectClosed() {
0773: try {
0774: ProjectManager.getDefault().saveProject(
0775: NbModuleProject.this );
0776: } catch (IOException e) {
0777: Util.err.notify(e);
0778: }
0779: // XXX could discard caches, etc.
0780: // unregister project's classpaths to GlobalClassPathRegistry
0781: assert boot != null && source != null && compile != null : "#46802: project being closed which was never opened?? "
0782: + NbModuleProject.this ;
0783: GlobalPathRegistry.getDefault().unregister(ClassPath.BOOT,
0784: boot);
0785: GlobalPathRegistry.getDefault().unregister(
0786: ClassPath.SOURCE, source);
0787: GlobalPathRegistry.getDefault().unregister(
0788: ClassPath.COMPILE, compile);
0789: boot = null;
0790: source = null;
0791: compile = null;
0792: }
0793: }
0794:
0795: /**
0796: * Run the open hook.
0797: * For use from unit tests.
0798: */
0799: public void open() {
0800: // write user.properties.file=$userdir/build.properties to platform-private.properties
0801: if (getModuleType() == NbModuleProvider.STANDALONE) {
0802: // XXX skip this in case nbplatform.active is not defined
0803: ProjectManager.mutex().writeAccess(
0804: new Mutex.Action<Void>() {
0805: public Void run() {
0806: String path = "nbproject/private/platform-private.properties"; // NOI18N
0807: EditableProperties ep = getHelper()
0808: .getProperties(path);
0809: File buildProperties = new File(System
0810: .getProperty("netbeans.user"),
0811: "build.properties"); // NOI18N
0812: ep.setProperty("user.properties.file",
0813: buildProperties.getAbsolutePath()); //NOI18N
0814: getHelper().putProperties(path, ep);
0815: try {
0816: ProjectManager.getDefault()
0817: .saveProject(
0818: NbModuleProject.this );
0819: } catch (IOException e) {
0820: ErrorManager.getDefault().notify(e);
0821: }
0822: return null;
0823: }
0824: });
0825: }
0826: // register project's classpaths to GlobalClassPathRegistry
0827: ClassPathProviderImpl cpProvider = lookup
0828: .lookup(ClassPathProviderImpl.class);
0829: ClassPath[] _boot = cpProvider
0830: .getProjectClassPaths(ClassPath.BOOT);
0831: assert _boot != null : "No BOOT path";
0832: ClassPath[] _source = cpProvider
0833: .getProjectClassPaths(ClassPath.SOURCE);
0834: assert _source != null : "No SOURCE path";
0835: ClassPath[] _compile = cpProvider
0836: .getProjectClassPaths(ClassPath.COMPILE);
0837: assert _compile != null : "No COMPILE path";
0838: // Possible cause of #68414: do not change instance vars until after the dangerous stuff has been computed.
0839: GlobalPathRegistry.getDefault().register(ClassPath.BOOT, _boot);
0840: GlobalPathRegistry.getDefault().register(ClassPath.SOURCE,
0841: _source);
0842: GlobalPathRegistry.getDefault().register(ClassPath.COMPILE,
0843: _compile);
0844: boot = _boot;
0845: source = _source;
0846: compile = _compile;
0847: // refresh build.xml and build-impl.xml for external modules
0848: if (getModuleType() != NbModuleProvider.NETBEANS_ORG) {
0849: try {
0850: refreshBuildScripts(true);
0851: } catch (IOException e) {
0852: ErrorManager.getDefault().notify(
0853: ErrorManager.INFORMATIONAL, e);
0854: }
0855: }
0856: }
0857:
0858: /**
0859: * <strong>For use from unit tests only.</strong> Returns {@link
0860: * LocalizedBundleInfo} for this project.
0861: */
0862: public LocalizedBundleInfo getBundleInfo() {
0863: return getLookup().lookup(LocalizedBundleInfo.Provider.class)
0864: .getLocalizedBundleInfo();
0865: }
0866:
0867: /** See issue #69440 for more details. */
0868: public void setRunInAtomicAction(boolean runInAtomicAction) {
0869: eval.setRunInAtomicAction(runInAtomicAction);
0870: }
0871:
0872: private final class Info implements ProjectInformation,
0873: PropertyChangeListener {
0874:
0875: private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(
0876: this );
0877:
0878: private String displayName;
0879:
0880: Info() {
0881: }
0882:
0883: public String getName() {
0884: String cnb = getCodeNameBase();
0885: return cnb != null ? cnb
0886: : /* #70490 */getProjectDirectory().toString();
0887: }
0888:
0889: public String getDisplayName() {
0890: if (displayName == null) {
0891: LocalizedBundleInfo bundleInfo = getBundleInfo();
0892: if (bundleInfo != null) {
0893: displayName = bundleInfo.getDisplayName();
0894: }
0895: }
0896: if (/* #70490 */displayName == null) {
0897: displayName = getName();
0898: }
0899: assert displayName != null : NbModuleProject.this ;
0900: return displayName;
0901: }
0902:
0903: private void setDisplayName(String newDisplayName) {
0904: String oldDisplayName = getDisplayName();
0905: displayName = newDisplayName == null ? getName()
0906: : newDisplayName;
0907: firePropertyChange(ProjectInformation.PROP_DISPLAY_NAME,
0908: oldDisplayName, displayName);
0909: }
0910:
0911: public Icon getIcon() {
0912: return NB_PROJECT_ICON;
0913: }
0914:
0915: public Project getProject() {
0916: return NbModuleProject.this ;
0917: }
0918:
0919: public void addPropertyChangeListener(
0920: PropertyChangeListener pchl) {
0921: changeSupport.addPropertyChangeListener(pchl);
0922: }
0923:
0924: public void removePropertyChangeListener(
0925: PropertyChangeListener pchl) {
0926: changeSupport.removePropertyChangeListener(pchl);
0927: }
0928:
0929: private void firePropertyChange(String propName,
0930: Object oldValue, Object newValue) {
0931: changeSupport.firePropertyChange(propName, oldValue,
0932: newValue);
0933: }
0934:
0935: public void propertyChange(PropertyChangeEvent evt) {
0936: if (ProjectInformation.PROP_DISPLAY_NAME.equals(evt
0937: .getPropertyName())) {
0938: setDisplayName((String) evt.getNewValue());
0939: }
0940: }
0941:
0942: }
0943:
0944: public void notifyDeleting() {
0945: eval.removeListeners();
0946: }
0947:
0948: private final class SavedHook extends ProjectXmlSavedHook {
0949:
0950: SavedHook() {
0951: }
0952:
0953: protected void projectXmlSaved() throws IOException {
0954: // refresh build.xml and build-impl.xml for external modules
0955: if (getModuleType() != NbModuleProvider.NETBEANS_ORG) {
0956: refreshBuildScripts(false);
0957: }
0958: }
0959:
0960: }
0961:
0962: private void refreshBuildScripts(boolean checkForProjectXmlModified)
0963: throws IOException {
0964: genFilesHelper.refreshBuildScript(
0965: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
0966: NbModuleProject.class
0967: .getResource("resources/build-impl.xsl"), // NOI18N
0968: checkForProjectXmlModified);
0969: genFilesHelper.refreshBuildScript(
0970: GeneratedFilesHelper.BUILD_XML_PATH,
0971: NbModuleProject.class
0972: .getResource("resources/build.xsl"), // NOI18N
0973: checkForProjectXmlModified);
0974: }
0975:
0976: private final class SuiteProviderImpl implements SuiteProvider {
0977:
0978: public File getSuiteDirectory() {
0979: String suiteDir = evaluator().getProperty("suite.dir"); // NOI18N
0980: return suiteDir == null ? null : helper
0981: .resolveFile(suiteDir);
0982: }
0983:
0984: }
0985:
0986: private class NbModuleProviderImpl implements NbModuleProvider,
0987: AntProjectListener {
0988:
0989: private NbModuleType type;
0990:
0991: public NbModuleProviderImpl() {
0992: getHelper().addAntProjectListener(this );
0993: }
0994:
0995: public NbModuleType getModuleType() {
0996: if (type == null) {
0997: type = NbModuleProject.this .getModuleType();
0998: }
0999: return type;
1000: }
1001:
1002: public void configurationXmlChanged(AntProjectEvent ev) {
1003: if (ev.getPath().equals(AntProjectHelper.PROJECT_XML_PATH)) {
1004: type = null;
1005: }
1006: }
1007:
1008: public void propertiesChanged(AntProjectEvent ev) {
1009: // do not need to react here, type is encoded in project.xml
1010: }
1011:
1012: public String getSpecVersion() {
1013: return NbModuleProject.this .getSpecVersion();
1014: }
1015:
1016: public String getCodeNameBase() {
1017: return NbModuleProject.this .getCodeNameBase();
1018: }
1019:
1020: public String getSourceDirectoryPath() {
1021: return NbModuleProject.this .getSourceDirectoryPath();
1022: }
1023:
1024: public FileObject getSourceDirectory() {
1025: return NbModuleProject.this .getSourceDirectory();
1026: }
1027:
1028: public FileObject getManifestFile() {
1029: return NbModuleProject.this .getManifestFile();
1030: }
1031:
1032: public String getResourceDirectoryPath(boolean inTests) {
1033: return evaluator().getProperty(
1034: inTests ? "test.unit.src.dir" : "src.dir");
1035: }
1036:
1037: public boolean addDependency(String codeNameBase,
1038: String releaseVersion, SpecificationVersion version,
1039: boolean useInCompiler) throws IOException {
1040: return Util.addDependency(NbModuleProject.this ,
1041: codeNameBase, releaseVersion, version,
1042: useInCompiler);
1043: }
1044:
1045: public SpecificationVersion getDependencyVersion(
1046: String codenamebase) throws IOException {
1047: ModuleList moduleList = getModuleList();
1048: ModuleEntry entry = moduleList.getEntry(codenamebase); // NOI18N
1049: SpecificationVersion current = new SpecificationVersion(
1050: entry.getSpecificationVersion());
1051: return current;
1052:
1053: }
1054:
1055: public String getProjectFilePath() {
1056: return "nbproject/project.xml";
1057: }
1058:
1059: public File getActivePlatformLocation() {
1060: return NbModuleProject.this .getPlatformFile(null);
1061: }
1062:
1063: }
1064:
1065: private static final class PrivilegedTemplatesImpl implements
1066: PrivilegedTemplates, RecommendedTemplates {
1067:
1068: private static final String[] PRIVILEGED_NAMES = new String[] {
1069: "Templates/Classes/Class.java", // NOI18N
1070: "Templates/Classes/Package", // NOI18N
1071: "Templates/Classes/Interface.java", // NOI18N
1072: //"Templates/GUIForms/JPanel.java", // NOI18N
1073: "Templates/JUnit/SimpleJUnitTest.java", // NOI18N
1074: "Templates/NetBeansModuleDevelopment/newAction", // NOI18N
1075: "Templates/NetBeansModuleDevelopment/emptyLibraryDescriptor", // NOI18N
1076: "Templates/NetBeansModuleDevelopment/newLoader", // NOI18N
1077: "Templates/NetBeansModuleDevelopment/newProject", // NOI18N
1078: "Templates/NetBeansModuleDevelopment/newWindow", // NOI18N
1079: "Templates/NetBeansModuleDevelopment/newWizard", // NOI18N
1080: //"Templates/Other/properties.properties", // NOI18N
1081: };
1082: static {
1083: assert PRIVILEGED_NAMES.length <= 10 : "Too many privileged templates to fit! extras will be ignored: "
1084: + Arrays.asList(PRIVILEGED_NAMES).subList(10,
1085: PRIVILEGED_NAMES.length);
1086: }
1087:
1088: private static final String[] RECOMMENDED_TYPES = new String[] {
1089: "java-classes", // NOI18N
1090: "java-main-class", // NOI18N
1091: "java-forms", // NOI18N
1092: "java-beans", // NOI18N
1093: "oasis-XML-catalogs", // NOI18N
1094: "XML", // NOI18N
1095: "ant-script", // NOI18N
1096: "ant-task", // NOI18N
1097: "junit", // NOI18N
1098: "simple-files", // NOI18N
1099: "nbm-specific", // NOI18N
1100: "nbm-specific2", // NOI18N
1101: };
1102:
1103: public String[] getPrivilegedTemplates() {
1104: return PRIVILEGED_NAMES;
1105: }
1106:
1107: public String[] getRecommendedTypes() {
1108: return RECOMMENDED_TYPES;
1109: }
1110: }
1111:
1112: private final class LocalizedBundleInfoProvider implements
1113: LocalizedBundleInfo.Provider {
1114:
1115: private LocalizedBundleInfo bundleInfo;
1116:
1117: public LocalizedBundleInfo getLocalizedBundleInfo() {
1118: if (bundleInfo == null) {
1119: Manifest mf = getManifest();
1120: FileObject srcFO = getSourceDirectory();
1121: if (mf != null && srcFO != null) {
1122: bundleInfo = Util.findLocalizedBundleInfo(srcFO,
1123: getManifest());
1124: }
1125: if (bundleInfo != null) {
1126: bundleInfo.addPropertyChangeListener(getLookup()
1127: .lookup(Info.class));
1128: }
1129: if (mf != null) {
1130: getManifestFile().addFileChangeListener(
1131: new FileChangeAdapter() {
1132: public @Override
1133: void fileChanged(FileEvent fe) {
1134: // cannot reload manifest-dependent things immediately (see 67961 for more details)
1135: bundleInfo = null;
1136: }
1137: });
1138: }
1139: }
1140: return bundleInfo;
1141: }
1142: }
1143:
1144: }
|