blob: 2062cb7d420009db0b7b612f4452dd83e127835c [file] [log] [blame]
/*******************************************************************************
* 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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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();
}
}
}
}