460983 support version ranges when resolved artifacts from workspace

Change-Id: I2a8dbc9b5214354d86c544d4a8b9b62ebb5f74e2
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java
index cae366e..0e9ecb7 100644
--- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java
@@ -13,12 +13,16 @@
 
 import java.io.File;
 import java.io.Serializable;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
 import org.eclipse.core.resources.IFile;
 
 import org.eclipse.m2e.core.embedder.ArtifactKey;
@@ -129,9 +133,15 @@
     return workspacePoms.values().toArray(new MavenProjectFacade[workspacePoms.size()]);
   }
 
-  public IFile getWorkspaceArtifact(ArtifactKey key) {
-    Set<IFile> paths = workspaceArtifacts.get(key);
-    return paths == null || paths.isEmpty() ? null : paths.iterator().next();
+  public Map<ArtifactKey, Collection<IFile>> getWorkspaceArtifacts(String groupId, String artifactId) {
+    Multimap<ArtifactKey, IFile> artifacts = HashMultimap.create();
+    for(Map.Entry<ArtifactKey, Set<IFile>> entry : workspaceArtifacts.entrySet()) {
+      ArtifactKey workspaceKey = entry.getKey();
+      if(groupId.equals(workspaceKey.getGroupId()) && artifactId.equals(workspaceKey.getArtifactId())) {
+        artifacts.putAll(workspaceKey, entry.getValue());
+      }
+    }
+    return artifacts.asMap();
   }
 
   protected void clear() {
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java
index 413191f..326ff94 100644
--- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java
@@ -13,11 +13,18 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.repository.WorkspaceReader;
 import org.eclipse.aether.repository.WorkspaceRepository;
+import org.eclipse.aether.util.version.GenericVersionScheme;
+import org.eclipse.aether.version.InvalidVersionSpecificationException;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IWorkspaceRoot;
@@ -30,6 +37,7 @@
 
 
 public final class EclipseWorkspaceArtifactRepository extends LocalArtifactRepository implements WorkspaceReader {
+  private static final GenericVersionScheme versionScheme = new GenericVersionScheme();
 
   private final transient ProjectRegistryManager.Context context;
 
@@ -53,8 +61,7 @@
     }
 
     // check in the workspace, note that workspace artifacts never have classifiers
-    ArtifactKey key = new ArtifactKey(groupId, artifactId, baseVersion, null);
-    IFile pom = context.state.getWorkspaceArtifact(key);
+    IFile pom = getWorkspaceArtifact(groupId, artifactId, baseVersion);
     if(pom == null || !pom.isAccessible()) {
       return null;
     }
@@ -85,6 +92,36 @@
     return null;
   }
 
+  private IFile getWorkspaceArtifact(String groupId, String artifactId, String version) {
+    Map<ArtifactKey, Collection<IFile>> workspaceArtifacts = context.state.getWorkspaceArtifacts(groupId, artifactId);
+    if(workspaceArtifacts.isEmpty()) {
+      return null;
+    }
+    VersionConstraint constraint;
+    try {
+      constraint = versionScheme.parseVersionConstraint(version);
+    } catch(InvalidVersionSpecificationException e) {
+      return null; // broken version range spec does not match anything
+    }
+    TreeMap<Version, ArtifactKey> matchingArtifacts = new TreeMap<>();
+    // in vast majority of cases there will be single workspace artifact with matching groupId and artifactId
+    for(ArtifactKey workspaceArtifact : workspaceArtifacts.keySet()) {
+      try {
+        Version workspaceVersion = versionScheme.parseVersion(workspaceArtifact.getVersion());
+        if(constraint.containsVersion(workspaceVersion)) {
+          matchingArtifacts.put(workspaceVersion, workspaceArtifact);
+        }
+      } catch(InvalidVersionSpecificationException e) {
+        // this can't happen with GenericVersionScheme
+      }
+    }
+    if(matchingArtifacts.isEmpty()) {
+      return null;
+    }
+    ArtifactKey matchingArtifact = matchingArtifacts.values().iterator().next();
+    return workspaceArtifacts.get(matchingArtifact).iterator().next();
+  }
+
   public File findArtifact(Artifact artifact) {
     return resolveAsEclipseProject(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(),
         artifact.getClassifier(), artifact.getExtension());
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java
index c13fc6c..deab0b7 100644
--- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java
@@ -11,6 +11,9 @@
 
 package org.eclipse.m2e.core.internal.project.registry;
 
+import java.util.Collection;
+import java.util.Map;
+
 import org.eclipse.core.resources.IFile;
 
 import org.eclipse.m2e.core.embedder.ArtifactKey;
@@ -29,6 +32,6 @@
 
   public MavenProjectFacade[] getProjects();
 
-  public IFile getWorkspaceArtifact(ArtifactKey key);
+  public Map<ArtifactKey, Collection<IFile>> getWorkspaceArtifacts(String groupId, String artifactId);
 
 }
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java
index 1804b76..96f74aa 100644
--- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java
@@ -12,6 +12,7 @@
 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;
@@ -160,11 +161,11 @@
     return super.getProjects();
   }
 
-  public IFile getWorkspaceArtifact(ArtifactKey key) {
+  public Map<ArtifactKey, Collection<IFile>> getWorkspaceArtifacts(String groupId, String artifactId) {
     if(isClosed()) {
-      return parent.getWorkspaceArtifact(key);
+      return parent.getWorkspaceArtifacts(groupId, artifactId);
     }
-    return super.getWorkspaceArtifact(key);
+    return super.getWorkspaceArtifacts(groupId, artifactId);
   }
 
   // low level access and manipulation
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java
index 12f612f..84ae5ec 100644
--- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java
@@ -13,7 +13,9 @@
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.eclipse.core.resources.IFile;
@@ -47,8 +49,8 @@
     return super.getProjects();
   }
 
-  public synchronized IFile getWorkspaceArtifact(ArtifactKey key) {
-    return super.getWorkspaceArtifact(key);
+  public synchronized Map<ArtifactKey, Collection<IFile>> getWorkspaceArtifacts(String groupId, String artifactId) {
+    return super.getWorkspaceArtifacts(groupId, artifactId);
   }
 
   public synchronized List<MavenProjectChangedEvent> apply(MutableProjectRegistry newState)