# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: /Users/mkleint/src/core-main # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: maven/src/org/netbeans/modules/maven/M2AuxilaryConfigImpl.java --- maven/src/org/netbeans/modules/maven/M2AuxilaryConfigImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/M2AuxilaryConfigImpl.java Locally Modified (Based On LOCAL) @@ -47,6 +47,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.StringReader; +import java.lang.ref.WeakReference; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; @@ -94,11 +95,12 @@ private Document cachedDoc; private final Object configIOLock = new Object(); private final FileObject projectDirectory; - private final ProblemReporterImpl reporter; + private WeakReference reporter; - public M2AuxilaryConfigImpl(FileObject dir, ProblemReporterImpl problemReporter) { + /** intentionally left without reference to project instance */ + public M2AuxilaryConfigImpl(FileObject dir) { this.projectDirectory = dir; - this.reporter = problemReporter; + savingTask = RP.create(new Runnable() { public @Override void run() { try { @@ -136,6 +138,10 @@ }); } + public void setProblemReporter(ProblemReporterImpl problemReporter) { + this.reporter = new WeakReference(problemReporter); + } + private Document loadConfig(FileObject config) throws IOException, SAXException { synchronized (configIOLock) { //TODO shall be have some kind of caching here to prevent frequent IO? @@ -190,14 +196,17 @@ cachedDoc = doc; return XMLUtil.findElement(doc.getDocumentElement(), elementName, namespace); } catch (SAXException ex) { - if (!reporter.hasReportWithId(BROKEN_NBCONFIG)) { + ProblemReporterImpl pr = reporter != null ? reporter.get() : null; + if (pr != null) { + if (!pr.hasReportWithId(BROKEN_NBCONFIG)) { ProblemReport rep = new ProblemReport(ProblemReport.SEVERITY_MEDIUM, TXT_Problem_Broken_Config(), DESC_Problem_Broken_Config(ex.getMessage()), new OpenConfigAction(config)); rep.setId(BROKEN_NBCONFIG); - reporter.addReport(rep); + pr.addReport(rep); } + } LOG.log(Level.INFO, ex.getMessage(), ex); cachedDoc = null; } catch (IOException ex) { Index: maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java --- maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java Locally Modified (Based On LOCAL) @@ -83,10 +83,12 @@ import org.netbeans.modules.maven.api.execute.ActiveJ2SEPlatformProvider; import org.netbeans.modules.maven.api.problem.ProblemReport; import org.netbeans.modules.maven.configurations.M2ConfigProvider; +import org.netbeans.modules.maven.configurations.M2Configuration; import org.netbeans.modules.maven.configurations.ProjectProfileHandlerImpl; import org.netbeans.modules.maven.embedder.EmbedderFactory; import org.netbeans.modules.maven.embedder.MavenEmbedder; import org.netbeans.modules.maven.execute.AbstractMavenExecutor; +import org.netbeans.modules.maven.modelcache.MavenProjectCache; import org.netbeans.modules.maven.problems.ProblemReporterImpl; import org.netbeans.modules.maven.spi.queries.JavaLikeRootProvider; import org.netbeans.spi.java.project.support.LookupMergerSupport; @@ -179,7 +181,8 @@ projectFolderUpdater = new Updater("nb-configuration.xml", "pom.xml"); //NOI18N userFolderUpdater = new Updater("settings.xml");//NOI18N problemReporter = new ProblemReporterImpl(this); - M2AuxilaryConfigImpl auxiliary = new M2AuxilaryConfigImpl(folder, problemReporter); + M2AuxilaryConfigImpl auxiliary = new M2AuxilaryConfigImpl(folder); + auxiliary.setProblemReporter(problemReporter); auxprops = new MavenProjectPropsImpl(auxiliary, this); profileHandler = new ProjectProfileHandlerImpl(this, auxiliary); configProvider = new M2ConfigProvider(this, auxiliary, profileHandler); @@ -208,6 +211,7 @@ * @param properties * @return */ + //TODO revisit usage, eventually should be only reuse MavenProjectCache public @NonNull MavenProject loadMavenProject(MavenEmbedder embedder, List activeProfiles, Properties properties) { try { MavenExecutionRequest req = embedder.createMavenExecutionRequest(); @@ -215,7 +219,7 @@ req.setPom(projectFile); req.setNoSnapshotUpdates(true); req.setUpdateSnapshots(false); - Properties props = createSystemPropsForProjectLoading(); + Properties props = MavenProjectCache.createSystemPropsForProjectLoading(null); if (properties != null) { props.putAll(properties); } @@ -241,7 +245,7 @@ //#136184 NumberFormatException LOG.log(Level.INFO, "Runtime exception thrown while loading maven project at " + getProjectDirectory(), exc); //NOI18N } - return getFallbackProject(); + return MavenProjectCache.getFallbackProject(this.getPOMFile()); } public List getCurrentActiveProfiles() { @@ -249,35 +253,12 @@ toRet.addAll(configProvider.getActiveConfiguration().getActivatedProfiles()); return toRet; } - private static final Properties statics = new Properties(); - private static Properties cloneStaticProps() { - synchronized (statics) { - if (statics.isEmpty()) { // not yet initialized - // Now a misnomer, but available to activate profiles only during NB project parse: - statics.setProperty("netbeans.execution", "true"); // NOI18N - EmbedderFactory.fillEnvVars(statics); - statics.putAll(AbstractMavenExecutor.excludeNetBeansProperties(System.getProperties())); - } - Properties toRet = new Properties(); - toRet.putAll(statics); - return toRet; - } - } - //#158700 - private Properties createSystemPropsForProjectLoading() { - Properties props = cloneStaticProps(); - props.putAll(configProvider.getActiveConfiguration().getProperties()); - //TODO the properties for java.home and maybe others shall be relevant to the project setup not ide setup. - // we got a chicken-egg situation here, the jdk used in project can be defined in the pom.xml file. - return props; - } - //#172952 for property expression resolution we need this to include // the properties of the platform to properly resolve stuff like com.sun.boot.class.path public Map createSystemPropsForPropertyExpressions() { - Map props = NbCollections.checkedMapByCopy(cloneStaticProps(), String.class, String.class, true); + Map props = NbCollections.checkedMapByCopy(MavenProjectCache.cloneStaticProps(), String.class, String.class, true); ActiveJ2SEPlatformProvider platformProvider = getLookup().lookup(ActiveJ2SEPlatformProvider.class); if (platformProvider != null) { // may be null inside PackagingProvider props.putAll(platformProvider.getJavaPlatform().getSystemProperties()); @@ -293,7 +274,7 @@ public @NonNull synchronized MavenProject getOriginalMavenProject() { MavenProject mp = project == null ? null : project.get(); if (mp == null) { - mp = loadOriginalMavenProject(); + mp = loadOriginalMavenProject(false); } project = new SoftReference(mp); return mp; @@ -317,55 +298,31 @@ + "This is preventing the project model from loading properly. \n" + "Please file a bug report with details about your project and the IDE's log file.\n\n" }) - private @NonNull MavenProject loadOriginalMavenProject() { - long startLoading = System.currentTimeMillis(); - MavenProject newproject = null; + private @NonNull MavenProject loadOriginalMavenProject(boolean reload) { + MavenProject newproject; try { -// ProgressTransferListener.setAggregateHandle(hndl); -// hndl.start(); - final MavenExecutionRequest req = getEmbedder().createMavenExecutionRequest(); - - //#172526 have the modellineage cache reset at the same time the project cache resets - profileHandler.clearLineageCache(); - req.addActiveProfiles(getCurrentActiveProfiles()); - req.setPom(projectFile); - req.setNoSnapshotUpdates(true); - req.setUpdateSnapshots(false); - //MEVENIDE-634 i'm wondering if this fixes the issue - req.setInteractiveMode(false); - // recursive == false is important to avoid checking all submodules for extensions - // that will not be used in current pom anyway.. - // #135070 - req.setRecursive(false); - req.setOffline(true); - req.setUserProperties(createSystemPropsForProjectLoading()); - MavenExecutionResult res = getEmbedder().readProjectWithDependencies(req, true); - newproject = res.getProject(); + newproject = MavenProjectCache.getMavenProject(this.folderFileObject, reload); + MavenExecutionResult res = MavenProjectCache.getExecutionResult(newproject); if (res.hasExceptions()) { problemReporter.reportExceptions(res); } else { problemReporter.doArtifactChecks(newproject); } - } catch (RuntimeException exc) { - //guard against exceptions that are not processed by the embedder - //#136184 NumberFormatException - LOG.log(Level.INFO, "Runtime exception thrown while loading maven project at " + getProjectDirectory(), exc); //NOI18N - StringWriter wr = new StringWriter(); - PrintWriter pw = new PrintWriter(wr); - exc.printStackTrace(pw); - pw.flush(); +// } catch (RuntimeException exc) { +// //guard against exceptions that are not processed by the embedder +// //#136184 NumberFormatException +// LOG.log(Level.INFO, "Runtime exception thrown while loading maven project at " + getProjectDirectory(), exc); //NOI18N +// StringWriter wr = new StringWriter(); +// PrintWriter pw = new PrintWriter(wr); +// exc.printStackTrace(pw); +// pw.flush(); +// +// ProblemReport report = new ProblemReport(ProblemReport.SEVERITY_HIGH, +// TXT_RuntimeException(), +// TXT_RuntimeExceptionLong() + wr.toString(), null); +// problemReporter.addReport(report); - ProblemReport report = new ProblemReport(ProblemReport.SEVERITY_HIGH, - TXT_RuntimeException(), - TXT_RuntimeExceptionLong() + wr.toString(), null); - problemReporter.addReport(report); - } finally { - if (newproject == null) { - newproject = getFallbackProject(); - } - long endLoading = System.currentTimeMillis(); - LOG.log(Level.FINE, "Loaded project in {0} msec at {1}", new Object[] {endLoading - startLoading, getProjectDirectory().getPath()}); if (LOG.isLoggable(Level.FINE) && SwingUtilities.isEventDispatchThread()) { LOG.log(Level.FINE, "Project " + getProjectDirectory().getPath() + " loaded in AWT event dispatching thread!", new RuntimeException()); } @@ -374,22 +331,8 @@ return newproject; } - @Messages({ - "LBL_Incomplete_Project_Name=", - "LBL_Incomplete_Project_Desc=Partially loaded Maven project; try building it." - }) - private MavenProject getFallbackProject() throws AssertionError { - MavenProject newproject = new MavenProject(); - newproject.setGroupId("error"); - newproject.setArtifactId("error"); - newproject.setVersion("0"); - newproject.setPackaging("pom"); - newproject.setName(LBL_Incomplete_Project_Name()); - newproject.setDescription(LBL_Incomplete_Project_Desc()); - newproject.setFile(projectFile); - return newproject; - } + public void fireProjectReload() { //#149566 prevent project firing squads to execute under project mutex. if (ProjectManager.mutex().isReadAccess() @@ -405,7 +348,7 @@ return; } problemReporter.clearReports(); //#167741 -this will trigger node refresh? - MavenProject prj = loadOriginalMavenProject(); + MavenProject prj = loadOriginalMavenProject(true); synchronized (this) { project = new SoftReference(prj); } Index: maven/src/org/netbeans/modules/maven/configurations/ConfigurationPersistenceConstants.java --- maven/src/org/netbeans/modules/maven/configurations/ConfigurationPersistenceConstants.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/configurations/ConfigurationPersistenceConstants.java Locally New @@ -0,0 +1,59 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.maven.configurations; + +/** + * + * @author mkleint + */ +public interface ConfigurationPersistenceConstants { + String NAMESPACE = "http://www.netbeans.org/ns/maven-config-data/1"; + String ROOT = "config-data"; + String ENABLED = "enabled"; + String ACTIVATED = "activated"; + String CONFIGURATIONS = "configurations"; + String CONFIG = "configuration"; + String PROPERTY = "property"; + String PROPERTY_NAME_ATTR = "name"; + String CONFIG_PROFILES_ATTR = "profiles"; + String CONFIG_ID_ATTR = "id"; +} Index: maven/src/org/netbeans/modules/maven/configurations/M2ConfigProvider.java --- maven/src/org/netbeans/modules/maven/configurations/M2ConfigProvider.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/configurations/M2ConfigProvider.java Locally Modified (Based On LOCAL) @@ -63,6 +63,7 @@ import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.AuxiliaryConfiguration; import org.netbeans.spi.project.ProjectConfigurationProvider; +import org.openide.filesystems.FileObject; import org.openide.util.Exceptions; import org.openide.util.RequestProcessor; import org.openide.xml.XMLUtil; @@ -74,7 +75,7 @@ * in the critical loop (getOriginalMavenproject * @author mkleint */ -public class M2ConfigProvider implements ProjectConfigurationProvider { +public class M2ConfigProvider implements ProjectConfigurationProvider, ConfigurationPersistenceConstants { private PropertyChangeSupport support = new PropertyChangeSupport(this); private NbMavenProjectImpl project; @@ -89,16 +90,6 @@ private ProjectProfileHandler profileHandler; private PropertyChangeListener propertyChange; - static String NAMESPACE = "http://www.netbeans.org/ns/maven-config-data/1"; //NOI18N - static String ROOT = "config-data"; //NOI18N - static String ENABLED = "enabled"; //NOI18N - static String ACTIVATED = "activated"; //NOI18N - static String CONFIGURATIONS = "configurations"; //NOI18N - static String CONFIG = "configuration"; //NOI18N - static String PROPERTY = "property"; //NOI18N - static String PROPERTY_NAME_ATTR = "name"; //NOI18N - static String CONFIG_PROFILES_ATTR = "profiles"; //NOI18N - static String CONFIG_ID_ATTR = "id"; //NOI18N private static final RequestProcessor RP = new RequestProcessor(M2ConfigProvider.class.getName(),10); @@ -153,7 +144,7 @@ Runnable dothis = new Runnable() { public @Override void run() { M2Configuration _active; - synchronized (this) { + synchronized (M2ConfigProvider.this) { _active = active; } try { @@ -177,11 +168,11 @@ } if (shared == null) { //read from auxconf - shared = readConfiguration(true); + shared = readConfiguration(aux, project.getProjectDirectory(), true); } if (nonshared == null) { //read from auxconf - nonshared = readConfiguration(false); + nonshared = readConfiguration(aux, project.getProjectDirectory(), false); } Collection toRet = new TreeSet(); toRet.add(DEFAULT); @@ -356,7 +347,7 @@ support.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null); } - private SortedSet readConfiguration(boolean shared) { + public static SortedSet readConfiguration(AuxiliaryConfiguration aux, FileObject projectDirectory, boolean shared) { Element el = aux.getConfigurationFragment(ROOT, NAMESPACE, shared); if (el != null) { NodeList list = el.getElementsByTagNameNS(NAMESPACE, CONFIG); @@ -366,7 +357,7 @@ for (int i = 0; i < len; i++) { Element enEl = (Element)list.item(i); - M2Configuration c = new M2Configuration(enEl.getAttribute(CONFIG_ID_ATTR), project.getProjectDirectory()); + M2Configuration c = new M2Configuration(enEl.getAttribute(CONFIG_ID_ATTR), projectDirectory); String profs = enEl.getAttribute(CONFIG_PROFILES_ATTR); if (profs != null) { String[] s = profs.split(" "); Index: maven/src/org/netbeans/modules/maven/configurations/M2Configuration.java --- maven/src/org/netbeans/modules/maven/configurations/M2Configuration.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/configurations/M2Configuration.java Locally Modified (Based On LOCAL) @@ -70,7 +70,7 @@ public static final String DEFAULT = "%%DEFAULT%%"; //NOI18N - static M2Configuration createDefault(FileObject projectDirectory) { + public static M2Configuration createDefault(FileObject projectDirectory) { return new M2Configuration(DEFAULT, projectDirectory); } Index: maven/src/org/netbeans/modules/maven/configurations/ProjectProfileHandlerImpl.java --- maven/src/org/netbeans/modules/maven/configurations/ProjectProfileHandlerImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/configurations/ProjectProfileHandlerImpl.java Locally Modified (Based On LOCAL) @@ -77,7 +77,6 @@ private final List sharedProfiles = new ArrayList(); private final AuxiliaryConfiguration ac; private final NbMavenProjectImpl nmp; - private List lineage; public ProjectProfileHandlerImpl(NbMavenProjectImpl nmp, AuxiliaryConfiguration ac) { this.nmp = nmp; @@ -86,28 +85,6 @@ sharedProfiles.addAll(retrieveActiveProfiles(ac, true)); } - /** - * reset caching of the lineage, invoked from MavenProject reloads - */ - public synchronized void clearLineageCache() { - lineage = null; - } - - /** - * cache the lineage for repeated use - */ - private synchronized List getLineage() { - if (lineage == null) { - try { - lineage = nmp.getEmbedder().createModelLineage(nmp.getPOMFile()); - } catch (ModelBuildingException ex) { - Logger.getLogger(ProjectProfileHandlerImpl.class.getName()).log(Level.FINE, "Error reading model lineage", ex);//NOI18N - lineage = Collections.emptyList(); - } - } - return lineage; - } - public @Override List getAllProfiles() { Set profileIds = new HashSet(); //pom profiles come first @@ -197,17 +174,10 @@ } private void extractProfiles(Set profileIds) { - /* Cannot use this as it would trigger a stack overflow when loading the project: for (Profile profile : nmp.getOriginalMavenProject().getModel().getProfiles()) { profileIds.add(profile.getId()); } - */ - for (Model model : getLineage()) { - for (Profile profile : model.getProfiles()) { - profileIds.add(profile.getId()); } - } - } private List retrieveActiveProfiles(AuxiliaryConfiguration ac, boolean shared) { Index: maven/src/org/netbeans/modules/maven/modelcache/ActiveConfigurationProvider.java --- maven/src/org/netbeans/modules/maven/modelcache/ActiveConfigurationProvider.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/modelcache/ActiveConfigurationProvider.java Locally New @@ -0,0 +1,98 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.maven.modelcache; + +import java.util.Collections; +import java.util.SortedSet; +import org.netbeans.modules.maven.configurations.ConfigurationPersistenceConstants; +import org.netbeans.modules.maven.configurations.M2ConfigProvider; +import org.netbeans.modules.maven.configurations.M2Configuration; +import org.netbeans.spi.project.AuxiliaryConfiguration; +import org.openide.filesystems.FileObject; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * + * @author mkleint + */ +public class ActiveConfigurationProvider implements ConfigurationPersistenceConstants { + private final AuxiliaryConfiguration aux; + private final FileObject projectDirectory; + + public ActiveConfigurationProvider(FileObject projectDirectory, AuxiliaryConfiguration aux) { + this.aux = aux; + this.projectDirectory = projectDirectory; + } + + public M2Configuration getActiveConfiguration() { + String active = null; + Element el = aux.getConfigurationFragment(ROOT, NAMESPACE, false); + if (el != null) { + NodeList list = el.getElementsByTagNameNS(NAMESPACE, ACTIVATED); + if (list.getLength() > 0) { + Element enEl = (Element)list.item(0); + active = enEl.getTextContent(); + } + } + if (active == null) { + return M2Configuration.createDefault(projectDirectory); + } else { + SortedSet configs = M2ConfigProvider.readConfiguration(aux, projectDirectory, true); + for (M2Configuration c : configs) { + if (c.getId().equals(active)) { + return c; + } + } + configs = M2ConfigProvider.readConfiguration(aux, projectDirectory, false); + for (M2Configuration c : configs) { + if (c.getId().equals(active)) { + return c; + } + } + // attempt to find the stored configuration, if not found it's a profile + M2Configuration toRet = new M2Configuration(active, projectDirectory); + toRet.setActivatedProfiles(Collections.singletonList(active)); + return toRet; + } + } +} Index: maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java --- maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java Locally New @@ -0,0 +1,222 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.modules.maven.modelcache; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.SwingUtilities; +import org.apache.maven.execution.DefaultMavenExecutionResult; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionResult; +import org.apache.maven.project.MavenProject; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.modules.maven.M2AuxilaryConfigImpl; +import org.netbeans.modules.maven.configurations.M2Configuration; +import org.netbeans.modules.maven.embedder.EmbedderFactory; +import org.netbeans.modules.maven.embedder.MavenEmbedder; +import org.netbeans.modules.maven.execute.AbstractMavenExecutor; +import org.netbeans.spi.project.AuxiliaryConfiguration; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.Mutex; +import org.openide.util.Mutex.Action; +import org.openide.util.NbBundle; + +/** + * externalize the creation of MavenProject instances outside of NbMavenProjectImpl + * and be able to access it without a project at hand + * @author mkleint + */ +public final class MavenProjectCache { + + private static final Logger LOG = Logger.getLogger(MavenProjectCache.class.getName()); + private static final String CONTEXT_EXECUTION_RESULT = "NB_Execution_Result"; + + //FileObject is referenced during lifetime of the Project. + //TODO should these maps be weak and free values when FileObject is GCed? + private static final Map> file2Project = new HashMap>(); + private static final Map file2Mutex = new HashMap(); + + public static MavenProject getMavenProject(final FileObject projectDirectory, final boolean reload) { + Mutex mutex = getMutex(projectDirectory); + MavenProject mp = mutex.writeAccess(new Action() { + @Override + public MavenProject run() { + if (!reload) { + WeakReference ref = file2Project.get(projectDirectory); + if (ref != null) { + MavenProject mp = ref.get(); + if (mp != null) { + return mp; + } + } + } + MavenProject mp = loadOriginalMavenProject(projectDirectory); + file2Project.put(projectDirectory, new WeakReference(mp)); //TODO our own referenceQueue to clean up the maps? + return mp; + } + }); + + return mp; + } + + public static MavenExecutionResult getExecutionResult(MavenProject project) { + return (MavenExecutionResult) project.getContextValue(CONTEXT_EXECUTION_RESULT); + } + + + + + @NbBundle.Messages({ + "TXT_RuntimeException=RuntimeException occurred in Apache Maven embedder while loading", + "TXT_RuntimeExceptionLong=RuntimeException occurred in Apache Maven embedder while loading the project. \n" + + "This is preventing the project model from loading properly. \n" + + "Please file a bug report with details about your project and the IDE's log file.\n\n" + }) + private static @NonNull MavenProject loadOriginalMavenProject(FileObject projectDirectory) { + long startLoading = System.currentTimeMillis(); + MavenEmbedder projectEmbedder = EmbedderFactory.getProjectEmbedder(); + MavenProject newproject = null; + //TODO have independent from M2AuxiliaryConfigImpl + AuxiliaryConfiguration aux = new M2AuxilaryConfigImpl(projectDirectory); + ActiveConfigurationProvider config = new ActiveConfigurationProvider(projectDirectory, aux); + M2Configuration active = config.getActiveConfiguration(); + final File pomFile = new File(FileUtil.toFile(projectDirectory), "pom.xml"); + MavenExecutionResult res = null; + try { + final MavenExecutionRequest req = projectEmbedder.createMavenExecutionRequest(); + req.addActiveProfiles(active.getActivatedProfiles()); + + req.setPom(pomFile); + req.setNoSnapshotUpdates(true); + req.setUpdateSnapshots(false); + //MEVENIDE-634 i'm wondering if this fixes the issue + req.setInteractiveMode(false); + // recursive == false is important to avoid checking all submodules for extensions + // that will not be used in current pom anyway.. + // #135070 + req.setRecursive(false); + req.setOffline(true); + req.setUserProperties(createSystemPropsForProjectLoading(active.getProperties())); + res = projectEmbedder.readProjectWithDependencies(req, true); + newproject = res.getProject(); + } catch (RuntimeException exc) { + //guard against exceptions that are not processed by the embedder + //#136184 NumberFormatException + LOG.log(Level.INFO, "Runtime exception thrown while loading maven project at " + projectDirectory, exc); //NOI18N + res = new DefaultMavenExecutionResult(); + res.addException(exc); + } finally { + if (newproject == null) { + newproject = getFallbackProject(pomFile); + } + newproject.setContextValue(CONTEXT_EXECUTION_RESULT, res); + long endLoading = System.currentTimeMillis(); + LOG.log(Level.FINE, "Loaded project in {0} msec at {1}", new Object[] {endLoading - startLoading, projectDirectory.getPath()}); + if (LOG.isLoggable(Level.FINE) && SwingUtilities.isEventDispatchThread()) { + LOG.log(Level.FINE, "Project " + projectDirectory.getPath() + " loaded in AWT event dispatching thread!", new RuntimeException()); + } + } + assert newproject != null; + return newproject; + } + @NbBundle.Messages({ + "LBL_Incomplete_Project_Name=", + "LBL_Incomplete_Project_Desc=Partially loaded Maven project; try building it." + }) + public static MavenProject getFallbackProject(File projectFile) throws AssertionError { + MavenProject newproject = new MavenProject(); + newproject.setGroupId("error"); + newproject.setArtifactId("error"); + newproject.setVersion("0"); + newproject.setPackaging("pom"); + newproject.setName(Bundle.LBL_Incomplete_Project_Name()); + newproject.setDescription(Bundle.LBL_Incomplete_Project_Desc()); + newproject.setFile(projectFile); + return newproject; + } + + private static final Properties statics = new Properties(); + + public static Properties cloneStaticProps() { + synchronized (statics) { + if (statics.isEmpty()) { // not yet initialized + // Now a misnomer, but available to activate profiles only during NB project parse: + statics.setProperty("netbeans.execution", "true"); // NOI18N + EmbedderFactory.fillEnvVars(statics); + statics.putAll(AbstractMavenExecutor.excludeNetBeansProperties(System.getProperties())); + } + Properties toRet = new Properties(); + toRet.putAll(statics); + return toRet; + } + } + + //#158700 + public static Properties createSystemPropsForProjectLoading(Map activeConfiguration) { + Properties props = cloneStaticProps(); + if (activeConfiguration != null) { + props.putAll(activeConfiguration); + } + //TODO the properties for java.home and maybe others shall be relevant to the project setup not ide setup. + // we got a chicken-egg situation here, the jdk used in project can be defined in the pom.xml file. + return props; + } + + private static Mutex getMutex(FileObject projectDirectory) { + synchronized (file2Mutex) { + Mutex mutex = file2Mutex.get(projectDirectory); + if (mutex != null) { + return mutex; + } + mutex = new Mutex(); + file2Mutex.put(projectDirectory, mutex); + return mutex; + } + } + +} Index: maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java --- maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java Base (BASE) +++ maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java Locally Modified (Based On LOCAL) @@ -64,6 +64,7 @@ import org.netbeans.modules.maven.NbMavenProjectImpl; import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.modules.maven.embedder.EmbedderFactory; +import org.netbeans.modules.maven.modelcache.MavenProjectCache; import org.netbeans.spi.project.FileOwnerQueryImplementation; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -290,6 +291,8 @@ return null; } + + //NOTE: called from NBArtifactFixer, cannot contain references to ProjectManager public File getOwnerPOM(String groupId, String artifactId, String version) { LOG.log(Level.FINER, "Checking {0} / {1} / {2} (POM only)", new Object[] {groupId, artifactId, version}); String oldKey = groupId + ":" + artifactId; @@ -324,10 +327,12 @@ LOG.log(Level.FINE, "mismatch on groupId in {0}", pom); } // Might actually be a match due to use of e.g. string interpolation, so double-check with live project. - Project p = getOwner(groupId, artifactId, version); - if (p != null) { - LOG.log(Level.FINE, "live project match for {0}", pom); - return p.getLookup().lookup(NbMavenProjectImpl.class).getPOMFile(); + FileObject projectDir = URLMapper.findFileObject(new URI(ownerURI).toURL()); + if (projectDir != null && projectDir.isFolder()) { + MavenProject prj = MavenProjectCache.getMavenProject(projectDir, false); + if (prj.getGroupId().equals(groupId) && prj.getArtifactId().equals(artifactId) && prj.getVersion().equals(version)) { + return pom; + } } else { LOG.log(Level.FINE, "no live project match for {0}", pom); }