Author: tjwatson
Date: Thu Dec 15 21:44:07 2016
New Revision: 1774530

URL: http://svn.apache.org/viewvc?rev=1774530&view=rev
Log:
[FELIX-5450] Fragments with multiple hosts can cause
java.lang.ArrayIndexOutOfBoundsException

Change-Id: Id1123619bd89a4d3f6a8a251fe8ee6944c113e56
Signed-off-by: Tom Watson <tjwat...@apache.org>

Modified:
    felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java
    
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java
    
felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java

Modified: 
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java?rev=1774530&r1=1774529&r2=1774530&view=diff
==============================================================================
--- 
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java 
(original)
+++ 
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java 
Thu Dec 15 21:44:07 2016
@@ -834,6 +834,30 @@ class Candidates
         }
 
         // Step 4
+        // First copy candidates for wrapped requirements to the host.
+        for (WrappedResource hostResource : hostResources) {
+            for (Requirement r : hostResource.getRequirements(null))
+            {
+                Requirement origReq = ((WrappedRequirement) 
r).getDeclaredRequirement();
+                CandidateSelector cands = m_candidateMap.get(origReq);
+                if (cands != null)
+                {
+                    if (cands instanceof ShadowList)
+                    {
+                        m_candidateMap.put(r, ShadowList.deepCopy((ShadowList) 
cands));
+                    } else {
+                        m_candidateMap.put(r, cands.copy());
+                    }
+                    for (Capability cand : cands.getRemainingCandidates())
+                    {
+                        Set<Requirement> dependents = m_dependentMap.get(cand);
+                        dependents.remove(origReq);
+                        dependents.add(r);
+                    }
+                }
+            }
+        }
+
         for (WrappedResource hostResource : hostResources)
         {
             // Replaces capabilities from fragments with the capabilities
@@ -918,28 +942,6 @@ class Candidates
                     }
                 }
             }
-
-            // Copy candidates for fragment requirements to the host.
-            for (Requirement r : hostResource.getRequirements(null))
-            {
-                Requirement origReq = ((WrappedRequirement) 
r).getDeclaredRequirement();
-                CandidateSelector cands = m_candidateMap.get(origReq);
-                if (cands != null)
-                {
-                    if (cands instanceof ShadowList)
-                    {
-                        m_candidateMap.put(r, ShadowList.deepCopy((ShadowList) 
cands));
-                    } else {
-                        m_candidateMap.put(r, cands.copy());
-                    }
-                    for (Capability cand : cands.getRemainingCandidates())
-                    {
-                        Set<Requirement> dependents = m_dependentMap.get(cand);
-                        dependents.remove(origReq);
-                        dependents.add(r);
-                    }
-                }
-            }
         }
 
         // Lastly, verify that all mandatory revisions are still

Modified: 
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java?rev=1774530&r1=1774529&r2=1774530&view=diff
==============================================================================
--- 
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java
 (original)
+++ 
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java
 Thu Dec 15 21:44:07 2016
