You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2018/02/23 13:52:46 UTC
svn commit: r1825128 - in /felix/trunk/osgi-r7/resolver: ./
src/main/java/org/apache/felix/resolver/
src/main/java/org/osgi/service/resolver/
src/test/java/org/apache/felix/resolver/test/
Author: pauls
Date: Fri Feb 23 13:52:46 2018
New Revision: 1825128
URL: http://svn.apache.org/viewvc?rev=1825128&view=rev
Log:
Merge FELIX-5601 into the r7 resolver, update to the latest OSGi sources, and set the version to 1.2.0-SNAPSHOT.
Modified:
felix/trunk/osgi-r7/resolver/pom.xml
felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/Candidates.java
felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/ResolveContext.java
felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/Resolver.java
felix/trunk/osgi-r7/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java
Modified: felix/trunk/osgi-r7/resolver/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/resolver/pom.xml?rev=1825128&r1=1825127&r2=1825128&view=diff
==============================================================================
--- felix/trunk/osgi-r7/resolver/pom.xml (original)
+++ felix/trunk/osgi-r7/resolver/pom.xml Fri Feb 23 13:52:46 2018
@@ -29,7 +29,7 @@
<description>
Provide OSGi resolver service.
</description>
- <version>1.11.0-SNAPSHOT</version>
+ <version>1.2.0-SNAPSHOT</version>
<artifactId>org.apache.felix.resolver</artifactId>
<scm>
<connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/resolver</connection>
Modified: felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/Candidates.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/Candidates.java?rev=1825128&r1=1825127&r2=1825128&view=diff
==============================================================================
--- felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/Candidates.java (original)
+++ felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/Candidates.java Fri Feb 23 13:52:46 2018
@@ -1201,7 +1201,61 @@ class Candidates
public boolean canRemoveCandidate(Requirement req)
{
CandidateSelector candidates = m_candidateMap.get(req);
- return ((candidates != null) && (candidates.getRemainingCandidateCount() > 1 || Util.isOptional(req)));
+ if (candidates != null)
+ {
+ Capability current = candidates.getCurrentCandidate();
+ if (current != null)
+ {
+ // IMPLEMENTATION NOTE:
+ // Here we check for a req that is used for a substitutable export.
+ // If we find a substitutable req then an extra check is done to see
+ // if the substitutable capability is currently depended on as the
+ // only provider of some other requirement. If it is then we do not
+ // allow the candidate to be removed.
+ // This is done because of the way we attempt to reduce permutations
+ // checked by permuting all used requirements that conflict with a
+ // directly imported/required capability in one go.
+ // If we allowed these types of substitutable requirements to move
+ // to the next capability then the permutation would be thrown out
+ // because it would cause some other resource to not resolve.
+ // That in turn would throw out the complete permutation along with
+ // any follow on permutations that could have resulted.
+ // See ResolverImpl::checkPackageSpaceConsistency
+
+ // Check if the current candidate is substitutable by the req;
+ // This check is necessary here because of the way we traverse used blames
+ // allows multiple requirements to be permuted in one Candidates
+ if (req.equals(m_subtitutableMap.get(current)))
+ {
+ // this is a substitute req,
+ // make sure there is not an existing dependency that would fail if we substitute
+ Set<Requirement> dependents = m_dependentMap.get(current);
+ if (dependents != null)
+ {
+ for (Requirement dependent : dependents)
+ {
+ CandidateSelector dependentSelector = m_candidateMap.get(
+ dependent);
+ // If the dependent selector only has one capability left then check if
+ // the current candidate is the selector's current candidate.
+ if (dependentSelector != null
+ && dependentSelector.getRemainingCandidateCount() <= 1)
+ {
+ if (current.equals(
+ dependentSelector.getCurrentCandidate()))
+ {
+ // return false since we do not want to allow this requirement
+ // to substitute the capability
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return candidates.getRemainingCandidateCount() > 1 || Util.isOptional(req);
+ }
+ return false;
}
static class DynamicImportFailed extends ResolutionError {
Modified: felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java?rev=1825128&r1=1825127&r2=1825128&view=diff
==============================================================================
--- felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java (original)
+++ felix/trunk/osgi-r7/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java Fri Feb 23 13:52:46 2018
@@ -23,6 +23,8 @@ import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
import org.apache.felix.resolver.util.ArrayMap;
import org.apache.felix.resolver.util.CandidateSelector;
import org.apache.felix.resolver.util.OpenHashMap;
@@ -1308,8 +1310,6 @@ public class ResolverImpl implements Res
Packages pkgs = resourcePkgMap.get(resource);
ResolutionError rethrow = null;
- Candidates permutation = null;
- Set<Requirement> mutated = null;
// Check for conflicting imports from fragments.
// TODO: Is this only needed for imports or are generic and bundle requirements also needed?
@@ -1351,6 +1351,16 @@ public class ResolverImpl implements Res
}
}
}
+ // IMPLEMENTATION NOTE:
+ // Below we track the mutated reqs that have been permuted
+ // in a single candidates permutation. This permutation may contain a
+ // delta of several reqs which conflict with a directly imported/required candidates.
+ // When several reqs are permuted at the same time this reduces the number of solutions tried.
+ // See the method Candidates::canRemoveCandidate for a case where substitutions must be checked
+ // because of this code that may permute multiple reqs in on candidates permutation.
+ AtomicReference<Candidates> permRef1 = new AtomicReference<Candidates>();
+ AtomicReference<Candidates> permRef2 = new AtomicReference<Candidates>();
+ Set<Requirement> mutated = null;
// Check if there are any uses conflicts with exported packages.
for (Entry<String, Blame> entry : pkgs.m_exportedPkgs.fast())
@@ -1366,54 +1376,11 @@ public class ResolverImpl implements Res
{
if (!isCompatible(exportBlame, usedBlames.m_cap, resourcePkgMap))
{
- for (Blame usedBlame : usedBlames.m_blames)
- {
- if (session.checkMultiple(usedBlames, usedBlame, allCandidates))
- {
- // Continue to the next usedBlame, if possible we
- // removed the conflicting candidates.
- continue;
- }
- // Create a candidate permutation that eliminates all candidates
- // that conflict with existing selected candidates.
- permutation = (permutation != null)
- ? permutation
- : allCandidates.copy();
- if (rethrow == null)
- {
- rethrow = new UseConstraintError(
- session.getContext(), allCandidates, resource, pkgName, usedBlame);
- }
- mutated = (mutated != null)
+ mutated = (mutated != null)
? mutated
: new HashSet<Requirement>();
-
- for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--)
- {
- Requirement req = usedBlame.m_reqs.get(reqIdx);
- // Sanity check for multiple.
- if (Util.isMultiple(req))
- {
- continue;
- }
- // If we've already permutated this requirement in another
- // uses constraint, don't permutate it again just continue
- // with the next uses constraint.
- if (mutated.contains(req))
- {
- break;
- }
-
- // See if we can permutate the candidates for blamed
- // requirement; there may be no candidates if the resource
- // associated with the requirement is already resolved.
- if (permutation.canRemoveCandidate(req)) {
- permutation.removeFirstCandidate(req);
- mutated.add(req);
- break;
- }
- }
- }
+ rethrow = permuteUsedBlames(session, rethrow, allCandidates, resource,
+ pkgName, null, usedBlames, permRef1, permRef2, mutated);
}
}
@@ -1421,7 +1388,8 @@ public class ResolverImpl implements Res
{
if (!mutated.isEmpty())
{
- session.addPermutation(PermutationType.USES, permutation);
+ session.addPermutation(PermutationType.USES, permRef1.get());
+ session.addPermutation(PermutationType.USES, permRef2.get());
}
if (m_logger.isDebugEnabled())
{
@@ -1463,60 +1431,12 @@ public class ResolverImpl implements Res
{
if (!isCompatible(requirementBlames, usedBlames.m_cap, resourcePkgMap))
{
- // Split packages, need to think how to get a good message for split packages (sigh)
+ mutated = (mutated != null)
+ ? mutated
+ : new HashSet<Requirement>();// Split packages, need to think how to get a good message for split packages (sigh)
// For now we just use the first requirement that brings in the package that conflicts
Blame requirementBlame = requirementBlames.get(0);
- for (Blame usedBlame : usedBlames.m_blames)
- {
- if (session.checkMultiple(usedBlames, usedBlame, allCandidates))
- {
- // Continue to the next usedBlame, if possible we
- // removed the conflicting candidates.
- continue;
- }
- // Create a candidate permutation that eliminates all candidates
- // that conflict with existing selected candidates.
- permutation = (permutation != null)
- ? permutation
- : allCandidates.copy();
- if (rethrow == null)
- {
- rethrow = new UseConstraintError(
- session.getContext(), allCandidates,
- resource, pkgName,
- requirementBlame, usedBlame);
- }
-
- mutated = (mutated != null)
- ? mutated
- : new HashSet<Requirement>();
-
- for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--)
- {
- Requirement req = usedBlame.m_reqs.get(reqIdx);
- // Sanity check for multiple.
- if (Util.isMultiple(req))
- {
- continue;
- }
- // If we've already permutated this requirement in another
- // uses constraint, don't permutate it again just continue
- // with the next uses constraint.
- if (mutated.contains(req))
- {
- break;
- }
-
- // See if we can permutate the candidates for blamed
- // requirement; there may be no candidates if the resource
- // associated with the requirement is already resolved.
- if (permutation.canRemoveCandidate(req)) {
- permutation.removeFirstCandidate(req);
- mutated.add(req);
- break;
- }
- }
- }
+ rethrow = permuteUsedBlames(session, rethrow, allCandidates, resource, pkgName, requirementBlame, usedBlames, permRef1, permRef2, mutated);
}
// If there was a uses conflict, then we should add a uses
@@ -1530,7 +1450,8 @@ public class ResolverImpl implements Res
// Add uses permutation if we m_mutated any candidates.
if (!mutated.isEmpty())
{
- session.addPermutation(PermutationType.USES, permutation);
+ session.addPermutation(PermutationType.USES, permRef1.get());
+ session.addPermutation(PermutationType.USES, permRef2.get());
}
// Try to permutate the candidate for the original
@@ -1598,7 +1519,99 @@ public class ResolverImpl implements Res
}
return null;
}
+
+ private ResolutionError permuteUsedBlames(ResolveSession session,
+ ResolutionError rethrow, Candidates allCandidates, Resource resource,
+ String pkgName, Blame requirementBlame, UsedBlames usedBlames,
+ AtomicReference<Candidates> permRef1, AtomicReference<Candidates> permRef2,
+ Set<Requirement> mutated)
+ {
+ for (Blame usedBlame : usedBlames.m_blames)
+ {
+ if (session.checkMultiple(usedBlames, usedBlame, allCandidates))
+ {
+ // Continue to the next usedBlame, if possible we
+ // removed the conflicting candidates.
+ continue;
+ }
+
+ if (rethrow == null)
+ {
+ if (requirementBlame == null)
+ {
+ rethrow = new UseConstraintError(session.getContext(), allCandidates,
+ resource, pkgName, usedBlame);
+ }
+ else
+ {
+ rethrow = new UseConstraintError(session.getContext(), allCandidates,
+ resource, pkgName, requirementBlame, usedBlame);
+ }
+ }
+
+ // Create a candidate permutation that eliminates all candidates
+ // that conflict with existing selected candidates going from direct requirement -> root
+ Candidates perm1 = permRef1.get();
+ if (perm1 == null)
+ {
+ perm1 = allCandidates.copy();
+ permRef1.set(perm1);
+ }
+ for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--)
+ {
+ Requirement req = usedBlame.m_reqs.get(reqIdx);
+ if (permuteUsedBlameRequirement(req, mutated, perm1))
+ {
+ break;
+ }
+ }
+ // Create a candidate permutation that eliminates all candidates
+ // that conflict with existing selected candidates going from root -> direct requirement
+ Candidates perm2 = permRef2.get();
+ if (perm2 == null)
+ {
+ perm2 = allCandidates.copy();
+ permRef2.set(perm2);
+ }
+ for (int reqIdx = 0; reqIdx < usedBlame.m_reqs.size(); reqIdx++)
+ {
+ Requirement req = usedBlame.m_reqs.get(reqIdx);
+ if (permuteUsedBlameRequirement(req, mutated, perm2))
+ {
+ break;
+ }
+ }
+ }
+ return rethrow;
+ }
+ private boolean permuteUsedBlameRequirement(Requirement req, Set<Requirement> mutated, Candidates permutation)
+ {
+ // Sanity check for multiple.
+ if (Util.isMultiple(req))
+ {
+ return false;
+ }
+ // If we've already permutated this requirement in another
+ // uses constraint, don't permutate it again just continue
+ // with the next uses constraint.
+ if (mutated.contains(req))
+ {
+ return true;
+ }
+
+ // See if we can permutate the candidates for blamed
+ // requirement; there may be no candidates if the resource
+ // associated with the requirement is already resolved.
+ if (permutation.canRemoveCandidate(req))
+ {
+ permutation.removeFirstCandidate(req);
+ mutated.add(req);
+ return true;
+ }
+ return false;
+ }
+
private static OpenHashMap<String, Blame> calculateExportedPackages(
ResolveSession session,
Candidates allCandidates,
Modified: felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/ResolveContext.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/ResolveContext.java?rev=1825128&r1=1825127&r2=1825128&view=diff
==============================================================================
--- felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/ResolveContext.java (original)
+++ felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/ResolveContext.java Fri Feb 23 13:52:46 2018
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2011, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2011, 2017). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,7 +66,7 @@ import org.osgi.resource.Wiring;
* capabilities, wires and effective requirements.
*
* @ThreadSafe
- * @author $Id: 887cb785c112f51b400164044b822c291d081bdb $
+ * @author $Id: 5a3d32eb947b703bcca36f00d1ba6a86ae4a8e4b $
*/
@ConsumerType
public abstract class ResolveContext {
Modified: felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/Resolver.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/Resolver.java?rev=1825128&r1=1825127&r2=1825128&view=diff
==============================================================================
--- felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/Resolver.java (original)
+++ felix/trunk/osgi-r7/resolver/src/main/java/org/osgi/service/resolver/Resolver.java Fri Feb 23 13:52:46 2018
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2006, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2006, 2017). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ import org.osgi.resource.Wiring;
* by the caller.
*
* @ThreadSafe
- * @author $Id: 555f3cd1543e7a2c3492a71d74dcf728668265b6 $
+ * @author $Id: 86bff007315e1e3c03eca6aaacdcfa379be9ddea $
*/
@ProviderType
public interface Resolver {
@@ -77,13 +77,15 @@ public interface Resolver {
Map<Resource, List<Wire>> resolve(ResolveContext context) throws ResolutionException;
/**
- * Resolves a given dynamic requirement dynamically for the given host
- * wiring using the given resolve context and return any new resources and
- * wires to the caller.
+ * Resolves a given requirement dynamically for the given host wiring using
+ * the given resolve context and return any new resources and wires to the
+ * caller.
* <p>
* The requirement must be a {@link Wiring#getResourceRequirements(String)
* requirement} of the wiring and must use the
- * {@link PackageNamespace#PACKAGE_NAMESPACE package} namespace.
+ * {@link PackageNamespace#PACKAGE_NAMESPACE package} namespace with a
+ * {@link Namespace#REQUIREMENT_RESOLUTION_DIRECTIVE resolution} of type
+ * {@link PackageNamespace#RESOLUTION_DYNAMIC dynamic}.
* <p>
* The resolve context is not asked for
* {@link ResolveContext#getMandatoryResources() mandatory} resources or for
Modified: felix/trunk/osgi-r7/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/osgi-r7/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java?rev=1825128&r1=1825127&r2=1825128&view=diff
==============================================================================
--- felix/trunk/osgi-r7/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java (original)
+++ felix/trunk/osgi-r7/resolver/src/test/java/org/apache/felix/resolver/test/ResolverTest.java Fri Feb 23 13:52:46 2018
@@ -905,6 +905,14 @@ public class ResolverTest
resolver.resolve(rci);
}
+ @Test
+ public void testScenario18() throws Exception
+ {
+ ResolveContext rci = populateScenario18();
+ ResolverImpl resolver = new ResolverImpl(new Logger(Logger.LOG_DEBUG), 1);
+ resolver.resolve(rci);
+ }
+
private ResolveContext populateScenario17(boolean realSubstitute,
boolean felixResolveContext, boolean existingWirings)
{
@@ -999,6 +1007,91 @@ public class ResolverTest
}
}
+ private ResolveContext populateScenario18()
+ {
+ Map<Requirement, List<Capability>> candMap = new HashMap<Requirement, List<Capability>>();
+
+ ResourceImpl core1 = new ResourceImpl("core1");
+ Capability core1_pkgCap1 = addCap(core1, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg1");
+ Capability core1_pkgCap2 = addCap(core1, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg2", "corepkg1");
+ Capability core1_pkgCap3 = addCap(core1, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg3", "corepkg2");
+
+ ResourceImpl core2 = new ResourceImpl("core2");
+ Capability core2_pkgCap1 = addCap(core2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg1");
+ Capability core2_pkgCap2 = addCap(core2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg2", "corepkg1");
+ Capability core2_pkgCap3 = addCap(core2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg3", "corepkg2");
+ Requirement core2_pkgReq1 = addReq(core2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg1");
+ Requirement core2_pkgReq2 = addReq(core2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg2");
+ Requirement core2_pkgReq3 = addReq(core2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg3");
+
+ ResourceImpl core3 = new ResourceImpl("core3");
+ Capability core3_pkgCap1 = addCap(core3, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg1");
+ Capability core3_pkgCap2 = addCap(core3, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg2", "corepkg1");
+ Capability core3_pkgCap3 = addCap(core3, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg3", "corepkg2");
+ Requirement core3_pkgReq1 = addReq(core3, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg1");
+ Requirement core3_pkgReq2 = addReq(core3, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg2");
+ Requirement core3_pkgReq3 = addReq(core3, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg3");
+
+ ResourceImpl client1 = new ResourceImpl("client1");
+ Capability client1_pkgCap = addCap(client1, PackageNamespace.PACKAGE_NAMESPACE,
+ "clientpkg1", "corepkg3");
+ Requirement client1_pkgReq1 = addReq(client1, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg3");
+
+ ResourceImpl client2 = new ResourceImpl("client2");
+ Capability client2_pkgCap = addCap(client2, PackageNamespace.PACKAGE_NAMESPACE,
+ "clientpkg1", "corepkg3");
+ Requirement client2_pkgReq1 = addReq(client2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg3");
+
+ ResourceImpl bundle1 = new ResourceImpl("bundle1");
+ Requirement bundle1_pkgReq1 = addReq(bundle1, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg1");
+ Requirement bundle1_pkgReq2 = addReq(bundle1, PackageNamespace.PACKAGE_NAMESPACE,
+ "clientpkg1");
+
+ ResourceImpl bundle2 = new ResourceImpl("bundle2");
+ Requirement bundle2_pkgReq1 = addReq(bundle2, PackageNamespace.PACKAGE_NAMESPACE,
+ "corepkg1");
+
+ candMap.put(core2_pkgReq1, Arrays.asList(core3_pkgCap1, core2_pkgCap1));
+ candMap.put(core2_pkgReq2, Arrays.asList(core3_pkgCap2, core2_pkgCap2));
+ candMap.put(core2_pkgReq3, Arrays.asList(core3_pkgCap3, core2_pkgCap3));
+
+ candMap.put(core3_pkgReq1, Arrays.asList(core3_pkgCap1, core2_pkgCap1));
+ candMap.put(core3_pkgReq2, Arrays.asList(core3_pkgCap2, core2_pkgCap2));
+ candMap.put(core3_pkgReq3, Arrays.asList(core3_pkgCap3, core2_pkgCap3));
+
+ candMap.put(client1_pkgReq1,
+ Arrays.asList(core3_pkgCap3, core2_pkgCap3, core1_pkgCap3));
+ candMap.put(client2_pkgReq1, Arrays.asList(core3_pkgCap3));
+
+ candMap.put(bundle1_pkgReq1, Arrays.asList(core1_pkgCap1));
+ candMap.put(bundle1_pkgReq2, Arrays.asList(client1_pkgCap));
+
+ candMap.put(bundle2_pkgReq1, Arrays.asList(core3_pkgCap1));
+
+ Collection<Resource> mandatory = Arrays.<Resource> asList(core1, core2, core3,
+ client1, client2, bundle1, bundle2);
+ return new ResolveContextImpl(Collections.<Resource, Wiring> emptyMap(), candMap,
+ mandatory, Collections.<Resource> emptyList());
+ }
+
private static String getResourceName(Resource r)
{
return r.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE).get(0).getAttributes()