/******************************************************************************* * Copyright (c) 2008-2010 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Sonatype, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.m2e.core.internal.project.registry; import java.io.File; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.m2e.core.embedder.ArtifactKey; /** * WorkspaceStateDelta * * @author igor */ public class MutableProjectRegistry extends BasicProjectRegistry implements IProjectRegistry { private static final long serialVersionUID = 4879169945594340946L; private final ProjectRegistry parent; private final int parentVersion; private boolean closed; public MutableProjectRegistry(ProjectRegistry state) { super(state); this.parent = state; this.parentVersion = state.getVersion(); } private void assertNotClosed() { if(closed) { throw new IllegalStateException("Can't modify closed MutableProjectRegistry"); //$NON-NLS-1$ } } public void setProject(IFile pom, MavenProjectFacade facade) { assertNotClosed(); // remove MavenProjectFacade oldFacade = workspacePoms.remove(pom); if(oldFacade != null) { Set<IFile> paths = workspaceArtifacts.get(oldFacade.getArtifactKey()); if(paths != null) { paths.remove(pom); } } if(facade != null) { // Add the project to workspaceProjects map workspacePoms.put(pom, facade); // Add the project to workspaceArtifacts map Set<IFile> paths = workspaceArtifacts.get(facade.getArtifactKey()); if(paths == null) { paths = new LinkedHashSet<IFile>(); workspaceArtifacts.put(facade.getArtifactKey(), paths); } paths.add(pom); } } public void removeProject(IFile pom, ArtifactKey mavenProject) { assertNotClosed(); // remove project from requiredCapabilities map removeRequiredCapabilities(pom); // Remove the project from workspaceProjects, projectRequirements and projectCapabilities maps MavenProjectFacade facade = workspacePoms.remove(pom); projectRequirements.remove(pom); projectCapabilities.remove(pom); // Remove the project from workspaceArtifacts map if(mavenProject != null) { Set<IFile> paths = workspaceArtifacts.get(mavenProject); if(paths != null) { paths.remove(pom); } } if(facade != null) { workspacePomFiles.remove(facade.getPomFile()); } } static boolean isSameProject(IResource r1, IResource r2) { if(r1 == null || r2 == null) { return false; } return r1.getProject().equals(r2.getProject()); } public Set<IFile> removeWorkspaceModules(IFile pom, ArtifactKey mavenProject) { assertNotClosed(); return getDependents(MavenCapability.createMavenParent(mavenProject), true); } public boolean isStale() { return parentVersion != parent.getVersion(); } public void close() { this.closed = true; clear(); } private boolean isClosed() { return closed; } // IProjectRegistry public MavenProjectFacade getProjectFacade(IFile pom) { if(isClosed()) { return parent.getProjectFacade(pom); } return super.getProjectFacade(pom); } public MavenProjectFacade getProjectFacade(File pom) { if(isClosed()) { return parent.getProjectFacade(pom); } return super.getProjectFacade(pom); } public MavenProjectFacade getProjectFacade(String groupId, String artifactId, String version) { if(isClosed()) { return parent.getProjectFacade(groupId, artifactId, version); } return super.getProjectFacade(groupId, artifactId, version); } public MavenProjectFacade[] getProjects() { if(isClosed()) { return parent.getProjects(); } return super.getProjects(); } public Map<ArtifactKey, Collection<IFile>> getWorkspaceArtifacts(String groupId, String artifactId) { if(isClosed()) { return parent.getWorkspaceArtifacts(groupId, artifactId); } return super.getWorkspaceArtifacts(groupId, artifactId); } // low level access and manipulation /** * Returns all workspace projects that require given Capability. */ public Set<IFile> getDependents(Capability capability, boolean remove) { return getDependents(capability, false, remove); } /** * Returns all workspace projects that require given Capability of a certain version, if available */ public Set<IFile> getVersionedDependents(Capability capability, boolean remove) { return getDependents(capability, true, remove); } private Set<IFile> getDependents(Capability capability, boolean versionMatch, boolean remove) { Map<RequiredCapability, Set<IFile>> rs = requiredCapabilities.get(capability.getVersionlessKey()); if(rs == null) { return Collections.emptySet(); } Set<IFile> result = new LinkedHashSet<IFile>(); Iterator<Entry<RequiredCapability, Set<IFile>>> iter = rs.entrySet().iterator(); while(iter.hasNext()) { Entry<RequiredCapability, Set<IFile>> entry = iter.next(); if(entry.getKey().isPotentialMatch(capability, versionMatch)) { result.addAll(entry.getValue()); if(remove) { iter.remove(); } } } if(remove && rs.isEmpty()) { requiredCapabilities.remove(capability.getVersionlessKey()); } return result; } /** * Returns all workspace projects that require given versionless Capability. */ public Set<IFile> getDependents(VersionlessKey capability, boolean remove) { Map<RequiredCapability, Set<IFile>> rs; if(remove) { rs = requiredCapabilities.remove(capability); } else { rs = requiredCapabilities.get(capability); } if(rs == null) { return Collections.emptySet(); } Set<IFile> result = new LinkedHashSet<IFile>(); for(Set<IFile> dependents : rs.values()) { result.addAll(dependents); } return result; } private void addRequiredCapability(IFile pom, RequiredCapability req) { Map<RequiredCapability, Set<IFile>> keyEntry = requiredCapabilities.get(req.getVersionlessKey()); if(keyEntry == null) { keyEntry = new HashMap<RequiredCapability, Set<IFile>>(); requiredCapabilities.put(req.getVersionlessKey(), keyEntry); } Set<IFile> poms = keyEntry.get(req); if(poms == null) { poms = new HashSet<IFile>(); keyEntry.put(req, poms); } poms.add(pom); } public Set<Capability> setCapabilities(IFile pom, Set<Capability> capabilities) { return capabilities != null ? projectCapabilities.put(pom, capabilities) : projectCapabilities.remove(pom); } public Set<RequiredCapability> setRequirements(IFile pom, Set<RequiredCapability> requirements) { removeRequiredCapabilities(pom); if(requirements != null) { for(RequiredCapability requirement : requirements) { addRequiredCapability(pom, requirement); } return projectRequirements.put(pom, requirements); } return projectRequirements.remove(pom); } private void removeRequiredCapabilities(IFile pom) { // TODO likely too slow Iterator<Entry<VersionlessKey, Map<RequiredCapability, Set<IFile>>>> keysIter = requiredCapabilities.entrySet() .iterator(); while(keysIter.hasNext()) { Entry<VersionlessKey, Map<RequiredCapability, Set<IFile>>> keysEntry = keysIter.next(); Iterator<Entry<RequiredCapability, Set<IFile>>> requirementsIter = keysEntry.getValue().entrySet().iterator(); while(requirementsIter.hasNext()) { Entry<RequiredCapability, Set<IFile>> requirementsEntry = requirementsIter.next(); requirementsEntry.getValue().remove(pom); if(requirementsEntry.getValue().isEmpty()) { // was last project that required this capability requirementsIter.remove(); } } if(keysEntry.getValue().isEmpty()) { // was last project that required this capability versionless key keysIter.remove(); } } } }