You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2010/04/23 20:49:25 UTC
svn commit: r937463 [3/3] - in
/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver:
./ cs/ manifestparser/ proto3/
Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/RequirementImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/RequirementImpl.java?rev=937463&r1=937462&r2=937463&view=diff
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/RequirementImpl.java (original)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/RequirementImpl.java Fri Apr 23 18:49:24 2010
@@ -29,6 +29,7 @@ import org.apache.felix.resolver.manifes
public class RequirementImpl implements Requirement
{
+ private final Module m_module;
private final String m_namespace;
private SimpleFilter m_filter;
private boolean m_optional;
@@ -38,8 +39,9 @@ public class RequirementImpl implements
private final List<Attribute> m_attrsConst;
// TODO: FELIX3 - Get rid of dynamic argument.
- public RequirementImpl(String namespace)
+ public RequirementImpl(Module module, String namespace)
{
+ m_module = module;
m_namespace = namespace;
m_dirs = new ArrayList();
m_dirsConst = Collections.unmodifiableList(m_dirs);
@@ -51,8 +53,9 @@ public class RequirementImpl implements
}
public RequirementImpl(
- String namespace, List<Directive> dirs, List<Attribute> attrs)
+ Module module, String namespace, List<Directive> dirs, List<Attribute> attrs)
{
+ m_module = module;
m_namespace = namespace;
m_dirs = dirs;
m_dirsConst = Collections.unmodifiableList(m_dirs);
@@ -72,6 +75,11 @@ public class RequirementImpl implements
m_optional = optional;
}
+ public Module getModule()
+ {
+ return m_module;
+ }
+
public String getNamespace()
{
return m_namespace;
@@ -106,7 +114,7 @@ public class RequirementImpl implements
public String toString()
{
- return m_namespace + "; " + getFilter().toString();
+ return "[" + m_module + "] " + m_namespace + "; " + getFilter().toString();
}
public RequirementImpl optional()
Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/StatefulResolver.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/StatefulResolver.java?rev=937463&r1=937462&r2=937463&view=diff
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/StatefulResolver.java (original)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/StatefulResolver.java Fri Apr 23 18:49:24 2010
@@ -38,7 +38,7 @@ public class StatefulResolver
return m_state;
}
- public void resolve(Module module)
+ public Map<Module, List<Wire>> resolve(Module module)
{
System.out.println("Target: " + module + " (" + module.getRequirements().size() + ")");
long starttime = System.currentTimeMillis();
@@ -49,6 +49,8 @@ public class StatefulResolver
// Mark all modules as resolved.
markResolvedModules(wireMap);
+
+ return wireMap;
}
private void markResolvedModules(Map<Module, List<Wire>> wireMap)
Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/Requirement.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/Requirement.java?rev=937463&r1=937462&r2=937463&view=diff
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/Requirement.java (original)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/cs/Requirement.java Fri Apr 23 18:49:24 2010
@@ -19,9 +19,11 @@
package org.apache.felix.resolver.cs;
import java.util.List;
+import org.apache.felix.resolver.Module;
public interface Requirement
{
+ Module getModule();
String getNamespace();
SimpleFilter getFilter();
boolean isOptional();
Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/Main.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/Main.java?rev=937463&r1=937462&r2=937463&view=diff
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/Main.java (original)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/Main.java Fri Apr 23 18:49:24 2010
@@ -697,7 +697,7 @@ public class Main
private static RequirementImpl convertToRequirement(Module module, FelixRequirement req)
{
- RequirementImpl ri = new RequirementImpl(req.getNamespace());
+ RequirementImpl ri = new RequirementImpl(module, req.getNamespace());
R4Directive[] dirs = req.getDirectives();
for (int dirIdx = 0; (dirs != null) && (dirIdx < dirs.length); dirIdx++)
Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/ManifestParser.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/ManifestParser.java?rev=937463&r1=937462&r2=937463&view=diff
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/ManifestParser.java (original)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/ManifestParser.java Fri Apr 23 18:49:24 2010
@@ -669,7 +669,7 @@ public class ManifestParser
return caps;
}
- private static FelixCapability[] parseExportHeader(String header)
+ public static FelixCapability[] parseExportHeader(String header)
{
Object[][][] clauses = parseStandardHeader(header);
@@ -765,7 +765,7 @@ public class ManifestParser
return (FelixCapability[]) capList.toArray(new FelixCapability[capList.size()]);
}
- private static FelixRequirement[] parseImportHeader(String header)
+ public static FelixRequirement[] parseImportHeader(String header)
{
Object[][][] clauses = parseStandardHeader(header);
Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/Proto3Resolver.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/Proto3Resolver.java?rev=937463&r1=937462&r2=937463&view=diff
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/Proto3Resolver.java (original)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/Proto3Resolver.java Fri Apr 23 18:49:24 2010
@@ -35,6 +35,7 @@ import org.apache.felix.resolver.Resolve
import org.apache.felix.resolver.Resolver;
import org.apache.felix.resolver.Resolver.ResolverState;
import org.apache.felix.resolver.ResolverStateImpl;
+import org.apache.felix.resolver.StatefulResolver;
import org.apache.felix.resolver.Wire;
import org.apache.felix.resolver.WireImpl;
import org.apache.felix.resolver.WireModuleImpl;
@@ -54,7 +55,16 @@ public class Proto3Resolver implements R
private static boolean m_isInvokeCount = false;
// Reusable empty array.
- private static final List<Wire> m_emptyWires = new ArrayList<Wire>(0);
+ private static final List<Wire> m_emptyWires = Collections.emptyList();
+
+ // Holds candidate permutations based on permutating "uses" chains.
+ // These permutations are given higher priority.
+ private final List<Map<Requirement, Set<Capability>>> m_usesPermutations =
+ new ArrayList<Map<Requirement, Set<Capability>>>();
+ // Holds candidate permutations based on permutating requirement candidates.
+ // These permutations represent backtracking on previous decisions.
+ private final List<Map<Requirement, Set<Capability>>> m_importPermutations =
+ new ArrayList<Map<Requirement, Set<Capability>>>();
public Proto3Resolver()
{
@@ -63,9 +73,6 @@ System.out.println("+++ PROTO3 RESOLVER"
m_isInvokeCount = (v == null) ? false : Boolean.valueOf(v);
}
- private final List<Map<Requirement, Set<Capability>>> m_candidatePermutations =
- new ArrayList<Map<Requirement, Set<Capability>>>();
-
public Map<Module, List<Wire>> resolve(ResolverState state, Module module)
{
m_invokeCounts.clear();
@@ -84,32 +91,44 @@ System.out.println("+++ PROTO3 RESOLVER"
if (!module.isResolved())
{
- m_candidatePermutations.clear();
+// TODO: FELIX3 - Should we clear these in a finally block?
+ m_usesPermutations.clear();
+ m_importPermutations.clear();
-System.out.println("+++ RESOLVING " + module);
Map<Requirement, Set<Capability>> candidateMap =
new HashMap<Requirement, Set<Capability>>();
populateCandidates(state, module, candidateMap, new HashMap<Module, Object>());
- m_candidatePermutations.add(candidateMap);
+ m_usesPermutations.add(candidateMap);
ResolveException rethrow = null;
+ Map<Capability, Set<Requirement>> capDepSet = new HashMap();
+
do
{
rethrow = null;
- candidateMap = m_candidatePermutations.remove(0);
+ modulePkgMap.clear();
+ capDepSet.clear();
+ m_packageSourcesCache.clear();
+
+ candidateMap = (m_usesPermutations.size() > 0)
+ ? m_usesPermutations.remove(0)
+ : m_importPermutations.remove(0);
dumpCandidateMap(state, candidateMap);
+ calculatePackageSpaces(
+ module, candidateMap, modulePkgMap,
+ capDepSet, new HashMap(), new HashSet());
+System.out.println("+++ PACKAGE SPACES START +++");
+dumpModulePkgMap(modulePkgMap);
+System.out.println("+++ PACKAGE SPACES END +++");
+
try
{
- findConsistentCandidates(
- module,
- new ArrayList(),
- candidateMap,
- modulePkgMap,
- new HashMap<Module, Object>());
+ checkPackageSpaceConsistency(
+ module, candidateMap, modulePkgMap, capDepSet, new HashMap());
}
catch (ResolveException ex)
{
@@ -117,13 +136,13 @@ dumpCandidateMap(state, candidateMap);
System.out.println("RE: " + ex);
}
}
- while ((rethrow != null) && (m_candidatePermutations.size() > 0));
+ while ((rethrow != null)
+ && ((m_usesPermutations.size() > 0) || (m_importPermutations.size() > 0)));
if (rethrow != null)
{
throw rethrow;
}
-//dumpModulePkgMap(modulePkgMap);
wireMap =
populateWireMap(module, modulePkgMap, wireMap,
@@ -148,8 +167,6 @@ dumpCandidateMap(state, candidateMap);
m_invokeCounts.put(methodName, count);
}
- Capability candidate = null;
-
// We can only create a dynamic import if the following
// conditions are met:
// 1. The specified module is resolved.
@@ -163,31 +180,39 @@ dumpCandidateMap(state, candidateMap);
getDynamicImportCandidates(state, module, pkgName);
if (candidateMap != null)
{
- m_candidatePermutations.clear();
+// TODO: FELIX3 - Should we clear these in a finally block?
+ m_usesPermutations.clear();
+ m_importPermutations.clear();
Map<Module, List<Wire>> wireMap = new HashMap();
Map<Module, Packages> modulePkgMap = new HashMap();
-//System.out.println("+++ DYNAMICALLY RESOLVING " + module + " - " + pkgName);
populateDynamicCandidates(state, module, candidateMap);
- m_candidatePermutations.add(candidateMap);
+ m_usesPermutations.add(candidateMap);
ResolveException rethrow = null;
+ Map<Capability, Set<Requirement>> capDepSet = new HashMap();
+
do
{
rethrow = null;
- candidateMap = m_candidatePermutations.remove(0);
-//dumpCandidateMap(state, candidateMap);
+ modulePkgMap.clear();
+ capDepSet.clear();
+
+ candidateMap = (m_usesPermutations.size() > 0)
+ ? m_usesPermutations.remove(0)
+ : m_importPermutations.remove(0);
+
+ calculatePackageSpaces(
+ module, candidateMap, modulePkgMap,
+ capDepSet, new HashMap(), new HashSet());
try
{
- findConsistentDynamicCandidate(
- module,
- new ArrayList(),
- candidateMap,
- modulePkgMap);
+ checkPackageSpaceConsistency(
+ module, candidateMap, modulePkgMap, capDepSet, new HashMap());
}
catch (ResolveException ex)
{
@@ -195,26 +220,25 @@ dumpCandidateMap(state, candidateMap);
System.out.println("RE: " + ex);
}
}
- while ((rethrow != null) && (m_candidatePermutations.size() > 0));
+ while ((rethrow != null)
+ && ((m_usesPermutations.size() > 0) || (m_importPermutations.size() > 0)));
if (rethrow != null)
{
throw rethrow;
}
+
//dumpModulePkgMap(modulePkgMap);
- wireMap =
- populateDynamicWireMap(
- module, pkgName, modulePkgMap, wireMap, candidateMap);
+ wireMap = populateDynamicWireMap(
+ module, pkgName, modulePkgMap, wireMap, candidateMap);
-//System.out.println("+++ DYNAMIC SUCCESS: " + wireMap.get(module));
return wireMap;
}
-//System.out.println("+++ DYNAMIC FAILURE");
return null;
}
- // TODO: FELIX3 - It would be nice to make this private.
+// TODO: FELIX3 - It would be nice to make this private.
public static Map<Requirement, Set<Capability>> getDynamicImportCandidates(
ResolverState state, Module module, String pkgName)
{
@@ -262,7 +286,7 @@ dumpCandidateMap(state, candidateMap);
List<Attribute> attrs = new ArrayList(1);
attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
Requirement req = new RequirementImpl(
- Capability.PACKAGE_NAMESPACE, dirs, attrs);
+ module, Capability.PACKAGE_NAMESPACE, dirs, attrs);
Set<Capability> candidates = state.getCandidates(module, req, false);
List<Requirement> dynamics = module.getDynamicRequirements();
@@ -301,7 +325,6 @@ dumpCandidateMap(state, candidateMap);
candidates.clear();
}
-
if (candidates.size() > 0)
{
Map<Requirement, Set<Capability>> candidateMap = new HashMap();
@@ -312,68 +335,6 @@ dumpCandidateMap(state, candidateMap);
return null;
}
- private static void dumpCandidateMap(
- ResolverState state, Map<Requirement, Set<Capability>> candidateMap)
- {
- System.out.println("=== BEGIN CANDIDATE MAP ===");
- for (Module module : ((ResolverStateImpl) state).getModules())
- {
- System.out.println(" " + module
- + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
- for (Requirement req : module.getRequirements())
- {
- Set<Capability> candidates = candidateMap.get(req);
- if ((candidates != null) && (candidates.size() > 0))
- {
- System.out.println(" " + req + ": " + candidates);
- }
- }
- for (Requirement req : module.getDynamicRequirements())
- {
- Set<Capability> candidates = candidateMap.get(req);
- if ((candidates != null) && (candidates.size() > 0))
- {
- System.out.println(" " + req + ": " + candidates);
- }
- }
- }
- System.out.println("=== END CANDIDATE MAP ===");
- }
-
- private static void dumpModulePkgMap(Map<Module, Packages> modulePkgMap)
- {
- System.out.println("+++MODULE PKG MAP+++");
- for (Entry<Module, Packages> entry : modulePkgMap.entrySet())
- {
- dumpModulePkgs(entry.getKey(), entry.getValue());
- }
- }
-
- private static void dumpModulePkgs(Module module, Packages packages)
- {
- System.out.println(module + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
- System.out.println(" EXPORTED");
- for (Entry<String, Blame> entry : packages.m_exportedPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- System.out.println(" IMPORTED");
- for (Entry<String, Blame> entry : packages.m_importedPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- System.out.println(" REQUIRED");
- for (Entry<String, List<Blame>> entry : packages.m_requiredPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- System.out.println(" USED");
- for (Entry<String, List<Blame>> entry : packages.m_usedPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- }
-
// TODO: FELIX3 - Modify to not be recursive.
private static void populateCandidates(
ResolverState state, Module module,
@@ -577,22 +538,15 @@ System.out.println("RE: Candidate not re
candidateMap.remove(dynReq);
throw new ResolveException("Dynamic import failed.", module, dynReq);
}
-
- // Add existing wires as candidates.
- for (Wire wire : module.getWires())
- {
- Set<Capability> cs = new TreeSet();
- cs.add(wire.getCapability());
- candidateMap.put(wire.getRequirement(), cs);
- }
}
-// TODO: FELIX3 - Modify to not be recursive.
- private void findConsistentCandidates(
- Module module, List<Requirement> incomingReqs,
+ private void calculatePackageSpaces(
+ Module module,
Map<Requirement, Set<Capability>> candidateMap,
Map<Module, Packages> modulePkgMap,
- Map<Module, Object> resultCache)
+ Map<Capability, Set<Requirement>> capDepSet,
+ Map<Capability, List<Module>> usesCycleMap,
+ Set<Module> cycle)
{
if (m_isInvokeCount)
{
@@ -602,83 +556,50 @@ System.out.println("RE: Candidate not re
m_invokeCounts.put(methodName, count);
}
- // Determine if we've already checked candidate consistency for this
- // module. The result cache will have one of two values:
- // 1. Boolean.TRUE if candidate consistency has been checked.
- // 2. An array containing the cycle count and a list of wires for an
- // already resolved (and consistent) module or a list of remaining
- // requirments whose candidates still need to be checked for an
- // unresolved module.
- // For case 1, return immediately. For case 2, this means we are in a
- // cycle so we should just continue checking consistency where we left
- // off.
-
- Integer cycleCount = null;
-
- Object o = resultCache.get(module);
-
- if (o instanceof Boolean)
+ if (cycle.contains(module))
{
return;
}
- else if (o == null)
- {
- List list;
- if (module.isResolved())
- {
- list = new ArrayList(module.getWires());
- }
- else
- {
- list = new ArrayList(module.getRequirements());
- }
- resultCache.put(module, o = new Object[] { cycleCount = new Integer(0), list });
- calculateExportedPackages(module, incomingReqs, modulePkgMap);
- }
- else
- {
- // Increment and get the cycle count.
- cycleCount = (Integer)
- (((Object[]) o)[0]
- = new Integer(((Integer) ((Object[]) o)[0]).intValue() + 1));
- }
-
-//System.out.println("+++ RESOLVING " + module);
+ cycle.add(module);
+ // Create a map of wires or proposed wired depending on whether
+ // the module is resolved or not.
+ List<Requirement> reqs = new ArrayList();
+ List<Capability> caps = new ArrayList();
if (module.isResolved())
{
- List<Wire> wires = (List<Wire>) ((Object[]) o)[1];
-
- while (wires.size() > 0)
+ // Use wires to get actual requirements and satisfying capabilities.
+ for (Wire wire : module.getWires())
{
- Wire wire = wires.remove(0);
+ reqs.add(wire.getRequirement());
+ caps.add(wire.getCapability());
+ }
- // Try to resolve the candidate.
- findConsistentCandidates(
- wire.getCapability().getModule(),
- incomingReqs,
- candidateMap,
- modulePkgMap,
- resultCache);
+ // Since the module is resolved, it could be dynamically importing,
+ // so check to see if there are candidates for any of its dynamic
+ // imports.
+ for (Requirement req : module.getDynamicRequirements())
+ {
+ // Get the candidates for the current requirement.
+ Set<Capability> candCaps = candidateMap.get(req);
+ // Optional requirements may not have any candidates.
+ if (candCaps == null)
+ {
+ continue;
+ }
- // If we are here, the candidate was consistent. Try to
- // merge the candidate into the target module's packages.
- mergeCandidatePackages(
- module,
- incomingReqs,
- wire.getCapability(),
- modulePkgMap,
- candidateMap);
+ Capability cap = candCaps.iterator().next();
+ reqs.add(req);
+ caps.add(cap);
+ // Can only dynamically import one at a time, so break
+ // out of the loop after the first.
+ break;
}
}
else
{
- List<Requirement> reqs = (List<Requirement>) ((Object[]) o)[1];
-
- while (reqs.size() > 0)
+ for (Requirement req : module.getRequirements())
{
- Requirement req = reqs.remove(0);
-
// Get the candidates for the current requirement.
Set<Capability> candCaps = candidateMap.get(req);
// Optional requirements may not have any candidates.
@@ -687,199 +608,79 @@ System.out.println("RE: Candidate not re
continue;
}
- List<Requirement> outgoingReqs = new ArrayList<Requirement>(incomingReqs);
- outgoingReqs.add(req);
-
- for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
- {
- Capability candCap = it.next();
-System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
- try
- {
- // Try to resolve the candidate.
- findConsistentCandidates(
- candCap.getModule(),
- outgoingReqs,
- candidateMap,
- modulePkgMap,
- resultCache);
-
- // If we are here, the candidate was consistent. Try to
- // merge the candidate into the target module's packages.
- mergeCandidatePackages(
- module,
- outgoingReqs,
- candCap,
- modulePkgMap,
- candidateMap);
-
- // If we are here, we merged the candidate successfully,
- // so we can continue with the next requirement
- break;
- }
- catch (ResolveException ex)
- {
-System.out.println("RE: " + ex);
-ex.printStackTrace();
- // Remove the current candidate since it failed to resolve.
- it.remove();
- if (!it.hasNext() && !req.isOptional())
- {
- throw new ResolveException("Unresolved constraint "
- + req + " in " + module, module, req);
- }
- }
- }
+ Capability cap = candCaps.iterator().next();
+ reqs.add(req);
+ caps.add(cap);
}
}
- // If we are exiting from a cycle then decrement
- // cycle counter, otherwise record the result.
- if (cycleCount.intValue() > 0)
- {
- ((Object[]) o)[0] = new Integer(cycleCount.intValue() - 1);
- }
- else if (cycleCount.intValue() == 0)
+ // First, add all exported packages to our package space.
+ calculateExportedPackages(module, modulePkgMap);
+ Packages modulePkgs = modulePkgMap.get(module);
+
+ // Second, add all imported packages to our candidate space.
+ for (int i = 0; i < reqs.size(); i++)
{
- // Record that the module was successfully populated.
- resultCache.put(module, Boolean.TRUE);
+ Requirement req = reqs.get(i);
+ Capability cap = caps.get(i);
+ calculateExportedPackages(cap.getModule(), modulePkgMap);
+ mergeCandidatePackages(module, req, cap, modulePkgMap, candidateMap);
+ addCapabilityDependency(cap, req, capDepSet);
}
- }
- private void findConsistentDynamicCandidate(
- Module module, List<Requirement> incomingReqs,
- Map<Requirement, Set<Capability>> candidateMap,
- Map<Module, Packages> modulePkgMap)
- {
- if (m_isInvokeCount)
+ // Third, ask our candidates to calculate their package spaces.
+ for (int i = 0; i < caps.size(); i++)
{
- String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
- Long count = m_invokeCounts.get(methodName);
- count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
- m_invokeCounts.put(methodName, count);
+ calculatePackageSpaces(
+ caps.get(i).getModule(), candidateMap, modulePkgMap,
+ capDepSet, usesCycleMap, cycle);
}
-//System.out.println("+++ RESOLVING " + module);
- calculateExportedPackages(module, incomingReqs, modulePkgMap);
-
- List<Requirement> reqs = new ArrayList(module.getRequirements());
- reqs.addAll(module.getDynamicRequirements());
- for (Requirement req : reqs)
- {
- // Get the candidates for the current requirement.
- Set<Capability> candCaps = candidateMap.get(req);
- // Optional requirements may not have any candidates.
- if (candCaps == null)
- {
- continue;
- }
-
- List<Requirement> outgoingReqs = new ArrayList<Requirement>(incomingReqs);
- outgoingReqs.add(req);
-
- for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
+ // Fourth, add all of the uses constraints implied by our imported
+ // and required packages.
+ for (Entry<String, List<Blame>> entry : modulePkgs.m_importedPkgs.entrySet())
+ {
+ for (Blame blame : entry.getValue())
{
- Capability candCap = it.next();
-//System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
- try
+ // Ignore modules that import from themselves.
+ if (!blame.m_cap.getModule().equals(module))
{
- // Try to resolve the candidate.
- findConsistentCandidates(
- candCap.getModule(),
- outgoingReqs,
- candidateMap,
- modulePkgMap,
- new HashMap());
+ List<Requirement> blameReqs = new ArrayList();
+ blameReqs.add(blame.m_reqs.get(0));
- // If we are here, the candidate was consistent. Try to
- // merge the candidate into the target module's packages.
- mergeCandidatePackages(
+ mergeUses(
module,
- outgoingReqs,
- candCap,
+ modulePkgs,
+ blame.m_cap,
+ blameReqs,
modulePkgMap,
- candidateMap);
-
- // If we are here, we merged the candidate successfully,
- // so we can continue with the next requirement
- break;
- }
- catch (ResolveException ex)
- {
-System.out.println("RE: " + ex);
-ex.printStackTrace();
- // Remove the current candidate since it failed to resolve.
- it.remove();
- if (!it.hasNext() && !req.isOptional())
- {
- throw new ResolveException("Unresolved constraint "
- + req + " in " + module, module, req);
- }
+ candidateMap,
+ usesCycleMap);
}
}
}
- }
-
- private static void calculateExportedPackages(
- Module module, List<Requirement> incomingReqs, Map<Module, Packages> modulePkgMap)
- {
- if (m_isInvokeCount)
- {
- String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
- Long count = m_invokeCounts.get(methodName);
- count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
- m_invokeCounts.put(methodName, count);
- }
-
- Packages packages = new Packages();
-
- List<Capability> caps = module.getCapabilities();
-
- if (caps.size() > 0)
+ for (Entry<String, List<Blame>> entry : modulePkgs.m_requiredPkgs.entrySet())
{
- for (int i = 0; i < caps.size(); i++)
+ for (Blame blame : entry.getValue())
{
-// TODO: FELIX3 - Assume if a module imports the same package it
-// exports that the import will overlap the export.
- if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
- && !hasOverlappingImport(module, caps.get(i)))
- {
- packages.m_exportedPkgs.put(
- (String) caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue(),
- new Blame(incomingReqs, caps.get(i)));
- }
- }
- }
-
- modulePkgMap.put(module, packages);
- }
-
- private static boolean hasOverlappingImport(Module module, Capability cap)
- {
- if (m_isInvokeCount)
- {
- String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
- Long count = m_invokeCounts.get(methodName);
- count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
- m_invokeCounts.put(methodName, count);
- }
+ List<Requirement> blameReqs = new ArrayList();
+ blameReqs.add(blame.m_reqs.get(0));
- List<Requirement> reqs = module.getRequirements();
- for (int i = 0; i < reqs.size(); i++)
- {
- if (reqs.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
- && CapabilitySet.matches(cap, reqs.get(i).getFilter()))
- {
- return true;
+ mergeUses(
+ module,
+ modulePkgs,
+ blame.m_cap,
+ blameReqs,
+ modulePkgMap,
+ candidateMap,
+ usesCycleMap);
}
}
- return false;
}
private void mergeCandidatePackages(
- Module current, List<Requirement> outgoingReqs,
- Capability candCap, Map<Module, Packages> modulePkgMap,
- Map<Requirement, Set<Capability>> candidateMap)
+ Module current, Requirement currentReq, Capability candCap,
+ Map<Module, Packages> modulePkgMap, Map<Requirement, Set<Capability>> candidateMap)
{
if (m_isInvokeCount)
{
@@ -892,10 +693,13 @@ ex.printStackTrace();
if (candCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
{
mergeCandidatePackage(
- current, false, new Blame(outgoingReqs, candCap), modulePkgMap, candidateMap);
+ current, false, currentReq, candCap, modulePkgMap);
}
else if (candCap.getNamespace().equals(Capability.MODULE_NAMESPACE))
{
+// TODO: FELIX3 - THIS NEXT LINE IS A HACK. IMPROVE HOW/WHEN WE CALCULATE EXPORTS.
+ calculateExportedPackages(candCap.getModule(), modulePkgMap);
+
// Get the candidate's package space to determine which packages
// will be visible to the current module.
Packages candPkgs = modulePkgMap.get(candCap.getModule());
@@ -907,9 +711,9 @@ ex.printStackTrace();
mergeCandidatePackage(
current,
true,
- new Blame(outgoingReqs, entry.getValue().m_cap),
- modulePkgMap,
- candidateMap);
+ currentReq,
+ entry.getValue().m_cap,
+ modulePkgMap);
}
// If the candidate requires any other bundles with reexport visibility,
@@ -924,7 +728,7 @@ ex.printStackTrace();
{
mergeCandidatePackages(
current,
- outgoingReqs,
+ currentReq,
candidateMap.get(req).iterator().next(),
modulePkgMap,
candidateMap);
@@ -936,8 +740,8 @@ ex.printStackTrace();
private void mergeCandidatePackage(
Module current, boolean requires,
- Blame candBlame, Map<Module, Packages> modulePkgMap,
- Map<Requirement, Set<Capability>> candidateMap)
+ Requirement currentReq, Capability candCap,
+ Map<Module, Packages> modulePkgMap)
{
if (m_isInvokeCount)
{
@@ -949,112 +753,54 @@ ex.printStackTrace();
// TODO: FELIX3 - Check for merging where module imports from itself,
// then it should be listed as an export for requiring bundles.
- if (candBlame.m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ if (candCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
{
//System.out.println("+++ MERGING " + candBlame.m_cap + " INTO " + current);
String pkgName = (String)
- candBlame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
+ candCap.getAttribute(Capability.PACKAGE_ATTR).getValue();
// Since this capability represents a package, it will become
// a hard constraint on the module's package space, so we need
// to make sure it doesn't conflict with any other hard constraints
// or any other uses constraints.
+ List blameReqs = new ArrayList();
+ blameReqs.add(currentReq);
+
//
// First, check to see if the capability conflicts with
// any existing hard constraints.
//
Packages currentPkgs = modulePkgMap.get(current);
- Blame currentExportedBlame = currentPkgs.m_exportedPkgs.get(pkgName);
- Blame currentImportedBlame = currentPkgs.m_importedPkgs.get(pkgName);
- List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(pkgName);
-
- // We don't need to worry about an import conflicting with a required
- // bundle's export, since imported package wires are terminal the
- // bundle will never see the exported package from the required bundle.
-// TODO: FELIX3 - See scenario 21, this seems odd.
- if (!requires &&
- (currentImportedBlame != null) && !currentImportedBlame.m_cap.equals(candBlame.m_cap))
-// if (!requires &&
-// (((currentExportedBlame != null) && !currentExportedBlame.m_cap.equals(candBlame.m_cap))
-// || ((currentImportedBlame != null) && !currentImportedBlame.m_cap.equals(candBlame.m_cap))))
-// || ((currentRequiredBlames != null) && !currentRequiredBlames.contains(candBlame))))
- {
- // Permutate the candidate map and throw a resolve exception.
- // NOTE: This method ALWAYS throws an exception.
- permutateCandidates(
- current,
- pkgName,
- currentImportedBlame,
- candBlame,
- candidateMap);
- }
-
- //
- // Second, check to see if the capability conflicts with
- // any existing uses constraints
- //
-
- Packages currentPkgsCopy = currentPkgs;
-
- if (!current.isResolved())
- {
- List<Blame> currentUsedBlames = currentPkgs.m_usedPkgs.get(pkgName);
- checkExistingUsesConstraints(
- current, pkgName, currentUsedBlames, candBlame, modulePkgMap, candidateMap);
-
- //
- // Last, check to see if any uses constraints implied by the
- // candidate conflict with any of the existing hard constraints.
- //
-
- // For now, create a copy of the module's package space and
- // add the current candidate to the imported packages.
- currentPkgsCopy = new Packages(currentPkgs);
- }
if (requires)
{
+ List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(pkgName);
if (currentRequiredBlames == null)
{
currentRequiredBlames = new ArrayList<Blame>();
- currentPkgsCopy.m_requiredPkgs.put(pkgName, currentRequiredBlames);
+ currentPkgs.m_requiredPkgs.put(pkgName, currentRequiredBlames);
}
-// TODO: FELIX3 - This is potentially modifying the original, we need to modify a copy.
- currentRequiredBlames.add(candBlame);
+ currentRequiredBlames.add(new Blame(candCap, blameReqs));
}
else
{
- currentPkgsCopy.m_importedPkgs.put(pkgName, candBlame);
+ List<Blame> currentImportedBlames = currentPkgs.m_importedPkgs.get(pkgName);
+ if (currentImportedBlames == null)
+ {
+ currentImportedBlames = new ArrayList<Blame>();
+ currentPkgs.m_importedPkgs.put(pkgName, currentImportedBlames);
+ }
+ currentImportedBlames.add(new Blame(candCap, blameReqs));
}
- // Verify and merge the candidate's transitive uses constraints.
- verifyAndMergeUses(
- current,
- currentPkgsCopy,
- candBlame,
- modulePkgMap,
- candidateMap,
- new HashMap<String, List<Module>>());
-
- // If we are here, then there were no conflict, so we should update
- // the module's package space.
- if (!current.isResolved())
- {
- currentPkgs.m_exportedPkgs.putAll(currentPkgsCopy.m_exportedPkgs);
- currentPkgs.m_importedPkgs.putAll(currentPkgsCopy.m_importedPkgs);
- currentPkgs.m_requiredPkgs.putAll(currentPkgsCopy.m_requiredPkgs);
- currentPkgs.m_usedPkgs.putAll(currentPkgsCopy.m_usedPkgs);
- }
-dumpModulePkgs(current, currentPkgs);
+//dumpModulePkgs(current, currentPkgs);
}
}
- private void checkExistingUsesConstraints(
- Module current, String pkgName, List<Blame> currentUsedBlames,
- Blame candBlame, Map<Module, Packages> modulePkgMap,
- Map<Requirement, Set<Capability>> candidateMap)
+ private static void addCapabilityDependency(
+ Capability cap, Requirement req, Map<Capability, Set<Requirement>> capDepSet)
{
if (m_isInvokeCount)
{
@@ -1064,30 +810,22 @@ dumpModulePkgs(current, currentPkgs);
m_invokeCounts.put(methodName, count);
}
- for (int i = 0; (currentUsedBlames != null) && (i < currentUsedBlames.size()); i++)
+ Set<Requirement> reqs = capDepSet.get(cap);
+ if (reqs == null)
{
-//System.out.println("+++ CHECK " + candBlame + " IN EXISTING " + currentUsedBlames.get(i));
- if (!isCompatible(currentUsedBlames.get(i).m_cap, candBlame.m_cap, modulePkgMap))
- {
- // Permutate the candidate map and throw a resolve exception.
- // NOTE: This method ALWAYS throws an exception.
- permutateCandidates(
- current,
- pkgName,
- currentUsedBlames.get(i),
- candBlame,
- candidateMap);
- }
+ reqs = new HashSet();
+ capDepSet.put(cap, reqs);
}
+ reqs.add(req);
}
// TODO: FELIX3 - We end up with duplicates in uses constraints,
// see scenario 2 for an example.
- private void verifyAndMergeUses(
+ private void mergeUses(
Module current, Packages currentPkgs,
- Blame candBlame, Map<Module, Packages> modulePkgMap,
+ Capability mergeCap, List<Requirement> blameReqs, Map<Module, Packages> modulePkgMap,
Map<Requirement, Set<Capability>> candidateMap,
- Map<String, List<Module>> cycleMap)
+ Map<Capability, List<Module>> cycleMap)
{
if (m_isInvokeCount)
{
@@ -1097,99 +835,82 @@ dumpModulePkgs(current, currentPkgs);
m_invokeCounts.put(methodName, count);
}
- // Check for cycles.
- String pkgName = (String)
- candBlame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
- List<Module> list = cycleMap.get(pkgName);
- if ((list != null) && list.contains(current))
+ if (!mergeCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ return;
+ }
+ // If the candidate module is the same as the current module,
+ // then we don't need to verify and merge the uses constraints
+ // since this will happen as we build up the package space.
+ else if (current == mergeCap.getModule())
{
return;
}
- list = (list == null) ? new ArrayList<Module>() : list;
- list.add(current);
- cycleMap.put(pkgName, list);
-//System.out.println("+++ VERIFYING USES " + current + " FOR " + candBlame);
- for (Capability candSourceCap : getPackageSources(
- candBlame.m_cap, modulePkgMap, new ArrayList<Capability>(), new HashSet<Capability>()))
+ // Check for cycles.
+ List<Module> list = cycleMap.get(mergeCap);
+ if ((list != null) && list.contains(current))
+ {
+ return;
+ }
+ list = (list == null) ? new ArrayList<Module>() : list;
+ list.add(current);
+ cycleMap.put(mergeCap, list);
+
+//System.out.println("+++ MERGING USES " + current + " FOR " + candBlame);
+ for (Capability candSourceCap : getPackageSources(mergeCap, modulePkgMap))
{
for (String usedPkgName : candSourceCap.getUses())
{
- Blame currentExportedBlame = currentPkgs.m_exportedPkgs.get(usedPkgName);
- Blame currentImportedBlame = currentPkgs.m_importedPkgs.get(usedPkgName);
-// TODO: FELIX3 - What do we do with required packages?
- List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(usedPkgName);
-
Packages candSourcePkgs = modulePkgMap.get(candSourceCap.getModule());
-//System.out.println("+++ candSourceCap " + candSourceCap);
-//System.out.println("+++ candSourceCap.getModule() " + candSourceCap.getModule() + " (" + candSourceCap.getModule().isResolved() + ")");
-//System.out.println("+++ candSourcePkgs " + candSourcePkgs);
-//System.out.println("+++ candSourcePkgs.m_exportedPkgs " + candSourcePkgs.m_exportedPkgs);
- Blame candSourceBlame = candSourcePkgs.m_exportedPkgs.get(usedPkgName);
- candSourceBlame = (candSourceBlame != null)
- ? candSourceBlame
- : candSourcePkgs.m_importedPkgs.get(usedPkgName);
-// sourceCap = (sourceCap != null)
-// ? sourceCap
-// : sourcePkgs.m_requiredPkgs.get(usedPkgName);
-
- // If the candidate doesn't actually have a constraint for
- // the used package, then just ignore it since this is likely
- // an error in its metadata.
- if (candSourceBlame == null)
- {
- return;
- }
-
- // If there is no current mapping for this package, then
- // we can just return.
- if ((currentExportedBlame == null)
- && (currentImportedBlame == null)
- && (currentRequiredBlames == null))
+ Blame candExportedBlame = candSourcePkgs.m_exportedPkgs.get(usedPkgName);
+ List<Blame> candSourceBlames = null;
+ if (candExportedBlame != null)
{
- List<Blame> usedCaps = currentPkgs.m_usedPkgs.get(usedPkgName);
- if (usedCaps == null)
- {
- usedCaps = new ArrayList<Blame>();
- currentPkgs.m_usedPkgs.put(usedPkgName, usedCaps);
- }
-//System.out.println("+++ MERGING CB " + candBlame + " SB " + candSourceBlame);
-// usedCaps.add(new Blame(candBlame.m_reqs, sourceBlame.m_cap));
- usedCaps.add(candSourceBlame);
-// return;
+ candSourceBlames = new ArrayList(1);
+ candSourceBlames.add(candExportedBlame);
+ }
+ else
+ {
+ candSourceBlames = candSourcePkgs.m_importedPkgs.get(usedPkgName);
+ }
+
+ if (candSourceBlames == null)
+ {
+ continue;
}
- else if (!current.isResolved())
+
+ List<Blame> usedCaps = currentPkgs.m_usedPkgs.get(usedPkgName);
+ if (usedCaps == null)
{
- if ((currentExportedBlame != null)
- && !isCompatible(currentExportedBlame.m_cap, candSourceBlame.m_cap, modulePkgMap))
+ usedCaps = new ArrayList<Blame>();
+ currentPkgs.m_usedPkgs.put(usedPkgName, usedCaps);
+ }
+ for (Blame blame : candSourceBlames)
+ {
+ if (blame.m_reqs != null)
{
- throw new ResolveException(
- "Constraint violation for package '" + usedPkgName
- + "' when resolving module " + current
- + " between existing constraint "
- + currentExportedBlame
- + " and candidate constraint "
- + candSourceBlame, null, null);
+ List<Requirement> blameReqs2 = new ArrayList(blameReqs);
+ blameReqs2.add(blame.m_reqs.get(blame.m_reqs.size() - 1));
+ usedCaps.add(new Blame(blame.m_cap, blameReqs2));
+ mergeUses(current, currentPkgs, blame.m_cap, blameReqs2,
+ modulePkgMap, candidateMap, cycleMap);
}
- else if ((currentImportedBlame != null)
- && !isCompatible(currentImportedBlame.m_cap, candSourceBlame.m_cap, modulePkgMap))
+ else
{
- permutateCandidates(
- current, usedPkgName, currentImportedBlame,
- candSourceBlame, candidateMap);
+ usedCaps.add(new Blame(blame.m_cap, blameReqs));
+ mergeUses(current, currentPkgs, blame.m_cap, blameReqs,
+ modulePkgMap, candidateMap, cycleMap);
}
}
-
- verifyAndMergeUses(current, currentPkgs, candSourceBlame,
- modulePkgMap, candidateMap, cycleMap);
}
}
}
- private void permutateCandidates(
- Module current, String pkgName, Blame currentBlame, Blame candBlame,
- Map<Requirement, Set<Capability>> candidateMap)
- throws ResolveException
+ private void checkPackageSpaceConsistency(
+ Module module, Map<Requirement, Set<Capability>> candidateMap,
+ Map<Module, Packages> modulePkgMap, Map<Capability, Set<Requirement>> capDepSet,
+ Map<Module, Object> resultCache)
{
if (m_isInvokeCount)
{
@@ -1199,73 +920,235 @@ dumpModulePkgs(current, currentPkgs);
m_invokeCounts.put(methodName, count);
}
-// TODO: FELIX3 - I think permutation is not as efficient as it could be, since
-// the check for subsets is costly.
+ if (module.isResolved())
+ {
+ return;
+ }
+ else if (resultCache.containsKey(module))
+ {
+ return;
+ }
+
+//System.out.println("+++ checkPackageSpaceConsistency(" + module + ")");
+ Packages pkgs = modulePkgMap.get(module);
+
+ ResolveException rethrow = null;
+ Map<Requirement, Set<Capability>> copyConflict = null;
+ Set<Requirement> mutated = null;
+
+ Set<Module> checkModules = new HashSet();
+
+ // Check for conflicting imports from fragments.
+ for (Entry<String, List<Blame>> entry : pkgs.m_importedPkgs.entrySet())
+ {
+ if (entry.getValue().size() > 1)
+ {
+ Blame sourceBlame = null;
+ for (Blame blame : entry.getValue())
+ {
+ if (sourceBlame == null)
+ {
+ sourceBlame = blame;
+ }
+ 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);
+ }
+ // 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);
+ }
+ throw new ResolveException(
+ "Constraint violation for package '"
+ + entry.getKey() + "' when resolving module "
+ + module + " between an imported constraint "
+ + sourceBlame + " and an additional imported constraint "
+ + blame, module, blame.m_reqs.get(0));
+ }
+ }
+ }
+ }
+
+ for (Entry<String, Blame> entry : pkgs.m_exportedPkgs.entrySet())
+ {
+ String pkgName = entry.getKey();
+ if (!pkgs.m_usedPkgs.containsKey(pkgName))
+ {
+ continue;
+ }
+ for (Blame blame : pkgs.m_usedPkgs.get(pkgName))
+ {
+ if (!isCompatible(entry.getValue().m_cap, blame.m_cap, modulePkgMap))
+ {
+ copyConflict = (copyConflict != null)
+ ? copyConflict
+ : copyCandidateMap(candidateMap);
+ rethrow = (rethrow != null)
+ ? rethrow
+ : new ResolveException(
+ "Constraint violation for package '"
+ + pkgName + "' when resolving module "
+ + module + " between existing exported constraint "
+ + entry.getValue() + " and uses constraint "
+ + blame, null, null);
+ mutated = (mutated != null)
+ ? mutated
+ : new HashSet();
+// TODO: FELIX3 - I think we need to walk up this chain too.
+// TODO: FELIX3 - What about uses and import permutations?
+ Requirement req = blame.m_reqs.get(blame.m_reqs.size() - 1);
+ if (!mutated.contains(req))
+ {
+ mutated.add(req);
+ Set<Capability> caps = copyConflict.get(req);
+ Iterator it = caps.iterator();
+ it.next();
+ it.remove();
+ if (caps.size() == 0)
+ {
+ removeInvalidateCandidate(req.getModule(), capDepSet, copyConflict);
+ }
+ }
+ }
+ }
+ if (rethrow != null)
+ {
+ m_usesPermutations.add(copyConflict);
+ throw rethrow;
+ }
+ }
+
+ // Check if there are any conflicts with imported packages.
+ for (Entry<String, List<Blame>> entry : pkgs.m_importedPkgs.entrySet())
+ {
+ for (Blame importBlame : entry.getValue())
+ {
+ if (!module.equals(importBlame.m_cap.getModule()))
+ {
+ checkModules.add(importBlame.m_cap.getModule());
+ }
+
+ String pkgName = entry.getKey();
+ if (!pkgs.m_usedPkgs.containsKey(pkgName))
+ {
+ continue;
+ }
+ for (Blame usedBlame : pkgs.m_usedPkgs.get(pkgName))
+ {
+ if (!isCompatible(importBlame.m_cap, usedBlame.m_cap, modulePkgMap))
+ {
+ // Create a candidate permutation that eliminates any candidates
+ // that conflict with existing selected candidates.
+ copyConflict = (copyConflict != null)
+ ? copyConflict
+ : copyCandidateMap(candidateMap);
+ rethrow = (rethrow != null)
+ ? rethrow
+ : new ResolveException(
+ "Constraint violation for package '"
+ + pkgName + "' when resolving module "
+ + module + " between existing imported constraint "
+ + importBlame + " and uses constraint "
+ + usedBlame, null, null);
+
+ mutated = (mutated != null)
+ ? mutated
+ : new HashSet();
+
+ for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--)
+ {
+ Requirement req = usedBlame.m_reqs.get(reqIdx);
- // When we detect a conflict, we need to permutate the candidate map
- // we when we try again, we'll select different candidates. To achieve
- // this, we create a different permutation for each requirement in
- // the set of blames requirements by eliminating the first candidate
- // (i.e., the selected candidate) for each. We need to create an separate
- // permutation for each blamed requirement to ensure we try all possible
- // combination. This is a form of back tracking, since we eliminate each
- // requirement's selected candidate, which will force them to choose
- // another in the new permutation.
- //
- // The blamed requirement may be null if the bundle itself is exports
- // the package imposing the uses constraint.
- if ((currentBlame.m_reqs != null) && (currentBlame.m_reqs.size() != 0))
- {
- // Permutate the candidate map for each blamed requirement.
- for (int reqIdx = 0; reqIdx < currentBlame.m_reqs.size(); reqIdx++)
- {
- // Verify whether we have more than one candidate to create
- // a permutation.
- Set<Capability> candidates = candidateMap.get(currentBlame.m_reqs.get(reqIdx));
- if (candidates.size() > 1)
- {
- // Create a copy of the current candidate map and then remove
- // the first (i.e., selected) candidate for the current
- // blamed requirement.
- Map<Requirement, Set<Capability>> copy = copyCandidateMap(candidateMap);
- Set<Capability> candCopy = copy.get(currentBlame.m_reqs.get(reqIdx));
- Iterator it = candCopy.iterator();
- it.next();
- it.remove();
-
- // Check if the created permutation is a subset of a previously
- // created permutation. If so, then we don't need to record it
- // since it will be generated again when the superset permutation
- // is processed.
- boolean isSubset = false;
- for (int permIdx = 0; !isSubset && (permIdx < m_candidatePermutations.size()); permIdx++)
+ // 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 module
+ // associated with the requirement is already resolved.
+ Set<Capability> candidates = copyConflict.get(req);
+ if ((candidates != null) && (candidates.size() > 1))
+ {
+ mutated.add(req);
+ Iterator it = candidates.iterator();
+ it.next();
+ it.remove();
+ // Continue with the next uses constraint.
+ break;
+ }
+ }
+ }
+ }
+
+ 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.
+ Requirement req = importBlame.m_reqs.get(0);
+ if (!mutated.contains(req))
{
- if (isSubsetPermutation(m_candidatePermutations.get(permIdx), copy))
+ Set<Capability> candidates = candidateMap.get(req);
+ if (candidates.size() > 1)
{
- isSubset = true;
+ Map<Requirement, Set<Capability>> importPerm =
+ copyCandidateMap(candidateMap);
+ candidates = importPerm.get(req);
+ Iterator it = candidates.iterator();
+ it.next();
+ it.remove();
+ m_importPermutations.add(importPerm);
}
}
- if (!isSubset)
+
+ if (mutated.size() > 0)
{
-//System.out.println("+++ SETTING "
-// + currentBlame.m_reqs.get(reqIdx)
-// + " CANDS FROM " + candidates + " TO " + candCopy);
- m_candidatePermutations.add(0, copy);
+ m_usesPermutations.add(copyConflict);
}
+
+ throw rethrow;
}
}
}
- throw new ResolveException(
- "Constraint violation for package '"
- + pkgName + "' when resolving module "
- + current + " between existing constraint "
- + currentBlame + " and candidate constraint "
- + candBlame, null, null);
+ resultCache.put(module, Boolean.TRUE);
+
+ // Now check the consistency of all modules on which the
+ // current module depends.
+ for (Module m : checkModules)
+ {
+ checkPackageSpaceConsistency(m, candidateMap, modulePkgMap, capDepSet, resultCache);
+ }
}
- private static boolean isSubsetPermutation(
- Map<Requirement, Set<Capability>> orig, Map<Requirement, Set<Capability>> copy)
+ private void removeInvalidateCandidate(
+ Module invalid, Map<Capability, Set<Requirement>> capDepSet,
+ Map<Requirement, Set<Capability>> candidateMap)
{
if (m_isInvokeCount)
{
@@ -1275,22 +1158,109 @@ dumpModulePkgs(current, currentPkgs);
m_invokeCounts.put(methodName, count);
}
- for (Entry<Requirement, Set<Capability>> entry : orig.entrySet())
+ Set<Module> invalidated = new HashSet();
+
+ for (Requirement req : invalid.getRequirements())
{
- Set<Capability> copyCands = copy.get(entry.getKey());
- if (copyCands == null)
+ candidateMap.remove(req);
+ }
+
+ boolean wasRequired = false;
+
+ for (Capability cap : invalid.getCapabilities())
+ {
+ Set<Requirement> reqs = capDepSet.remove(cap);
+ if (reqs == null)
{
- return false;
+ continue;
}
- if (!entry.getValue().containsAll(copyCands))
+ wasRequired = true;
+ for (Requirement req : reqs)
{
- return false;
+ Set<Capability> candidates = candidateMap.get(req);
+ candidates.remove(cap);
+ if (candidates.size() == 0)
+ {
+ candidateMap.remove(req);
+ invalidated.add(req.getModule());
+ }
}
}
- return true;
+
+ if (!wasRequired)
+ {
+ throw new ResolveException(
+ "Unable to resolve module", invalid, null);
+ }
+
+ for (Module m : invalidated)
+ {
+ removeInvalidateCandidate(m, capDepSet, candidateMap);
+ }
}
- private static boolean isCompatible(
+ private static void calculateExportedPackages(
+ Module module, Map<Module, Packages> modulePkgMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ Packages packages = modulePkgMap.get(module);
+ if (packages != null)
+ {
+ return;
+ }
+ packages = new Packages();
+
+ List<Capability> caps = module.getCapabilities();
+
+ if (caps.size() > 0)
+ {
+ for (int i = 0; i < caps.size(); i++)
+ {
+// TODO: FELIX3 - Assume if a module imports the same package it
+// exports that the import will overlap the export.
+ if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+ && !hasOverlappingImport(module, caps.get(i)))
+ {
+ packages.m_exportedPkgs.put(
+ (String) caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue(),
+ new Blame(caps.get(i), null));
+ }
+ }
+ }
+
+ modulePkgMap.put(module, packages);
+ }
+
+ private static boolean hasOverlappingImport(Module module, Capability cap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ List<Requirement> reqs = module.getRequirements();
+ for (int i = 0; i < reqs.size(); i++)
+ {
+ if (reqs.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+ && CapabilitySet.matches(cap, reqs.get(i).getFilter()))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isCompatible(
Capability currentCap, Capability candCap, Map<Module, Packages> modulePkgMap)
{
if (m_isInvokeCount)
@@ -1303,25 +1273,54 @@ dumpModulePkgs(current, currentPkgs);
if ((currentCap != null) && (candCap != null))
{
+ if (currentCap.equals(candCap))
+ {
+ return true;
+ }
+
List<Capability> currentSources =
getPackageSources(
currentCap,
- modulePkgMap,
- new ArrayList<Capability>(),
- new HashSet<Capability>());
+ modulePkgMap);
List<Capability> candSources =
getPackageSources(
candCap,
- modulePkgMap,
- new ArrayList<Capability>(),
- new HashSet<Capability>());
+ modulePkgMap);
//System.out.println("+++ currentSources " + currentSources + " - candSources " + candSources);
return currentSources.containsAll(candSources) || candSources.containsAll(currentSources);
}
return true;
}
- private static List<Capability> getPackageSources(
+ private Map<Capability, List<Capability>> m_packageSourcesCache = new HashMap();
+
+ private List<Capability> getPackageSources(
+ Capability cap, Map<Module, Packages> modulePkgMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ if (cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ List<Capability> sources = m_packageSourcesCache.get(cap);
+ if (sources == null)
+ {
+ sources = getPackageSourcesInternal(
+ cap, modulePkgMap, new ArrayList(), new HashSet());
+ m_packageSourcesCache.put(cap, sources);
+ }
+ return sources;
+ }
+
+ return Collections.emptyList();
+ }
+
+ private static List<Capability> getPackageSourcesInternal(
Capability cap, Map<Module, Packages> modulePkgMap, List<Capability> sources,
Set<Capability> cycleMap)
{
@@ -1363,7 +1362,7 @@ dumpModulePkgs(current, currentPkgs);
{
for (Blame blame : required)
{
- getPackageSources(blame.m_cap, modulePkgMap, sources, cycleMap);
+ getPackageSourcesInternal(blame.m_cap, modulePkgMap, sources, cycleMap);
}
}
}
@@ -1471,30 +1470,37 @@ dumpModulePkgs(current, currentPkgs);
List<Wire> packageWires = new ArrayList<Wire>();
Packages pkgs = modulePkgMap.get(module);
- for (Entry<String, Blame> entry : pkgs.m_importedPkgs.entrySet())
+ for (Entry<String, List<Blame>> entry : pkgs.m_importedPkgs.entrySet())
{
- if (!entry.getValue().m_cap.getModule().isResolved())
+ for (Blame blame : entry.getValue())
{
- populateWireMap(entry.getValue().m_cap.getModule(), modulePkgMap, wireMap,
- candidateMap);
- }
+ // Ignore modules that import themselves.
+ if (!module.equals(blame.m_cap.getModule())
+ && blame.m_cap.getAttribute(
+ Capability.PACKAGE_ATTR).getValue().equals(pkgName))
+ {
+ if (!blame.m_cap.getModule().isResolved())
+ {
+ populateWireMap(blame.m_cap.getModule(), modulePkgMap, wireMap,
+ candidateMap);
+ }
- // Ignore modules that import themselves.
- if (!module.equals(entry.getValue().m_cap.getModule())
- && entry.getValue().m_cap.getAttribute(
- Capability.PACKAGE_ATTR).getValue().equals(pkgName))
- {
- List<Attribute> attrs = new ArrayList();
- attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
- packageWires.add(
- new WireImpl(
- module,
- // We need an unique requirement here or else subsequent
- // dynamic imports for the same dynamic requirement will
- // conflict with previous ones.
- new RequirementImpl(Capability.PACKAGE_NAMESPACE, new ArrayList(0), attrs),
- entry.getValue().m_cap.getModule(),
- entry.getValue().m_cap));
+ List<Attribute> attrs = new ArrayList();
+ attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
+ packageWires.add(
+ new WireImpl(
+ module,
+ // We need an unique requirement here or else subsequent
+ // dynamic imports for the same dynamic requirement will
+ // conflict with previous ones.
+ new RequirementImpl(
+ module,
+ Capability.PACKAGE_NAMESPACE,
+ new ArrayList(0),
+ attrs),
+ blame.m_cap.getModule(),
+ blame.m_cap));
+ }
}
}
@@ -1503,16 +1509,74 @@ dumpModulePkgs(current, currentPkgs);
return wireMap;
}
+ private static void dumpCandidateMap(
+ ResolverState state, Map<Requirement, Set<Capability>> candidateMap)
+ {
+ System.out.println("=== BEGIN CANDIDATE MAP ===");
+ for (Module module : ((ResolverStateImpl) state).getModules())
+ {
+ System.out.println(" " + module
+ + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
+ for (Requirement req : module.getRequirements())
+ {
+ Set<Capability> candidates = candidateMap.get(req);
+ if ((candidates != null) && (candidates.size() > 0))
+ {
+ System.out.println(" " + req + ": " + candidates);
+ }
+ }
+ for (Requirement req : module.getDynamicRequirements())
+ {
+ Set<Capability> candidates = candidateMap.get(req);
+ if ((candidates != null) && (candidates.size() > 0))
+ {
+ System.out.println(" " + req + ": " + candidates);
+ }
+ }
+ }
+ System.out.println("=== END CANDIDATE MAP ===");
+ }
+
+ private static void dumpModulePkgMap(Map<Module, Packages> modulePkgMap)
+ {
+ System.out.println("+++MODULE PKG MAP+++");
+ for (Entry<Module, Packages> entry : modulePkgMap.entrySet())
+ {
+ dumpModulePkgs(entry.getKey(), entry.getValue());
+ }
+ }
+
+ private static void dumpModulePkgs(Module module, Packages packages)
+ {
+ System.out.println(module + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
+ System.out.println(" EXPORTED");
+ for (Entry<String, Blame> entry : packages.m_exportedPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ System.out.println(" IMPORTED");
+ for (Entry<String, List<Blame>> entry : packages.m_importedPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ System.out.println(" REQUIRED");
+ for (Entry<String, List<Blame>> entry : packages.m_requiredPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ System.out.println(" USED");
+ for (Entry<String, List<Blame>> entry : packages.m_usedPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ }
+
private static class Packages
{
- public final Map<String, Blame> m_exportedPkgs
- = new HashMap<String, Blame>();
- public final Map<String, Blame> m_importedPkgs
- = new HashMap<String, Blame>();
- public final Map<String, List<Blame>> m_requiredPkgs
- = new HashMap<String, List<Blame>>();
- public final Map<String, List<Blame>> m_usedPkgs
- = new HashMap<String, List<Blame>>();
+ public final Map<String, Blame> m_exportedPkgs = new HashMap();
+ public final Map<String, List<Blame>> m_importedPkgs = new HashMap();
+ public final Map<String, List<Blame>> m_requiredPkgs = new HashMap();
+ public final Map<String, List<Blame>> m_usedPkgs = new HashMap();
public Packages()
{
@@ -1555,22 +1619,22 @@ dumpModulePkgs(current, currentPkgs);
private static class Blame
{
- public final List<Requirement> m_reqs;
public final Capability m_cap;
+ public final List<Requirement> m_reqs;
- public Blame(List<Requirement> reqs, Capability cap)
+ public Blame(Capability cap, List<Requirement> reqs)
{
- m_reqs = reqs;
m_cap = cap;
+ m_reqs = reqs;
}
public String toString()
{
return m_cap.getModule()
+ "." + m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue()
- + ((m_reqs.size() == 0)
+ + (((m_reqs == null) || (m_reqs.size() == 0))
? " NO BLAME"
- : " BLAMED ON " + m_reqs.get(m_reqs.size() - 1));
+ : " BLAMED ON " + m_reqs);
}
public boolean equals(Object o)