Fixed some bugs in the fragment conflict detection algorithm.
I thought VersionRange implemented equals, but it was using the
default implementation. Also made optionality a little more flexible
by allowing optional requirements to overlap non-optional ones.
(FELIX-29)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@772010 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
index bdbff4a..6760a1c 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -35,6 +35,7 @@
 import org.apache.felix.moduleloader.IModule;
 import org.apache.felix.moduleloader.IRequirement;
 import org.apache.felix.moduleloader.IWire;
+import org.osgi.framework.Constants;
 import org.osgi.framework.PackagePermission;
 import org.osgi.framework.Version;
 
@@ -276,33 +277,53 @@
         {
             return true;
         }
-        // If optionality is not the same, then they conflict.
-        if (existing.isOptional() != additional.isOptional())
+        // If optionality is not the same, then they conflict, unless
+        // the existing requirement is not optional, then it doesn't matter
+        // what subsequent requirements are since non-optional is stronger
+        // than optional.
+        if (existing.isOptional() && (existing.isOptional() != additional.isOptional()))
         {
             return true;
         }
         // Verify directives are the same.
+        // This is sort of ugly, but we need to remove
+        // the resolution directive, since it is effectively
+        // test above when checking optionality.
+        // Put directives in a map, since ordering is arbitrary.
         final R4Directive[] exDirs = (existing.getDirectives() == null)
             ? new R4Directive[0] : existing.getDirectives();
-        final R4Directive[] addDirs = (additional.getDirectives() == null)
-            ? new R4Directive[0] : additional.getDirectives();
-        // If different number of directives, then they conflict.
-        if (exDirs.length != addDirs.length)
-        {
-            return true;
-        }
-        // Put directives in a map, since ordering is arbitrary.
         final Map exDirMap = new HashMap();
         for (int i = 0; i < exDirs.length; i++)
         {
-            exDirMap.put(exDirs[i].getName(), exDirs[i]);
+            if (!exDirs[i].getName().equals(Constants.RESOLUTION_DIRECTIVE))
+            {
+                exDirMap.put(exDirs[i].getName(), exDirs[i]);
+            }
         }
-        // If directive values do not match, then they conflict.
+        final R4Directive[] addDirs = (additional.getDirectives() == null)
+            ? new R4Directive[0] : additional.getDirectives();
+        final Map addDirMap = new HashMap();
         for (int i = 0; i < addDirs.length; i++)
         {
-            final R4Directive exDir = (R4Directive) exDirMap.get(addDirs[i].getName());
+            if (!addDirs[i].getName().equals(Constants.RESOLUTION_DIRECTIVE))
+            {
+                addDirMap.put(addDirs[i].getName(), addDirs[i]);
+            }
+        }
+        // If different number of directives, then they conflict.
+        if (exDirMap.size() != addDirMap.size())
+        {
+            return true;
+        }
+        // If directive values do not match, then they conflict.
+        for (Iterator it = addDirMap.entrySet().iterator(); it.hasNext(); )
+        {
+            final Map.Entry entry = (Map.Entry) it.next();
+            final String name = (String) entry.getKey();
+            final R4Directive addDir = (R4Directive) entry.getValue();
+            final R4Directive exDir = (R4Directive) exDirMap.get(name);
             if ((exDir == null) ||
-                !exDir.getValue().equals(addDirs[i].getValue()))
+                !exDir.getValue().equals(addDir.getValue()))
             {
                 return true;
             }
diff --git a/framework/src/main/java/org/apache/felix/framework/util/VersionRange.java b/framework/src/main/java/org/apache/felix/framework/util/VersionRange.java
index 0a0d386..f415fa5 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/VersionRange.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/VersionRange.java
@@ -98,6 +98,46 @@
         }
     }
 
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        final VersionRange other = (VersionRange) obj;
+        if (m_low != other.m_low && (m_low == null || !m_low.equals(other.m_low)))
+        {
+            return false;
+        }
+        if (m_isLowInclusive != other.m_isLowInclusive)
+        {
+            return false;
+        }
+        if (m_high != other.m_high && (m_high == null || !m_high.equals(other.m_high)))
+        {
+            return false;
+        }
+        if (m_isHighInclusive != other.m_isHighInclusive)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public int hashCode()
+    {
+        int hash = 5;
+        hash = 97 * hash + (m_low != null ? m_low.hashCode() : 0);
+        hash = 97 * hash + (m_isLowInclusive ? 1 : 0);
+        hash = 97 * hash + (m_high != null ? m_high.hashCode() : 0);
+        hash = 97 * hash + (m_isHighInclusive ? 1 : 0);
+        return hash;
+    }
+
     public String toString()
     {
         if (m_toString == null)