Apply patch FELIX-4182 to address some package space consistency bugs.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1589731 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java b/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
index 0f2caa0..82d1d4d 100644
--- a/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
+++ b/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java
@@ -131,7 +131,6 @@
do
{
retry = false;
-
try
{
// Create object to hold all candidates.
@@ -215,6 +214,7 @@
}
}
+ Collection<Resource> faultyResources = null;
do
{
rethrow = null;
@@ -230,6 +230,7 @@
? usesPermutations.remove(0)
: importPermutations.remove(0);
//allCandidates.dump();
+ Collection<Resource> currentFaultyResources = null;
// Reuse a resultCache map for checking package consistency
// for all resources.
Map<Resource, Object> resultCache =
@@ -264,8 +265,20 @@
catch (ResolutionException ex)
{
rethrow = ex;
+ if (currentFaultyResources == null) {
+ currentFaultyResources = new ArrayList();
+ }
+ currentFaultyResources.add(resource);
}
}
+ if (currentFaultyResources != null) {
+ if (faultyResources == null) {
+ faultyResources = currentFaultyResources;
+ } else if (faultyResources.size() > currentFaultyResources.size()) {
+ // save the optimal faultyResources which has less
+ faultyResources = currentFaultyResources;
+ }
+ }
}
while ((rethrow != null)
&& ((usesPermutations.size() > 0) || (importPermutations.size() > 0)));
@@ -276,31 +289,10 @@
// again; otherwise, rethrow the resolve exception.
if (rethrow != null)
{
- Collection<Requirement> exReqs = rethrow.getUnresolvedRequirements();
- Requirement faultyReq = ((exReqs == null) || (exReqs.isEmpty()))
- ? null : exReqs.iterator().next();
- Resource faultyResource = (faultyReq == null)
- ? null : getDeclaredResource(faultyReq.getResource());
- // If the faulty requirement is wrapped, then it may
- // be from a fragment, so consider the fragment faulty
- // instead of the host.
- if (faultyReq instanceof WrappedRequirement)
- {
- faultyResource =
- ((WrappedRequirement) faultyReq)
- .getDeclaredRequirement().getResource();
+ if (faultyResources != null) {
+ retry = (optionalResources.removeAll(faultyResources) || ondemandFragments.removeAll(faultyResources));
}
- // Try to ignore the faulty resource if it is not mandatory.
- if (optionalResources.remove(faultyResource))
- {
- retry = true;
- }
- else if (ondemandFragments.remove(faultyResource))
- {
- retry = true;
- }
- else
- {
+ if (!retry) {
throw rethrow;
}
}
@@ -1170,7 +1162,7 @@
}
for (UsedBlames usedBlames : pkgs.m_usedPkgs.get(pkgName))
{
- if (!isCompatible(session, exportBlame.m_cap, usedBlames.m_cap, resourcePkgMap))
+ if (!isCompatible(session, Collections.singletonList(exportBlame), usedBlames.m_cap, resourcePkgMap))
{
for (Blame usedBlame : usedBlames.m_blames)
{
@@ -1261,85 +1253,86 @@
new HashMap<String, List<Blame>>(pkgs.m_requiredPkgs);
allImportRequirePkgs.putAll(pkgs.m_importedPkgs);
- for (Entry<String, List<Blame>> pkgEntry : allImportRequirePkgs.entrySet())
+ for (Entry<String, List<Blame>> requirementBlames : allImportRequirePkgs.entrySet())
{
- String pkgName = pkgEntry.getKey();
- for (Blame requirementBlame : pkgEntry.getValue())
+ String pkgName = requirementBlames.getKey();
+ if (!pkgs.m_usedPkgs.containsKey(pkgName))
{
- if (!pkgs.m_usedPkgs.containsKey(pkgName))
+ continue;
+ }
+
+ for (UsedBlames usedBlames : pkgs.m_usedPkgs.get(pkgName))
+ {
+ if (!isCompatible(session, requirementBlames.getValue(), usedBlames.m_cap, resourcePkgMap))
{
- continue;
- }
- for (UsedBlames usedBlames : pkgs.m_usedPkgs.get(pkgName))
- {
- if (!isCompatible(session, requirementBlame.m_cap, usedBlames.m_cap, resourcePkgMap))
+ // 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.getValue().get(0);
+ for (Blame usedBlame : usedBlames.m_blames)
{
- for (Blame usedBlame : usedBlames.m_blames)
+ if (checkMultiple(session, usedBlames, usedBlame, allCandidates))
{
- if (checkMultiple(session, 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();
+ rethrow = (rethrow != null)
+ ? rethrow
+ : new ResolutionException(
+ "Uses constraint violation. Unable to resolve resource "
+ + Util.getSymbolicName(resource)
+ + " [" + resource
+ + "] because it is exposed to package '"
+ + pkgName
+ + "' from resources "
+ + Util.getSymbolicName(requirementBlame.m_cap.getResource())
+ + " [" + requirementBlame.m_cap.getResource()
+ + "] and "
+ + Util.getSymbolicName(usedBlame.m_cap.getResource())
+ + " [" + usedBlame.m_cap.getResource()
+ + "] via two dependency chains.\n\nChain 1:\n"
+ + toStringBlame(session.getContext(), allCandidates, requirementBlame)
+ + "\n\nChain 2:\n"
+ + toStringBlame(session.getContext(), allCandidates, usedBlame),
+ null,
+ 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 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();
- rethrow = (rethrow != null)
- ? rethrow
- : new ResolutionException(
- "Uses constraint violation. Unable to resolve resource "
- + Util.getSymbolicName(resource)
- + " [" + resource
- + "] because it is exposed to package '"
- + pkgName
- + "' from resources "
- + Util.getSymbolicName(requirementBlame.m_cap.getResource())
- + " [" + requirementBlame.m_cap.getResource()
- + "] and "
- + Util.getSymbolicName(usedBlame.m_cap.getResource())
- + " [" + usedBlame.m_cap.getResource()
- + "] via two dependency chains.\n\nChain 1:\n"
- + toStringBlame(session.getContext(), allCandidates, requirementBlame)
- + "\n\nChain 2:\n"
- + toStringBlame(session.getContext(), allCandidates, usedBlame),
- null,
- null);
-
- mutated = (mutated != null)
- ? mutated
- : new HashSet<Requirement>();
-
- for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--)
+ // 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))
{
- 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;
- }
+ 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.
- List<Capability> candidates = permutation.getCandidates(req);
- if ((candidates != null) && (candidates.size() > 1))
- {
- mutated.add(req);
- // Remove the conflicting candidate.
- candidates.remove(0);
- // Continue with the next uses constraint.
- 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.
+ List<Capability> candidates = permutation.getCandidates(req);
+ if ((candidates != null) && (candidates.size() > 1))
+ {
+ mutated.add(req);
+ // Remove the conflicting candidate.
+ candidates.remove(0);
+ // Continue with the next uses constraint.
+ break;
}
}
}
@@ -1362,15 +1355,18 @@
// Try to permutate the candidate for the original
// import requirement; only permutate it if we haven't
// done so already.
- Requirement req = requirementBlame.m_reqs.get(0);
- if (!mutated.contains(req))
- {
- // Since there may be lots of uses constraint violations
- // with existing import decisions, we may end up trying
- // to permutate the same import a lot of times, so we should
- // try to check if that the case and only permutate it once.
- permutateIfNeeded(allCandidates, req, importPermutations);
- }
+ for (Blame requirementBlame : requirementBlames.getValue()) {
+ Requirement req = requirementBlame.m_reqs.get(0);
+ if (!mutated.contains(req))
+ {
+ // Since there may be lots of uses constraint violations
+ // with existing import decisions, we may end up trying
+ // to permutate the same import a lot of times, so we should
+ // try to check if that the case and only permutate it once.
+ permutateIfNeeded(allCandidates, req, importPermutations);
+ }
+ }
+
m_logger.log(
Logger.LOG_DEBUG,
@@ -1562,21 +1558,40 @@
}
private boolean isCompatible(
- ResolveSession session, Capability currentCap, Capability candCap,
+ ResolveSession session, List<Blame> currentBlames, Capability candCap,
Map<Resource, Packages> resourcePkgMap)
{
- if ((currentCap != null) && (candCap != null))
+ if ((!currentBlames.isEmpty()) && (candCap != null))
{
- if (currentCap.equals(candCap))
+ List<Capability> currentSources;
+ // quick check for single source package
+ if (currentBlames.size() == 1)
{
- return true;
+ Capability currentCap = currentBlames.get(0).m_cap;
+ if (currentCap.equals(candCap)) {
+ return true;
+ }
+ currentSources =
+ getPackageSources(
+ session,
+ currentCap,
+ resourcePkgMap);
+ } else {
+ currentSources = new ArrayList<Capability>(currentBlames.size());
+ for (Blame currentBlame : currentBlames) {
+ List<Capability> blameSources =
+ getPackageSources(
+ session,
+ currentBlame.m_cap,
+ resourcePkgMap);
+ for (Capability blameSource : blameSources) {
+ if (!currentSources.contains(blameSource)) {
+ currentSources.add(blameSource);
+ }
+ }
+ }
}
- List<Capability> currentSources =
- getPackageSources(
- session,
- currentCap,
- resourcePkgMap);
List<Capability> candSources =
getPackageSources(
session,
@@ -1649,10 +1664,9 @@
// for that case and wrap them.
if (!cap.getResource().equals(sourceCap.getResource()))
{
- sources.add(new WrappedCapability(cap.getResource(), sourceCap));
+ sourceCap = new WrappedCapability(cap.getResource(), sourceCap);
}
- else
- {
+ if (!sources.contains(sourceCap)) {
sources.add(sourceCap);
}
}