/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ package org.netbeans.modules.scala.project; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.Icon; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.classpath.GlobalPathRegistry; import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.project.*; import org.netbeans.api.project.ant.AntArtifact; import org.netbeans.api.project.ant.AntBuildExtender; import org.netbeans.modules.java.api.common.SourceRoots; import org.netbeans.modules.java.api.common.ant.UpdateHelper; import org.netbeans.modules.java.api.common.ant.UpdateImplementation; import org.netbeans.modules.java.api.common.classpath.ClassPathModifier; import org.netbeans.modules.java.api.common.project.ProjectProperties; import org.netbeans.modules.java.api.common.queries.QuerySupport; import org.netbeans.modules.scala.project.api.J2SEPropertyEvaluator; import org.netbeans.modules.scala.project.classpath.ClassPathProviderImpl; import org.netbeans.modules.scala.project.queries.BinaryForSourceQueryImpl; import org.netbeans.modules.scala.project.ui.J2SELogicalViewProvider; import org.netbeans.modules.scala.project.ui.customizer.CustomizerProviderImpl; import org.netbeans.modules.scala.project.ui.customizer.J2SEProjectProperties; import org.netbeans.spi.java.project.support.ExtraSourceJavadocSupport; import org.netbeans.spi.java.project.support.LookupMergerSupport; import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.AuxiliaryConfiguration; import org.netbeans.spi.project.SubprojectProvider; import org.netbeans.spi.project.ant.AntArtifactProvider; import org.netbeans.spi.project.ant.AntBuildExtenderFactory; import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; import org.netbeans.spi.project.support.LookupProviderSupport; import org.netbeans.spi.project.support.ant.AntProjectHelper; import org.netbeans.spi.project.support.ant.EditableProperties; import org.netbeans.spi.project.support.ant.FilterPropertyProvider; import org.netbeans.spi.project.support.ant.GeneratedFilesHelper; import org.netbeans.spi.project.support.ant.ProjectXmlSavedHook; import org.netbeans.spi.project.support.ant.PropertyEvaluator; import org.netbeans.spi.project.support.ant.PropertyProvider; import org.netbeans.spi.project.support.ant.PropertyUtils; import org.netbeans.spi.project.support.ant.ReferenceHelper; import org.netbeans.spi.project.ui.PrivilegedTemplates; import org.netbeans.spi.project.ui.ProjectOpenedHook; import org.netbeans.spi.project.ui.RecommendedTemplates; import org.netbeans.spi.project.ui.support.UILookupMergerSupport; import org.netbeans.spi.queries.FileEncodingQueryImplementation; import org.openide.DialogDisplayer; import org.openide.ErrorManager; import org.openide.NotifyDescriptor; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; import org.openide.modules.InstalledFileLocator; import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; import org.openide.util.Lookup; import org.openide.util.Mutex; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Represents one plain J2SE project. * @author Jesse Glick, et al. */ public final class J2SEProject implements Project { private static final Icon J2SE_PROJECT_ICON = ImageUtilities.loadImageIcon("org/netbeans/modules/scala/project/ui/resources/scalaProject.png", true); // NOI18N private static final Logger LOG = Logger.getLogger(J2SEProject.class.getName()); private final AuxiliaryConfiguration aux; private final AntProjectHelper helper; private final PropertyEvaluator eval; private final ReferenceHelper refHelper; private final GeneratedFilesHelper genFilesHelper; private final Lookup lookup; private final UpdateHelper updateHelper; private MainClassUpdater mainClassUpdater; private SourceRoots sourceRoots; private SourceRoots testRoots; private final ClassPathProviderImpl cpProvider; private final ClassPathModifier cpMod; private AntBuildExtender buildExtender; J2SEProject(AntProjectHelper helper) throws IOException { this.helper = helper; eval = createEvaluator(); aux = helper.createAuxiliaryConfiguration(); for (int v = 4; v < 10; v++) { if (aux.getConfigurationFragment("data", "http://www.netbeans.org/ns/scala-project/" + v, true) != null) { // NOI18N throw Exceptions.attachLocalizedMessage(new IOException("too new"), // NOI18N NbBundle.getMessage(J2SEProject.class, "ScalaProject.too_new", FileUtil.getFileDisplayName(helper.getProjectDirectory()))); } } refHelper = new ReferenceHelper(helper, aux, eval); buildExtender = AntBuildExtenderFactory.createAntExtender(new J2SEExtenderImplementation(), refHelper); /// TODO replace this GeneratedFilesHelper with the default one when fixing #101710 genFilesHelper = new GeneratedFilesHelper(helper, buildExtender); UpdateImplementation updateProject = new UpdateProjectImpl(this, helper, aux); this.updateHelper = new UpdateHelper(updateProject, helper); this.cpProvider = new ClassPathProviderImpl(this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()); //Does not use APH to get/put properties/cfgdata this.cpMod = new ClassPathModifier(this, this.updateHelper, eval, refHelper, null, createClassPathModifierCallback(), null); final J2SEActionProvider actionProvider = new J2SEActionProvider(this, this.updateHelper); lookup = createLookup(aux, actionProvider); actionProvider.startFSListener(); } private ClassPathModifier.Callback createClassPathModifierCallback() { return new ClassPathModifier.Callback() { @Override public String getClassPathProperty(SourceGroup sg, String type) { assert sg != null : "SourceGroup cannot be null"; //NOI18N assert type != null : "Type cannot be null"; //NOI18N final String[] classPathProperty = getClassPathProvider().getPropertyName (sg, type); if (classPathProperty == null || classPathProperty.length == 0) { throw new UnsupportedOperationException ("Modification of [" + sg.getRootFolder().getPath() +", " + type + "] is not supported"); //NOI18N } return classPathProperty[0]; } @Override public String getElementName(String classpathProperty) { return null; } }; } /** * Returns the project directory * @return the directory the project is located in */ @Override public FileObject getProjectDirectory() { return helper.getProjectDirectory(); } @Override public String toString() { return "ScalaProject[" + FileUtil.getFileDisplayName(getProjectDirectory()) + "]"; // NOI18N } private PropertyEvaluator createEvaluator() { // It is currently safe to not use the UpdateHelper for PropertyEvaluator; UH.getProperties() delegates to APH // Adapted from APH.getStandardPropertyEvaluator (delegates to ProjectProperties): PropertyEvaluator baseEval1 = PropertyUtils.sequentialPropertyEvaluator( helper.getStockPropertyPreprovider(), helper.getPropertyProvider(J2SEConfigurationProvider.CONFIG_PROPS_PATH)); PropertyEvaluator baseEval2 = PropertyUtils.sequentialPropertyEvaluator( helper.getStockPropertyPreprovider(), helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH)); ConfigPropertyProvider configPropertyProvider1 = new ConfigPropertyProvider(baseEval1, "nbproject/private/configs", helper); // NOI18N baseEval1.addPropertyChangeListener(configPropertyProvider1); ConfigPropertyProvider configPropertyProvider2 = new ConfigPropertyProvider(baseEval1, "nbproject/configs", helper); // NOI18N baseEval1.addPropertyChangeListener(configPropertyProvider2); return PropertyUtils.sequentialPropertyEvaluator( helper.getStockPropertyPreprovider(), helper.getPropertyProvider(J2SEConfigurationProvider.CONFIG_PROPS_PATH), configPropertyProvider1, helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH), helper.getProjectLibrariesPropertyProvider(), PropertyUtils.userPropertiesProvider(baseEval2, "user.properties.file", FileUtil.toFile(getProjectDirectory())), // NOI18N configPropertyProvider2, helper.getPropertyProvider(AntProjectHelper.PROJECT_PROPERTIES_PATH)); } private static final class ConfigPropertyProvider extends FilterPropertyProvider implements PropertyChangeListener { private final PropertyEvaluator baseEval; private final String prefix; private final AntProjectHelper helper; public ConfigPropertyProvider(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) { super(computeDelegate(baseEval, prefix, helper)); this.baseEval = baseEval; this.prefix = prefix; this.helper = helper; } @Override public void propertyChange(PropertyChangeEvent ev) { if (J2SEConfigurationProvider.PROP_CONFIG.equals(ev.getPropertyName())) { setDelegate(computeDelegate(baseEval, prefix, helper)); } } private static PropertyProvider computeDelegate(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) { String config = baseEval.getProperty(J2SEConfigurationProvider.PROP_CONFIG); if (config != null) { return helper.getPropertyProvider(prefix + "/" + config + ".properties"); // NOI18N } else { return PropertyUtils.fixedPropertyProvider(Collections.<String, String>emptyMap()); } } } public PropertyEvaluator evaluator() { return eval; } public ReferenceHelper getReferenceHelper() { return this.refHelper; } public UpdateHelper getUpdateHelper() { return this.updateHelper; } @Override public Lookup getLookup() { return lookup; } public AntProjectHelper getAntProjectHelper() { return helper; } private Lookup createLookup(final AuxiliaryConfiguration aux, final ActionProvider actionProvider) { final SubprojectProvider spp = refHelper.createSubprojectProvider(); FileEncodingQueryImplementation encodingQuery = QuerySupport.createFileEncodingQuery(evaluator(), J2SEProjectProperties.SOURCE_ENCODING); @SuppressWarnings("deprecation") Object cpe = new org.netbeans.modules.java.api.common.classpath.ClassPathExtender( cpMod, ProjectProperties.JAVAC_CLASSPATH, null); final Lookup base = Lookups.fixed(new Object[]{ J2SEProject.this, QuerySupport.createProjectInformation(updateHelper, this, J2SE_PROJECT_ICON), aux, helper.createAuxiliaryProperties(), helper.createCacheDirectoryProvider(), spp, actionProvider, new J2SELogicalViewProvider(this, this.updateHelper, evaluator(), spp, refHelper), // new J2SECustomizerProvider(this, this.updateHelper, evaluator(), refHelper), new CustomizerProviderImpl(this, this.updateHelper, evaluator(), refHelper, this.genFilesHelper), LookupMergerSupport.createClassPathProviderMerger(cpProvider), QuerySupport.createCompiledSourceForBinaryQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), QuerySupport.createJavadocForBinaryQuery(helper, evaluator()), new AntArtifactProviderImpl(), new ProjectXmlSavedHookImpl(), UILookupMergerSupport.createProjectOpenHookMerger(new ProjectOpenedHookImpl()), QuerySupport.createUnitTestForSourceQuery(getSourceRoots(), getTestSourceRoots()), QuerySupport.createSourceLevelQuery(evaluator()), new J2SESources(this, helper, evaluator(), getSourceRoots(), getTestSourceRoots()), QuerySupport.createSharabilityQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), QuerySupport.createFileBuiltQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), new RecommendedTemplatesImpl(this.updateHelper), cpe, buildExtender, cpMod, this, // never cast an externally obtained Project to J2SEProject - use lookup instead new J2SEProjectOperations(this), new J2SEConfigurationProvider(this), //new J2SEPersistenceProvider(this, cpProvider), UILookupMergerSupport.createPrivilegedTemplatesMerger(), UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), encodingQuery, new J2SEPropertyEvaluatorImpl(evaluator()), new J2SETemplateAttributesProvider(this.helper), ExtraSourceJavadocSupport.createExtraSourceQueryImplementation(this, helper, eval), LookupMergerSupport.createSFBLookupMerger(), ExtraSourceJavadocSupport.createExtraJavadocQueryImplementation(this, helper, eval), LookupMergerSupport.createJFBLookupMerger(), new BinaryForSourceQueryImpl(this.sourceRoots, this.testRoots, this.helper, this.eval) //Does not use APH to get/put properties/cfgdata }); return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-scala-project/Lookup"); //NOI18N } public ClassPathProviderImpl getClassPathProvider() { return this.cpProvider; } public ClassPathModifier getProjectClassPathModifier() { return this.cpMod; } // Package private methods ------------------------------------------------- /** * Returns the source roots of this project * @return project's source roots */ public synchronized SourceRoots getSourceRoots() { if (this.sourceRoots == null) { //Local caching, no project metadata access this.sourceRoots = SourceRoots.create(updateHelper, evaluator(), getReferenceHelper(), J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, "source-roots", false, "src.{0}{1}.dir"); //NOI18N } return this.sourceRoots; } public synchronized SourceRoots getTestSourceRoots() { if (this.testRoots == null) { //Local caching, no project metadata access this.testRoots = SourceRoots.create(updateHelper, evaluator(), getReferenceHelper(), J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, "test-roots", true, "test.{0}{1}.dir"); //NOI18N } return this.testRoots; } File getTestClassesDirectory() { String testClassesDir = evaluator().getProperty(ProjectProperties.BUILD_TEST_CLASSES_DIR); if (testClassesDir == null) { return null; } return helper.resolveFile(testClassesDir); } // Currently unused (but see #47230): /** Store configured project name. */ public void setName(final String name) { ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() { @Override public Void run() { Element data = helper.getPrimaryConfigurationData(true); // XXX replace by XMLUtil when that has findElement, findText, etc. NodeList nl = data.getElementsByTagNameNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name"); Element nameEl; if (nl.getLength() == 1) { nameEl = (Element) nl.item(0); NodeList deadKids = nameEl.getChildNodes(); while (deadKids.getLength() > 0) { nameEl.removeChild(deadKids.item(0)); } } else { nameEl = data.getOwnerDocument().createElementNS(J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name"); data.insertBefore(nameEl, /* OK if null */ data.getChildNodes().item(0)); } nameEl.appendChild(data.getOwnerDocument().createTextNode(name)); helper.putPrimaryConfigurationData(data, true); return null; } }); } private final class ProjectXmlSavedHookImpl extends ProjectXmlSavedHook { ProjectXmlSavedHookImpl() { } @Override protected void projectXmlSaved() throws IOException { //May be called by {@link AuxiliaryConfiguration#putConfigurationFragment} //which didn't affect the j2seproject if (updateHelper.isCurrent()) { //Refresh build-impl.xml only for j2seproject/2 genFilesHelper.refreshBuildScript( GeneratedFilesHelper.BUILD_IMPL_XML_PATH, J2SEProject.class.getResource("resources/build-impl.xsl"), false); genFilesHelper.refreshBuildScript( GeneratedFilesHelper.BUILD_XML_PATH, J2SEProject.class.getResource("resources/build.xsl"), false); } } } private final class ProjectOpenedHookImpl extends ProjectOpenedHook { ProjectOpenedHookImpl() { } private static final String JAX_RPC_NAMESPACE = "http://www.netbeans.org/ns/j2se-project/jax-rpc"; //NOI18N private static final String JAX_RPC_CLIENTS = "web-service-clients"; //NOI18N private static final String JAX_RPC_CLIENT = "web-service-client"; //NOI18N private ClassPath coreLibsCp; @Override protected void projectOpened() { // Check up on build scripts. try { if (updateHelper.isCurrent()) { //Refresh build-impl.xml only for j2seproject/2 genFilesHelper.refreshBuildScript( GeneratedFilesHelper.BUILD_IMPL_XML_PATH, J2SEProject.class.getResource("resources/build-impl.xsl"), true); genFilesHelper.refreshBuildScript( GeneratedFilesHelper.BUILD_XML_PATH, J2SEProject.class.getResource("resources/build.xsl"), true); } } catch (IOException e) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); } // register project's classpaths to GlobalPathRegistry /** register java classpaths, so the java's query will update it */ GlobalPathRegistry.getDefault().register( ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT)); GlobalPathRegistry.getDefault().register( ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE)); GlobalPathRegistry.getDefault().register( ClassPath.COMPILE, cpProvider.getProjectClassPaths(ClassPath.COMPILE)); /** * @Note: * Register classpaths to GlobalPathRegistry will cause GSF indexer to monitor and indexing them. * * Per org.netbeans.modules.gsfret.source.GlobalSourcePath#createResources(Request), * Tor' midifications: Treat bootCps as a source path, not a binary - I want to scan directories. * * We should here register boot source's classpath instead of binary boot classpath. * * GlobalPathRegistry.getDefault().register(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT)); */ // FileObject scalaStubsFo = ScalaLanguage.getScalaStubFo(); // if (scalaStubsFo != null) { // coreLibsCp = ClassPathSupport.createClassPath(new FileObject[]{scalaStubsFo}); // GlobalPathRegistry.getDefault().register(ClassPath.BOOT, new ClassPath[]{coreLibsCp}); // } // // GlobalPathRegistry.getDefault().register(ClassPath.BOOT, cpProvider.getProjectSourcesClassPaths(ClassPath.BOOT)); // GlobalPathRegistry.getDefault().register(ClassPath.COMPILE, cpProvider.getProjectSourcesClassPaths(ClassPath.COMPILE)); // GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, cpProvider.getProjectSourcesClassPaths(ClassPath.SOURCE)); //register updater of main.class //the updater is active only on the opened projects mainClassUpdater = new MainClassUpdater(J2SEProject.this, eval, updateHelper, cpProvider.getProjectClassPaths(ClassPath.SOURCE)[0], J2SEProjectProperties.MAIN_CLASS); mainClassUpdater.start(); // Make it easier to run headless builds on the same machine at least. try { getProjectDirectory().getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { @Override public void run() throws IOException { ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() { @Override public Void run() { EditableProperties ep = updateHelper.getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH); File buildProperties = new File(System.getProperty("netbeans.user"), "build.properties"); // NOI18N ep.setProperty("user.properties.file", buildProperties.getAbsolutePath()); //NOI18N // set jaxws.endorsed.dir property (for endorsed mechanism to be used with wsimport, wsgen) setJaxWsEndorsedDirProperty(ep); // move web-service-clients one level up from in project.xml // WS should be part of auxiliary configuration Element data = helper.getPrimaryConfigurationData(true); NodeList nodes = data.getElementsByTagName(JAX_RPC_CLIENTS); if (nodes.getLength() > 0) { Element oldJaxRpcClients = (Element) nodes.item(0); Document doc = createNewDocument(); Element newJaxRpcClients = doc.createElementNS(JAX_RPC_NAMESPACE, JAX_RPC_CLIENTS); NodeList childNodes = oldJaxRpcClients.getElementsByTagName(JAX_RPC_CLIENT); for (int i = 0; i < childNodes.getLength(); i++) { Element oldJaxRpcClient = (Element) childNodes.item(i); Element newJaxRpcClient = doc.createElementNS(JAX_RPC_NAMESPACE, JAX_RPC_CLIENT); NodeList nodeProps = oldJaxRpcClient.getChildNodes(); for (int j = 0; j < nodeProps.getLength(); j++) { Node n = nodeProps.item(j); if (n instanceof Element) { Element oldProp = (Element) n; Element newProp = doc.createElementNS(JAX_RPC_NAMESPACE, oldProp.getLocalName()); String text = oldProp.getTextContent(); newProp.setTextContent(text); newJaxRpcClient.appendChild(newProp); } } newJaxRpcClients.appendChild(newJaxRpcClient); } aux.putConfigurationFragment(newJaxRpcClients, true); data.removeChild(oldJaxRpcClients); helper.putPrimaryConfigurationData(data, true); } updateHelper.putProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH, ep); ep = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); if (!ep.containsKey(ProjectProperties.INCLUDES)) { ep.setProperty(ProjectProperties.INCLUDES, "**"); // NOI18N } if (!ep.containsKey(ProjectProperties.EXCLUDES)) { ep.setProperty(ProjectProperties.EXCLUDES, ""); // NOI18N } helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, ep); try { ProjectManager.getDefault().saveProject(J2SEProject.this); } catch (IOException e) { //#91398 provide a better error message in case of read-only location of project. if (!J2SEProject.this.getProjectDirectory().canWrite()) { NotifyDescriptor nd = new NotifyDescriptor.Message(NbBundle.getMessage(J2SEProject.class, "ERR_ProjectReadOnly", J2SEProject.this.getProjectDirectory().getName())); DialogDisplayer.getDefault().notify(nd); } else { ErrorManager.getDefault().notify(e); } } return null; } }); } }); } catch (IOException e) { Exceptions.printStackTrace(e); } J2SELogicalViewProvider physicalViewProvider = getLookup().lookup(J2SELogicalViewProvider.class); if (physicalViewProvider != null && physicalViewProvider.hasBrokenLinks()) { BrokenReferencesSupport.showAlert(); } String prop = eval.getProperty(J2SEProjectProperties.SOURCE_ENCODING); if (prop != null) { try { Charset c = Charset.forName(prop); } catch (IllegalCharsetNameException e) { //Broken property, log & ignore LOG.log(Level.WARNING, "Illegal charset: {0} in project: {1}", new Object[]{prop, FileUtil.getFileDisplayName(getProjectDirectory())}); //NOI18N } catch (UnsupportedCharsetException e) { //todo: Needs UI notification like broken references. LOG.log(Level.WARNING, "Unsupported charset: {0} in project: {1}", new Object[]{prop, FileUtil.getFileDisplayName(getProjectDirectory())}); //NOI18N } } } @Override protected void projectClosed() { // just do if the whole project was not deleted... if (getProjectDirectory().isValid()) { // Probably unnecessary, but just in case: try { ProjectManager.getDefault().saveProject(J2SEProject.this); } catch (IOException e) { if (!J2SEProject.this.getProjectDirectory().canWrite()) { // #91398 - ignore, we already reported on project open. // not counting with someone setting the ro flag while the project is opened. } else { ErrorManager.getDefault().notify(e); } } } // --- unregister project's classpaths to GlobalPathRegistry /** unregister java classpaths */ GlobalPathRegistry.getDefault().unregister( ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT)); GlobalPathRegistry.getDefault().unregister( ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE)); GlobalPathRegistry.getDefault().unregister( ClassPath.COMPILE, cpProvider.getProjectClassPaths(ClassPath.COMPILE)); if (coreLibsCp != null) { // Do we need unregister coreLibsCp? //GlobalPathRegistry.getDefault().unregister(ClassPath.BOOT, new ClassPath[]{coreLibsCp}); } /** * Why unreister COMPILE/BOOT classpath will cause: * java.lang.IllegalArgumentException: Attempt to remove nonexistent path ClassPath[Entry[file:/Users/dcaoyuan/my-project/nbsrc/main/nbbuild/netbeans/extra/scala/scala-2.7.1.final/src/META-INF/], Entry[file:/Users/dcaoyuan/my-project/nbsrc/main/nbbuild/netbeans/extra/scala/scala-2.7.1.final/src/sbaz/], Entry[file:/Users/dcaoyuan/my-project/nbsrc/main/nbbuild/netbeans/extra/scala/scala-2.7.1.final/src/scala/], Entry[file:/Users/dcaoyuan/my-project/nbsrc/main/nbbuild/netbeans/extra/scalastubs/]] * This never happen on Java classpath * Anyway, we can keep COMPILE/BOOT classpath there, since they are shared by all scala projects. */ //GlobalPathRegistry.getDefault().unregister(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT)); //GlobalPathRegistry.getDefault().unregister(ClassPath.COMPILE, cpProvider.getProjectClassPaths(ClassPath.COMPILE)); //GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE)); if (mainClassUpdater != null) { mainClassUpdater.stop(); mainClassUpdater = null; } } } /** * Exports the main JAR as an official build product for use from other scripts. * The type of the artifact will be {@link AntArtifact#TYPE_JAR}. */ private final class AntArtifactProviderImpl implements AntArtifactProvider { @Override public AntArtifact[] getBuildArtifacts() { return new AntArtifact[]{ helper.createSimpleAntArtifact(JavaProjectConstants.ARTIFACT_TYPE_JAR, "dist.jar", evaluator(), "jar", "clean"), // NOI18N }; } } private static final class RecommendedTemplatesImpl implements RecommendedTemplates, PrivilegedTemplates { RecommendedTemplatesImpl(UpdateHelper helper) { this.helper = helper; } private UpdateHelper helper; // List of primarily supported templates private static final String[] APPLICATION_TYPES = new String[]{ "java-classes", // NOI18N "java-main-class", // NOI18N "java-forms", // NOI18N "gui-java-application", // NOI18N "java-beans", // NOI18N "persistence", // NOI18N "oasis-XML-catalogs", // NOI18N "XML", // NOI18N "ant-script", // NOI18N "ant-task", // NOI18N "web-service-clients", // NOI18N "wsdl", // NOI18N // "servlet-types", // NOI18N // "web-types", // NOI18N "junit", // NOI18N // "MIDP", // NOI18N "simple-files" // NOI18N }; private static final String[] LIBRARY_TYPES = new String[]{ "java-classes", // NOI18N "java-main-class", // NOI18N "java-forms", // NOI18N //"gui-java-application", // NOI18N "java-beans", // NOI18N "persistence", // NOI18N "oasis-XML-catalogs", // NOI18N "XML", // NOI18N "ant-script", // NOI18N "ant-task", // NOI18N "servlet-types", // NOI18N "web-service-clients", // NOI18N "wsdl", // NOI18N // "web-types", // NOI18N "junit", // NOI18N // "MIDP", // NOI18N "simple-files" // NOI18N }; private static final String[] PRIVILEGED_NAMES = new String[]{ "Templates/Classes/Class.java", // NOI18N "Templates/Classes/Package", // NOI18N "Templates/Classes/Interface.java", // NOI18N "Templates/GUIForms/JPanel.java", // NOI18N "Templates/GUIForms/JFrame.java", // NOI18N "Templates/Persistence/Entity.java", // NOI18N "Templates/Persistence/RelatedCMP", // NOI18N "Templates/WebServices/WebServiceClient" // NOI18N }; @Override public String[] getRecommendedTypes() { EditableProperties ep = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); // if the project has no main class, it's not really an application boolean isLibrary = ep.getProperty(J2SEProjectProperties.MAIN_CLASS) == null || "".equals(ep.getProperty(J2SEProjectProperties.MAIN_CLASS)); // NOI18N return isLibrary ? LIBRARY_TYPES : APPLICATION_TYPES; } @Override public String[] getPrivilegedTemplates() { return PRIVILEGED_NAMES; } } private static final class J2SEPropertyEvaluatorImpl implements J2SEPropertyEvaluator { private PropertyEvaluator evaluator; public J2SEPropertyEvaluatorImpl(PropertyEvaluator eval) { evaluator = eval; } @Override public PropertyEvaluator evaluator() { return evaluator; } } private class J2SEExtenderImplementation implements AntBuildExtenderImplementation { //add targets here as required by the external plugins.. @Override public List<String> getExtensibleTargets() { String[] targets = new String[]{ "-do-init", "-init-check", "-post-clean", "jar", "-pre-pre-compile", "-do-compile", "-do-compile-single" //NOI18N }; return Arrays.asList(targets); } @Override public Project getOwningProject() { return J2SEProject.this; } } private static final String ENDORSED_DIR_PROPERTY = "jaxws.endorsed.dir"; //NOI18N /** Set jaxws.endorsed.dir property for wsimport, wsgen tasks * to specify jvmarg value : -Djava.endorsed.dirs=${jaxws.endorsed.dir}" */ public static void setJaxWsEndorsedDirProperty(EditableProperties ep) { String oldJaxWsEndorsedDirs = ep.getProperty(ENDORSED_DIR_PROPERTY); String javaVersion = System.getProperty("java.specification.version"); //NOI18N if ("1.6".equals(javaVersion)) { //NOI18N String jaxWsEndorsedDirs = getJaxWsApiDir(); if (jaxWsEndorsedDirs != null && !jaxWsEndorsedDirs.equals(oldJaxWsEndorsedDirs)) { ep.setProperty(ENDORSED_DIR_PROPERTY, jaxWsEndorsedDirs); } } else { if (oldJaxWsEndorsedDirs != null) { ep.remove(ENDORSED_DIR_PROPERTY); } } } private static String getJaxWsApiDir() { File file = InstalledFileLocator.getDefault().locate("modules/ext/jaxws21/api/jaxws-api.jar", null, false); // NOI18N if (file != null) { return file.getParent(); } return null; } private static final DocumentBuilder db; static { try { db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new AssertionError(e); } } private static Document createNewDocument() { // #50198: for thread safety, use a separate document. // Using XMLUtil.createDocument is much too slow. synchronized (db) { return db.newDocument(); } } }