@@ -27,36 +27,29 @@ import org.osgi.service.resolver.Resolve
 
 public class ShadowList extends CandidateSelector
 {
-    public static  ShadowList createShadowList(CandidateSelector original) {
+    public static ShadowList createShadowList(CandidateSelector original) {
         if (original instanceof ShadowList)
         {
             throw new IllegalArgumentException("Cannot create a ShadowList 
using another ShadowList.");
         }
-        return new ShadowList(original);
+        return new ShadowList(original.unmodifiable, original.unmodifiable, 
original.isUnmodifiable);
     }
 
     public static ShadowList deepCopy(ShadowList original) {
-        List<Capability> originalCopy = new 
ArrayList<Capability>(original.m_original);
-        return new ShadowList(original.unmodifiable, originalCopy, 
original.isUnmodifiable);
+        return new ShadowList(original.unmodifiable, original.m_original, 
original.isUnmodifiable);
     }
 
     private final List<Capability> m_original;
 
-    private ShadowList(CandidateSelector original)
-    {
-        super(original);
-        m_original = new 
ArrayList<Capability>(original.getRemainingCandidates());
-    }
-
     private ShadowList(CandidateSelector shadow, List<Capability> original)
     {
         super(shadow);
         m_original = original;
     }
 
-    public ShadowList(List<Capability> unmodifiable, List<Capability> 
originalCopy, AtomicBoolean isUnmodifiable) {
+    private ShadowList(List<Capability> unmodifiable, List<Capability> 
original, AtomicBoolean isUnmodifiable) {
         super(unmodifiable, isUnmodifiable);
-        m_original = originalCopy;
+        m_original = new ArrayList<Capability>(original);
     }
 
     public ShadowList copy() {

Modified: 
felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java?rev=1774530&r1=1774529&r2=1774530&view=diff
==============================================================================
--- 
felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java
 (original)
+++ 
felix/trunk/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java
 Thu Dec 15 21:44:07 2016
@@ -686,6 +686,146 @@ public class ResolverTest
     }
 
     @Test
+    public void testScenario15() throws Exception
+    {
+        ResolverImpl resolver = new ResolverImpl(new Logger(Logger.LOG_DEBUG), 
1);
+
+        Map<Requirement, List<Capability>> candMap = new HashMap<Requirement, 
List<Capability>>();
+
+        ResourceImpl exporter = new ResourceImpl("exporter", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("1.0.0"));
+        Capability exporter_hostCap = addCap(exporter, 
HostNamespace.HOST_NAMESPACE, "exporter");
+        Capability exporter_pkgCap = addCap(exporter, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl exporterFrag = new ResourceImpl("exporter.frag", 
IdentityNamespace.TYPE_FRAGMENT, Version.emptyVersion);
+        Requirement exporterFrag_hostReq = addReq(exporterFrag, 
HostNamespace.HOST_NAMESPACE, "exporter");
+
+        ResourceImpl host1 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("1.0.0"));
+        Capability host1_hostCap = addCap(host1, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host1_pkgReq = addReq(host1, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl host2 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("2.0.0"));
+        Capability host2_hostCap = addCap(host2, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host2_pkgReq = addReq(host2, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl host3 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("3.0.0"));
+        Capability host3_hostCap = addCap(host3, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host3_pkgReq = addReq(host3, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl host4 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("4.0.0"));
+        Capability host4_hostCap = addCap(host4, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host4_pkgReq = addReq(host4, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl host5 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("5.0.0"));
+        Capability host5_hostCap = addCap(host5, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host5_pkgReq = addReq(host5, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl host6 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("6.0.0"));
+        Capability host6_hostCap = addCap(host6, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host6_pkgReq = addReq(host6, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl host7 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("7.0.0"));
+        Capability host7_hostCap = addCap(host7, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host7_pkgReq = addReq(host7, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl host8 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("8.0.0"));
+        Capability host8_hostCap = addCap(host8, HostNamespace.HOST_NAMESPACE, 
"host");
+        Requirement host8_pkgReq = addReq(host8, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl hostFrag = new ResourceImpl("host.frag", 
IdentityNamespace.TYPE_FRAGMENT, Version.emptyVersion);
+        Requirement hostFrag_hostReq = addReq(hostFrag, 
HostNamespace.HOST_NAMESPACE, "host");
+        Requirement hostFrag_pkgReq = addReq(hostFrag, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        candMap.put(exporterFrag_hostReq, 
Collections.singletonList(exporter_hostCap));
+        candMap.put(host1_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(host2_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(host3_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(host4_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(host5_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(host6_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(host7_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(host8_pkgReq, Collections.singletonList(exporter_pkgCap));
+        candMap.put(hostFrag_pkgReq, 
Collections.singletonList(exporter_pkgCap));
+        candMap.put(hostFrag_hostReq,
+            Arrays.asList(host1_hostCap, host2_hostCap, host3_hostCap, 
host4_hostCap, host5_hostCap, host6_hostCap, host7_hostCap, host8_hostCap));
+
+        ResolveContextImpl rci = new ResolveContextImpl(Collections.<Resource, 
Wiring> emptyMap(), candMap,
+            Arrays.<Resource> asList(host1, host2, host3, host4, exporter, 
exporterFrag, host5, host6, host7, host8, hostFrag),
+            Collections.<Resource> emptyList());
+
+        Map<Resource, List<Wire>> wireMap = resolver.resolve(rci);
+
+        // all bundles should be resolved
+        assertEquals(11, wireMap.size());
+
+        // There should be 8 hosts
+        List<Wire> wiresHostFrag = wireMap.get(hostFrag);
+        assertNotNull(wiresHostFrag);
+        assertEquals(8, wiresHostFrag.size());
+
+        List<Wire> wiresHost1 = wireMap.get(host1);
+        assertNotNull(wiresHost1);
+    }
+
+    @Test
+    public void testScenario16() throws Exception
+    {
+        ResolverImpl resolver = new ResolverImpl(new Logger(Logger.LOG_DEBUG), 
1);
+
+        Map<Requirement, List<Capability>> candMap = new HashMap<Requirement, 
List<Capability>>();
+
+        ResourceImpl exporter = new ResourceImpl("exporter", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("1.0.0"));
+        Capability exporter_hostCap = addCap(exporter, 
HostNamespace.HOST_NAMESPACE, "exporter");
+        Capability exporter_pkgCap = addCap(exporter, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        ResourceImpl exporterFrag = new ResourceImpl("exporter.frag", 
IdentityNamespace.TYPE_FRAGMENT, Version.emptyVersion);
+        Requirement exporterFrag_hostReq = addReq(exporterFrag, 
HostNamespace.HOST_NAMESPACE, "exporter");
+
+        ResourceImpl host1 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("1.0.0"));
+        Capability host1_hostCap = addCap(host1, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl host2 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("2.0.0"));
+        Capability host2_hostCap = addCap(host2, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl host3 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("3.0.0"));
+        Capability host3_hostCap = addCap(host3, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl host4 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("4.0.0"));
+        Capability host4_hostCap = addCap(host4, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl host5 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("5.0.0"));
+        Capability host5_hostCap = addCap(host4, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl host6 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("6.0.0"));
+        Capability host6_hostCap = addCap(host4, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl host7 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("7.0.0"));
+        Capability host7_hostCap = addCap(host4, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl host8 = new ResourceImpl("host", 
IdentityNamespace.TYPE_BUNDLE, Version.parseVersion("8.0.0"));
+        Capability host8_hostCap = addCap(host4, HostNamespace.HOST_NAMESPACE, 
"host");
+
+        ResourceImpl hostFrag = new ResourceImpl("host.frag", 
IdentityNamespace.TYPE_FRAGMENT, Version.emptyVersion);
+        Requirement hostFrag_hostReq = addReq(hostFrag, 
HostNamespace.HOST_NAMESPACE, "host");
+        Requirement hostFrag_pkgReq = addReq(hostFrag, 
PackageNamespace.PACKAGE_NAMESPACE, "exporter");
+
+        candMap.put(exporterFrag_hostReq, 
Collections.singletonList(exporter_hostCap));
+        candMap.put(hostFrag_pkgReq, 
Collections.singletonList(exporter_pkgCap));
+
+        candMap.put(hostFrag_hostReq,
+            Arrays.asList(host1_hostCap, host2_hostCap, host3_hostCap, 
host4_hostCap, host5_hostCap, host6_hostCap, host7_hostCap, host8_hostCap));
+
+        ResolveContextImpl rci = new ResolveContextImpl(Collections.<Resource, 
Wiring> emptyMap(), candMap,
+            Arrays.<Resource> asList(host1, host2, host3, host4, exporter, 
exporterFrag, hostFrag, host5, host6, host7, host8),
+            Collections.<Resource> emptyList());
+
+        Map<Resource, List<Wire>> wireMap = resolver.resolve(rci);
+
+        // all bundles should be resolved
+        assertEquals(11, wireMap.size());
+
+    }
+
+    @Test
     public void testPackageSources() throws Exception {
         Method m = ResolverImpl.class.getDeclaredMethod("getPackageSources",
                 Capability.class, Map.class);


Reply via email to