Modify the resolver algorithm to try to avoid creating duplicate permutations
for conflicts involving an imported package. (FELIX-2528)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@983039 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
index 4daecd9..3db5df4 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
@@ -28,7 +28,6 @@
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
-import org.apache.felix.framework.FelixResolverState;
import org.apache.felix.framework.Logger;
import org.apache.felix.framework.capabilityset.Attribute;
import org.apache.felix.framework.capabilityset.Capability;
@@ -58,8 +57,6 @@
public ResolverImpl(Logger logger)
{
m_logger = logger;
-
- String v = System.getProperty("invoke.count");
}
public Map<Module, List<Wire>> resolve(ResolverState state, Module module)
@@ -872,7 +869,7 @@
Packages pkgs = modulePkgMap.get(module);
ResolveException rethrow = null;
- Map<Requirement, Set<Capability>> copyConflict = null;
+ Map<Requirement, Set<Capability>> permutation = null;
Set<Requirement> mutated = null;
Set<Module> checkModules = new HashSet();
@@ -892,31 +889,10 @@
else if (!sourceBlame.m_cap.equals(blame.m_cap))
{
// Try to permutate the conflicting requirement.
- Requirement req = blame.m_reqs.get(0);
- Set<Capability> candidates = candidateMap.get(req);
- if (candidates.size() > 1)
- {
- Map<Requirement, Set<Capability>> importPerm =
- copyCandidateMap(candidateMap);
- candidates = importPerm.get(req);
- Iterator it = candidates.iterator();
- it.next();
- it.remove();
- m_importPermutations.add(importPerm);
- }
+ permutate(candidateMap, blame.m_reqs.get(0), m_importPermutations);
// Try to permutate the source requirement.
- req = sourceBlame.m_reqs.get(0);
- candidates = candidateMap.get(req);
- if (candidates.size() > 1)
- {
- Map<Requirement, Set<Capability>> importPerm =
- copyCandidateMap(candidateMap);
- candidates = importPerm.get(req);
- Iterator it = candidates.iterator();
- it.next();
- it.remove();
- m_importPermutations.add(importPerm);
- }
+ permutate(candidateMap, sourceBlame.m_reqs.get(0), m_importPermutations);
+ // Report conflict.
ResolveException ex = new ResolveException(
"Constraint violation for package '"
+ entry.getKey() + "' when resolving module "
@@ -942,10 +918,10 @@
{
if (!isCompatible(exportBlame.m_cap, usedBlame.m_cap, modulePkgMap))
{
- // Create a candidate permutation that eliminates any candidates
+ // Create a candidate permutation that eliminates all candidates
// that conflict with existing selected candidates.
- copyConflict = (copyConflict != null)
- ? copyConflict
+ permutation = (permutation != null)
+ ? permutation
: copyCandidateMap(candidateMap);
rethrow = (rethrow != null)
? rethrow
@@ -975,7 +951,7 @@
// See if we can permutate the candidates for blamed
// requirement; there may be no candidates if the module
// associated with the requirement is already resolved.
- Set<Capability> candidates = copyConflict.get(req);
+ Set<Capability> candidates = permutation.get(req);
if ((candidates != null) && (candidates.size() > 1))
{
mutated.add(req);
@@ -993,7 +969,7 @@
{
if (mutated.size() > 0)
{
- m_usesPermutations.add(copyConflict);
+ m_usesPermutations.add(permutation);
}
m_logger.log(Logger.LOG_DEBUG, "Conflict between an export and import", rethrow);
throw rethrow;
@@ -1021,8 +997,8 @@
{
// Create a candidate permutation that eliminates any candidates
// that conflict with existing selected candidates.
- copyConflict = (copyConflict != null)
- ? copyConflict
+ permutation = (permutation != null)
+ ? permutation
: copyCandidateMap(candidateMap);
rethrow = (rethrow != null)
? rethrow
@@ -1052,7 +1028,7 @@
// See if we can permutate the candidates for blamed
// requirement; there may be no candidates if the module
// associated with the requirement is already resolved.
- Set<Capability> candidates = copyConflict.get(req);
+ Set<Capability> candidates = permutation.get(req);
if ((candidates != null) && (candidates.size() > 1))
{
mutated.add(req);
@@ -1066,33 +1042,54 @@
}
}
+ // If there was a uses confliect, then we should add a uses
+ // permutation if we were able to permutate any candidates.
+ // Additionally, we should try to push an import permutation
+ // for the original import to force a backtracking on the
+ // original candidate decision if no viable candidate is found
+ // for the conflicting uses constraint.
if (rethrow != null)
{
- // If we couldn't permutate the uses constraints,
- // then try to permutate the import.
-// TODO: FELIX3 - Maybe we will push too many permutations this way, since
-// we will push one on each level as we move down.
+ // Add uses permutation if we mutated any candidates.
+ if (mutated.size() > 0)
+ {
+ m_usesPermutations.add(permutation);
+ }
+
+ // Try to permutate the candidate for the original
+ // import requirement; only permutate it if we haven't
+ // done so already.
Requirement req = importBlame.m_reqs.get(0);
if (!mutated.contains(req))
{
Set<Capability> candidates = candidateMap.get(req);
if (candidates.size() > 1)
{
- Map<Requirement, Set<Capability>> importPerm =
- copyCandidateMap(candidateMap);
- candidates = importPerm.get(req);
- Iterator it = candidates.iterator();
- it.next();
- it.remove();
- m_importPermutations.add(importPerm);
+ // Check existing import permutations to make sure
+ // we haven't already permutated this requirement.
+ // This check for duplicate permutations is simplistic.
+ // It assumes if there is any permutation that contains
+ // a different candidate for the requirement in question,
+ // then it has already been permutated.
+ boolean permutated = false;
+ for (Map<Requirement, Set<Capability>> existingPerm
+ : m_importPermutations)
+ {
+ Set<Capability> existingPermCands = existingPerm.get(req);
+ if (!existingPermCands.iterator().next().equals(candidates.iterator().next()))
+ {
+ permutated = true;
+ }
+ }
+ // If we haven't already permutated the existing
+ // import, do so now.
+ if (!permutated)
+ {
+ permutate(candidateMap, req, m_importPermutations);
+ }
}
}
- if (mutated.size() > 0)
- {
- m_usesPermutations.add(copyConflict);
- }
-
m_logger.log(Logger.LOG_DEBUG, "Conflict between imports", rethrow);
throw rethrow;
}
@@ -1109,6 +1106,22 @@
}
}
+ private static void permutate(
+ Map<Requirement, Set<Capability>> candidateMap, Requirement req,
+ List<Map<Requirement, Set<Capability>>> permutations)
+ {
+ Set<Capability> candidates = candidateMap.get(req);
+ if (candidates.size() > 1)
+ {
+ Map<Requirement, Set<Capability>> perm = copyCandidateMap(candidateMap);
+ candidates = perm.get(req);
+ Iterator it = candidates.iterator();
+ it.next();
+ it.remove();
+ permutations.add(perm);
+ }
+ }
+
private static void calculateExportedPackages(
Module module, Map<Module, Packages> modulePkgMap)
{