# HG changeset patch # Parent 506c7aefea4086a9edd4f3a056f30b1947972184 #186024: rewrite how the association between artifacts in the local repo and source projects is tracked. diff --git a/maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java b/maven/src/org/netbeans/modules/maven/MavenFileOwner.java rename from maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java rename to maven/src/org/netbeans/modules/maven/MavenFileOwner.java --- a/maven/src/org/netbeans/modules/maven/queries/MavenFileOwnerQueryImpl.java +++ b/maven/src/org/netbeans/modules/maven/MavenFileOwner.java @@ -40,124 +40,63 @@ * Portions Copyrighted 2008 Sun Microsystems, Inc. */ -package org.netbeans.modules.maven.queries; +package org.netbeans.modules.maven; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.event.ChangeListener; -import org.netbeans.modules.maven.NbMavenProjectImpl; -import org.netbeans.modules.maven.api.NbMavenProject; -import org.netbeans.api.project.Project; -import org.netbeans.api.project.ProjectManager; -import org.netbeans.spi.project.FileOwnerQueryImplementation; -import org.netbeans.spi.project.SubprojectProvider; -import org.openide.filesystems.FileObject; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.netbeans.api.project.FileOwnerQuery; import org.openide.filesystems.FileUtil; import org.openide.util.ChangeSupport; -import org.openide.util.Lookup; -import org.openide.util.Mutex.Action; -import org.openide.util.lookup.ServiceProvider; - /** - * A global implementation of FileOwnerQueryImplementation, is required to link together the maven project - * and it's artifact in the maven repository. any other files shall be handled by the - * default netbeans implementation. - * - * @author Milos Kleint + * Links the Maven project with its artifact in the local repository. */ -@ServiceProvider(service=FileOwnerQueryImplementation.class, position=97) -public class MavenFileOwnerQueryImpl implements FileOwnerQueryImplementation { +public class MavenFileOwner { - private Set set; - private final Object setLock = new Object(); - - private Set cachedProjects; - private Set projectsToAddToCache; - private final Object cacheLock = new Object(); - - private PropertyChangeListener projectListener; + private final PropertyChangeListener projectListener; private final ChangeSupport cs = new ChangeSupport(this); - private static final Logger LOG = Logger.getLogger(MavenFileOwnerQueryImpl.class.getName()); + private static final Logger LOG = Logger.getLogger(MavenFileOwner.class.getName()); - public MavenFileOwnerQueryImpl() { - set = new HashSet(); - cachedProjects = null; - projectsToAddToCache = null; + private MavenFileOwner() { projectListener = new PropertyChangeListener() { public @Override void propertyChange(PropertyChangeEvent evt) { if (NbMavenProjectImpl.PROP_PROJECT.equals(evt.getPropertyName())) { - Object evtSource = evt.getSource(); - if (evtSource instanceof NbMavenProjectImpl) { - // try adding the changed project and its subprojects again to cache - // new subprojects might have been added/activated for the changed project - synchronized (cacheLock) { - if (null == projectsToAddToCache) { - projectsToAddToCache = new HashSet(1); - } - projectsToAddToCache.add((NbMavenProjectImpl) evtSource); - } - } + fireChange(); } } }; } - - public static MavenFileOwnerQueryImpl getInstance() { - Lookup.Result implementations = - Lookup.getDefault().lookup(new Lookup.Template(FileOwnerQueryImplementation.class)); - Iterator it = implementations.allInstances().iterator(); - while (it.hasNext()) { - FileOwnerQueryImplementation obj = it.next(); - if (obj instanceof MavenFileOwnerQueryImpl) { - return (MavenFileOwnerQueryImpl)obj; - } - } - return null; + + private static final MavenFileOwner IMPL = new MavenFileOwner(); + public static MavenFileOwner getInstance() { + return IMPL; } public void addMavenProject(NbMavenProjectImpl project) { - synchronized (setLock) { - if (!set.contains(project)) { - LOG.log(Level.FINE, "Adding Maven project:{0}", project.getArtifactRelativeRepositoryPath()); - set.add(project); - NbMavenProject.addPropertyChangeListener(project, projectListener); + Artifact art = project.getOriginalMavenProject().getArtifact(); + if (art != null) { + File f = art.getFile(); + if (f == null) { // XXX seems to be the normal case - why? + ArtifactRepository repo = project.getEmbedder().getLocalRepository(); + f = new File(repo.getBasedir(), repo.pathOf(art)); } + File allArtifacts = FileUtil.normalizeFile(f.getParentFile()); + LOG.log(Level.FINE, "registering {0} for {1}", new Object[] {allArtifacts, art}); + FileOwnerQuery.markExternalOwner(allArtifacts.toURI(), project, FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); + // Also claim other versions, though another project with that exact version might override you: + FileOwnerQuery.markExternalOwner(allArtifacts.getParentFile().toURI(), project, FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); + } else { + LOG.log(Level.WARNING, "no artifact for {0}", project); } - synchronized (cacheLock) { - // add the new project to cache incrementally if it has not been - // added to cache already from "set" where we added it just above - if (null != cachedProjects && !cachedProjects.contains(project)) { - if (null == projectsToAddToCache) { - projectsToAddToCache = new HashSet(1); - } - projectsToAddToCache.add(project); - } - } - - fireChange(); - } - public void removeMavenProject(NbMavenProjectImpl project) { - synchronized (setLock) { - if (set.contains(project)) { - LOG.log(Level.FINE, "Removing Maven project:{0}", project.getArtifactRelativeRepositoryPath()); - set.remove(project); - NbMavenProject.removePropertyChangeListener(project, projectListener); - } - } - synchronized (cacheLock) { - cachedProjects = null; - } + project.getProjectWatcher().removePropertyChangeListener(projectListener); + project.getProjectWatcher().addPropertyChangeListener(projectListener); fireChange(); } @@ -173,140 +112,4 @@ cs.fireChange(); } - /** - * get the list of currently opened maven projects.. kind of hack, but well.. - */ - public Set getOpenedProjects() { - synchronized (setLock) { - return new HashSet(set); - } - } - - public @Override Project getOwner(URI uri) { - LOG.log(Level.FINEST, "getOwner of uri={0}", uri); - if (uri.getScheme() != null && "file".equals(uri.getScheme())) { //NOI18N - File file = new File(uri); - return getOwner(file); - } - return null; - } - - public @Override Project getOwner(FileObject fileObject) { - LOG.log(Level.FINEST, "getOwner of fileobject={0}", fileObject); - File file = FileUtil.toFile(fileObject); - if (file != null) { - //logger.fatal("getOwner of fileobject=" + fileObject.getNameExt()); - return getOwner(file); - } - return null; - } - - private Project getOwner(File file) { - //TODO check if the file is from local repo ?? - LOG.log(Level.FINE, "Looking for owner of {0}", file); - boolean passBasicCheck = false; - String nm = file.getName(); - File parentVer = file.getParentFile(); - if (parentVer != null) { - File parentArt = parentVer.getParentFile(); - if (parentArt != null) { - if (nm.startsWith(parentArt.getName() + "-" + parentVer.getName())) { - passBasicCheck = true; - } - } - } - if (!passBasicCheck) { - LOG.fine(" exiting early, not from local repository."); - return null; - } - Set currentProjects = getAllKnownProjects(); - - Iterator it = currentProjects.iterator(); - String filepath = file.getAbsolutePath().replace('\\', '/'); - while (it.hasNext()) { - NbMavenProjectImpl project = it.next(); - String path = project.getArtifactRelativeRepositoryPath(); - LOG.log(Level.FINEST, "matching againts known project {0}", path); - if (filepath.endsWith(path)) { - return project; - } - path = project.getTestArtifactRelativeRepositoryPath(); - LOG.log(Level.FINEST, "matching againts known project''s test {0}", path); - if (filepath.endsWith(path)) { - return project; - } - } - return null; - - } - - - private Set getAllKnownProjects() { - return ProjectManager.mutex().readAccess(new Action>() { - public @Override Set run() { - synchronized (cacheLock) { - // is cachedProjects up-to-date? - if (cachedProjects != null && null == projectsToAddToCache) { - return new HashSet(cachedProjects); - } - // cachedProjects empty? - if (null == cachedProjects) { - // full build of the cache - Set currentProjects; - List iterating; - synchronized (setLock) { - currentProjects = new HashSet(set); - iterating = new ArrayList(set); - } - int index = 0; - // iterate all opened projects and figure their subprojects.. - // consider these as well. do so recursively. - while (index < iterating.size()) { - NbMavenProjectImpl prj = iterating.get(index); - addSubProjects(currentProjects, iterating, prj); - index = index + 1; - } - cachedProjects = currentProjects; - projectsToAddToCache = null; - } - // non-empty projectsToAddToCache? - if (null != projectsToAddToCache) { - // incrementally adding to the cache - Set currentProjects; - List iterating; - currentProjects = new HashSet(cachedProjects); - currentProjects.addAll(projectsToAddToCache); - iterating = new ArrayList(projectsToAddToCache); - int index = 0; - // iterate all new or changed (after propChange) projects - // and figure their subprojects.. - // consider these as well. do so recursively. - while (index < iterating.size()) { - NbMavenProjectImpl prj = iterating.get(index); - addSubProjects(currentProjects, iterating, prj); - index = index + 1; - } - cachedProjects = currentProjects; - projectsToAddToCache = null; - } - return new HashSet(cachedProjects); - } - } - }); - } - - private void addSubProjects(Set finalset, List iteratinglist, NbMavenProjectImpl prj) { - SubprojectProvider sub = prj.getLookup().lookup(SubprojectProvider.class); - if (sub != null) { - Set subs = sub.getSubprojects(); - for (Project p : subs) { - if (p instanceof NbMavenProjectImpl) { - finalset.add((NbMavenProjectImpl) p); - if (!iteratinglist.contains((NbMavenProjectImpl)p)) { - iteratinglist.add((NbMavenProjectImpl) p); - } - } - } - } - } } diff --git a/maven/src/org/netbeans/modules/maven/ProjectOpenedHookImpl.java b/maven/src/org/netbeans/modules/maven/ProjectOpenedHookImpl.java --- a/maven/src/org/netbeans/modules/maven/ProjectOpenedHookImpl.java +++ b/maven/src/org/netbeans/modules/maven/ProjectOpenedHookImpl.java @@ -55,7 +55,6 @@ import java.util.logging.Logger; import java.util.prefs.Preferences; import org.netbeans.modules.maven.classpath.ClassPathProviderImpl; -import org.netbeans.modules.maven.queries.MavenFileOwnerQueryImpl; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.classpath.GlobalPathRegistry; import org.netbeans.api.project.FileOwnerQuery; @@ -63,7 +62,6 @@ import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.modules.maven.options.MavenSettings; import org.netbeans.spi.project.ui.ProjectOpenedHook; -import org.openide.ErrorManager; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; @@ -101,12 +99,7 @@ checkSourceDownloads(); checkJavadocDownloads(); attachUpdater(); - MavenFileOwnerQueryImpl q = MavenFileOwnerQueryImpl.getInstance(); - if (q != null) { - q.addMavenProject(project); - } else { - ErrorManager.getDefault().log("MavenFileOwnerQueryImpl not found.."); //NOI18N - } + MavenFileOwner.getInstance().addMavenProject(project); Set uris = new HashSet(); uris.addAll(Arrays.asList(project.getSourceRoots(false))); uris.addAll(Arrays.asList(project.getSourceRoots(true))); @@ -149,12 +142,6 @@ protected void projectClosed() { uriReferences.clear(); - MavenFileOwnerQueryImpl q = MavenFileOwnerQueryImpl.getInstance(); - if (q != null) { - q.removeMavenProject(project); - } else { - ErrorManager.getDefault().log("MavenFileOwnerQueryImpl not found.."); //NOI18N - } detachUpdater(); // unregister project's classpaths to GlobalPathRegistry ClassPathProviderImpl cpProvider = project.getLookup().lookup(org.netbeans.modules.maven.classpath.ClassPathProviderImpl.class); diff --git a/maven/src/org/netbeans/modules/maven/SubprojectProviderImpl.java b/maven/src/org/netbeans/modules/maven/SubprojectProviderImpl.java --- a/maven/src/org/netbeans/modules/maven/SubprojectProviderImpl.java +++ b/maven/src/org/netbeans/modules/maven/SubprojectProviderImpl.java @@ -54,8 +54,8 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.apache.maven.artifact.Artifact; +import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.modules.maven.api.NbMavenProject; -import org.netbeans.modules.maven.queries.MavenFileOwnerQueryImpl; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectManager; import org.netbeans.spi.project.SubprojectProvider; @@ -94,9 +94,7 @@ fireChange(); } }; - MavenFileOwnerQueryImpl.getInstance().addChangeListener( - WeakListeners.change(listener2, - MavenFileOwnerQueryImpl.getInstance())); + MavenFileOwner.getInstance().addChangeListener(WeakListeners.change(listener2, MavenFileOwner.getInstance())); } @@ -109,23 +107,21 @@ // can be interrupted in the open project dialog.. return Collections.emptySet(); } - addOpenedCandidates(projects); + addKnownOwners(projects); projects.remove(project); return projects; } - private void addOpenedCandidates(Set resultset) { - Set opened = MavenFileOwnerQueryImpl.getInstance().getOpenedProjects(); + private void addKnownOwners(Set resultset) { @SuppressWarnings("unchecked") List compileArtifacts = project.getOriginalMavenProject().getCompileArtifacts(); - List artPaths = new ArrayList(); for (Artifact ar : compileArtifacts) { - artPaths.add(project.getArtifactRelativeRepositoryPath(ar)); - } - for (Project prj : opened) { - String prjpath = ((NbMavenProjectImpl)prj).getArtifactRelativeRepositoryPath(); - if (artPaths.contains(prjpath)) { - resultset.add(prj); + File f = ar.getFile(); + if (f != null) { + Project p = FileOwnerQuery.getOwner(f.toURI()); + if (p != null) { + resultset.add(p); + } } } } diff --git a/maven/src/org/netbeans/modules/maven/nodes/DependencyNode.java b/maven/src/org/netbeans/modules/maven/nodes/DependencyNode.java --- a/maven/src/org/netbeans/modules/maven/nodes/DependencyNode.java +++ b/maven/src/org/netbeans/modules/maven/nodes/DependencyNode.java @@ -59,8 +59,6 @@ import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Icon; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; @@ -71,18 +69,22 @@ import org.netbeans.modules.maven.api.CommonArtifactActions; import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.modules.maven.embedder.NbArtifact; -import org.netbeans.modules.maven.queries.MavenFileOwnerQueryImpl; import hidden.org.codehaus.plexus.util.FileUtils; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; import org.netbeans.api.java.queries.JavadocForBinaryQuery; import org.netbeans.api.java.queries.SourceForBinaryQuery; import org.netbeans.api.progress.aggregate.ProgressContributor; +import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.ui.OpenProjects; +import org.netbeans.modules.maven.MavenFileOwner; import org.netbeans.modules.maven.dependencies.DependencyExcludeNodeVisitor; import org.netbeans.modules.maven.embedder.DependencyTreeFactory; import org.netbeans.modules.maven.dependencies.ExcludeDependencyPanel; @@ -191,9 +193,7 @@ } }; //TODO check if this one is a performance bottleneck. - MavenFileOwnerQueryImpl.getInstance().addChangeListener( - WeakListeners.change(listener2, - MavenFileOwnerQueryImpl.getInstance())); + MavenFileOwner.getInstance().addChangeListener(WeakListeners.change(listener2, MavenFileOwner.getInstance())); } setDisplayName(createName()); setIconBase(false); @@ -230,7 +230,7 @@ } private void setIconBase(boolean longLiving) { - if (longLiving && isDependencyProjectOpen()) { + if (longLiving && isDependencyProjectAvailable()) { if (isTransitive()) { setIconBaseWithExtension("org/netbeans/modules/maven/TransitiveMaven2Icon.gif"); //NOI18N } else { @@ -272,14 +272,12 @@ * this call is slow * @return */ - boolean isDependencyProjectOpen() { + private boolean isDependencyProjectAvailable() { if ( Artifact.SCOPE_SYSTEM.equals(art.getScope())) { return false; } URI uri = art.getFile().toURI(); -// URI rootUri = project.getRepositoryRoot().getURL().toURI(); -// URI uri = rootUri.create(rootUri.toString() + "/" + project.getArtifactRelativeRepositoryPath(art)); - Project depPrj = MavenFileOwnerQueryImpl.getInstance().getOwner(uri); + Project depPrj = FileOwnerQuery.getOwner(uri); return depPrj != null; } @@ -329,6 +327,9 @@ @SuppressWarnings("unchecked") public Action[] getActions(boolean context) { Collection acts = new ArrayList(); + if (longLiving && isDependencyProjectAvailable()) { + acts.add(OpenProjectAction.SINGLETON); + } if (isAddedToCP()) { InstallLocalArtifactAction act = new InstallLocalArtifactAction(); acts.add(act); @@ -1101,4 +1102,29 @@ } } } + + private static class OpenProjectAction extends AbstractAction implements ContextAwareAction { + + static final OpenProjectAction SINGLETON = new OpenProjectAction(); + + private OpenProjectAction() {} + + public @Override void actionPerformed(ActionEvent e) { + assert false; + } + + public @Override Action createContextAwareInstance(final Lookup context) { + return new AbstractAction(NbBundle.getMessage(ModulesNode.class, "BTN_Open_Project")) { + public @Override void actionPerformed(ActionEvent e) { + Set projects = new HashSet(); + for (Artifact art : context.lookupAll(Artifact.class)) { + projects.add(FileOwnerQuery.getOwner(art.getFile().toURI())); + } + projects.remove(null); + OpenProjects.getDefault().open(projects.toArray(new NbMavenProjectImpl[projects.size()]), false, true); + } + }; + } + } + }