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);