Author: rickhall
Date: Mon Jan 4 21:55:22 2010
New Revision: 895797
URL: http://svn.apache.org/viewvc?rev=895797&view=rev
Log:
Another resolver algorithm prototype.
Added:
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/Proto3Resolver.java
Modified:
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/Main.java
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/manifestparser/Main.java
Modified:
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/Main.java
URL:
http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/Main.java?rev=895797&r1=895796&r2=895797&view=diff
==============================================================================
---
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/Main.java
(original)
+++
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/Main.java
Mon Jan 4 21:55:22 2010
@@ -27,7 +27,7 @@
import java.util.Map.Entry;
import org.apache.felix.resolver.cs.Capability;
import org.apache.felix.resolver.felix.FelixResolver;
-import org.apache.felix.resolver.proto2.Proto2Resolver;
+import org.apache.felix.resolver.proto3.Proto3Resolver;
import org.apache.felix.resolver.prototype.ProtoResolver;
public class Main
@@ -53,7 +53,7 @@
}
else if (args[i].equals("-proto"))
{
- legacy = true;
+ proto = true;
}
else
{
@@ -75,7 +75,7 @@
}
else
{
- resolver = new Proto2Resolver(moduleList);
+ resolver = new Proto3Resolver(moduleList);
}
try
@@ -651,6 +651,10 @@
return target;
}
+ // SOLUTION:
+ // A: foo->B, bar->C, woz->E
+ // B: woz->E
+ // C: woz->E
private static Module scenario13(List<Module> moduleList)
{
Module m, target;
@@ -660,17 +664,17 @@
target = (m = new Module("A"))
.requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=foo"))
.requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=bar"))
- .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz")));
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz").with("version=2.0.0")));
// Bundle B
moduleList.add(
(m = new Module("B"))
.providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=foo").using("woz"))
- .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz").with("version=1.0.0")));
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz")));
// Bundle C
moduleList.add(
(m = new Module("C"))
.providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").using("woz"))
- .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz").with("version=2.0.0")));
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz")));
// Bundle D
moduleList.add(
(m = new Module("D"))
@@ -682,4 +686,187 @@
return target;
}
+
+ private static Module scenario14(List<Module> moduleList)
+ {
+ Module m, target;
+
+ // Bundle A
+ moduleList.add(
+ target = (m = new Module("A"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=B"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C")));
+ // Bundle B
+ moduleList.add(
+ (m = new Module("B"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=B"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar")));
+ // Bundle C
+ moduleList.add(
+ (m = new Module("C"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar")));
+
+ return target;
+ }
+
+ private static Module scenario15(List<Module> moduleList)
+ {
+ Module m, target;
+
+ // Bundle A
+ moduleList.add(
+ target = (m = new Module("A"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=B"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=foo").with("vendor=E")));
+ // Bundle B
+ moduleList.add(
+ (m = new Module("B"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=B"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D")));
+ // Bundle C
+ moduleList.add(
+ (m = new Module("C"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar")));
+ // Bundle D
+ moduleList.add(
+ (m = new Module("D"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").using("foo"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=foo")));
+ // Bundle E
+ moduleList.add(
+ (m = new Module("E"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=foo")));
+ // Bundle F
+ moduleList.add(
+ (m = new Module("F"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=foo").with("vendor=E")));
+
+ return target;
+ }
+
+ private static Module scenario16(List<Module> moduleList)
+ {
+ Module m, target;
+
+ // Bundle A
+ moduleList.add(
+ target = (m = new Module("A"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=C"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=foo")));
+ // Bundle B
+ moduleList.add(
+ (m = new Module("B"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=foo").using("bar"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D")));
+ // Bundle C
+ moduleList.add(
+ (m = new Module("C"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=C")));
+ // Bundle D
+ moduleList.add(
+ (m = new Module("D"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar")));
+
+ return target;
+ }
+
+ private static Module scenario17(List<Module> moduleList)
+ {
+ Module m, target;
+
+ // Bundle A
+ moduleList.add(
+ target = (m = new Module("A"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=foo"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=bar")));
+ // Bundle B
+ moduleList.add(
+ (m = new Module("B"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=foo").using("bar"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D")));
+ // Bundle C
+ moduleList.add(
+ (m = new Module("C"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=C")));
+ // Bundle D
+ moduleList.add(
+ (m = new Module("D"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar")));
+ // Bundle BB
+ moduleList.add(
+ (m = new Module("BB"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=woz").using("bar"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=CC"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=DD")));
+ // Bundle CC
+ moduleList.add(
+ (m = new Module("CC"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=CC"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=CC")));
+ // Bundle DD
+ moduleList.add(
+ (m = new Module("DD"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=DD"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar")));
+
+ return target;
+ }
+
+ private static Module scenario18(List<Module> moduleList)
+ {
+ Module m, target;
+
+ // Bundle A
+ moduleList.add(
+ target = (m = new Module("A"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=foo"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz"))
+ .requiring(new
RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=bar")));
+ // Bundle B
+ moduleList.add(
+ (m = new Module("B"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=foo").using("bar"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D")));
+ // Bundle C
+ moduleList.add(
+ (m = new Module("C"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=C"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=C")));
+ // Bundle D
+ moduleList.add(
+ (m = new Module("D"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar")));
+ // Bundle BB
+ moduleList.add(
+ (m = new Module("BB"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=woz").using("bar"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=CC"))
+ .requiring(new
RequirementImpl(Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=D")));
+ // Bundle CC
+ moduleList.add(
+ (m = new Module("CC"))
+ .providing(new CapabilityImpl(m,
Capability.MODULE_NAMESPACE).with("bundle-symbolic-name=CC"))
+ .providing(new CapabilityImpl(m,
Capability.PACKAGE_NAMESPACE).with("package=bar").with("vendor=CC")));
+
+ return target;
+ }
}
\ No newline at end of file
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=895797&r1=895796&r2=895797&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
Mon Jan 4 21:55:22 2010
@@ -38,6 +38,7 @@
import org.apache.felix.resolver.cs.Capability;
import org.apache.felix.resolver.cs.Requirement;
import org.apache.felix.resolver.felix.FelixResolver;
+import org.apache.felix.resolver.proto3.Proto3Resolver;
import org.apache.felix.resolver.prototype.ProtoResolver;
public class Main
@@ -46,19 +47,24 @@
{
if (args.length < 1)
{
- System.err.println("usage: [-Dinvoke.count=true] [-legacy]
[-nodupes] <bundle-dir>");
+ System.err.println("usage: [-Dinvoke.count=true] [-legacy |
-proto] [-nodupes] <bundle-dir>");
System.exit(0);
}
boolean legacy = false;
+ boolean proto = false;
boolean duplicates = true;
String dir = args[args.length - 1];
- for (int i = 0; i < args.length - 1; i++)
+ for (int i = 0; i < args.length; i++)
{
if (args[i].equals("-legacy"))
{
legacy = true;
}
+ else if (args[i].equals("-proto"))
+ {
+ proto = true;
+ }
else if (args[i].equals("-nodupes"))
{
duplicates = false;
@@ -334,10 +340,14 @@
{
resolver = new FelixResolver(moduleList);
}
- else
+ else if (proto)
{
resolver = new ProtoResolver(moduleList);
}
+ else
+ {
+ resolver = new Proto3Resolver(moduleList);
+ }
try
{
@@ -400,9 +410,9 @@
private static Module getTarget(List<Module> modules)
{
-// return getTargetByUnresolved(modules);
+ return getTargetByUnresolved(modules);
// return getTargetBySymbolicName(modules, "org.springframework.faces");
- return getTargetBySymbolicName(modules, "bundle1");
+// return getTargetBySymbolicName(modules, "bundle1");
}
private static Module getTargetByUnresolved(List<Module> modules)
Added:
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=895797&view=auto
==============================================================================
---
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/Proto3Resolver.java
(added)
+++
felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto3/Proto3Resolver.java
Mon Jan 4 21:55:22 2010
@@ -0,0 +1,848 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver.proto3;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeSet;
+import org.apache.felix.resolver.Module;
+import org.apache.felix.resolver.ResolveException;
+import org.apache.felix.resolver.Resolver;
+import org.apache.felix.resolver.Version;
+import org.apache.felix.resolver.Wire;
+import org.apache.felix.resolver.cs.Capability;
+import org.apache.felix.resolver.cs.CapabilitySet;
+import org.apache.felix.resolver.cs.Requirement;
+import org.apache.felix.resolver.manifestparser.Constants;
+
+// 1. Treat hard pkg constraints separately from implied package constraints
+// 2. Map pkg constraints to a set of capabilities, not a single capability.
+// 3. Uses constraints cannot conflict with other uses constraints, only with
hard constraints.
+public class Proto3Resolver implements Resolver
+{
+ private final List<Module> m_modules;
+ private final CapabilitySet m_pkgCapSet;
+ private final CapabilitySet m_modCapSet;
+
+ private static final Map<String, Long> m_invokeCounts = new
HashMap<String, Long>();
+
+ private static boolean m_isInvokeCount = false;
+
+ public Proto3Resolver(List<Module> modules)
+ {
+System.out.println("+++ PROTO3 RESOLVER");
+ m_modules = modules;
+
+ List indices = new ArrayList();
+ indices.add(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
+ m_modCapSet = new CapabilitySet(indices);
+
+ indices = new ArrayList();
+ indices.add(Capability.PACKAGE_ATTR);
+ m_pkgCapSet = new CapabilitySet(indices);
+
+ for (int modIdx = 0; modIdx < m_modules.size(); modIdx++)
+ {
+ List<Capability> caps = m_modules.get(modIdx).getCapabilities();
+ for (int capIdx = 0; capIdx < caps.size(); capIdx++)
+ {
+ if
(caps.get(capIdx).getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ m_modCapSet.addCapability(caps.get(capIdx));
+ }
+ else if
(caps.get(capIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ m_pkgCapSet.addCapability(caps.get(capIdx));
+ }
+ }
+ }
+
+ String v = System.getProperty("invoke.count");
+ 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(Module module)
+ {
+ 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 (!module.isResolved())
+ {
+ Map<Requirement, Set<Capability>> candidateMap =
+ new HashMap<Requirement, Set<Capability>>();
+ Map<Module, Packages> modulePkgMap = new HashMap<Module,
Packages>();
+
+ populateCandidates(module, candidateMap, new HashSet<Module>());
+ m_candidatePermutations.add(candidateMap);
+
+ ResolveException rethrow = null;
+
+ do
+ {
+ rethrow = null;
+
+ candidateMap = m_candidatePermutations.remove(0);
+dumpCandidateMap(candidateMap);
+
+ try
+ {
+ findConsistentCandidates(
+ module,
+ new ArrayList(),
+ candidateMap,
+ modulePkgMap,
+ new HashMap<Module, Object>());
+ }
+ catch (ResolveException ex)
+ {
+ rethrow = ex;
+ System.out.println("RE: " + ex);
+ }
+ }
+ while ((rethrow != null) && (m_candidatePermutations.size() > 0));
+
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
+dumpModulePkgMap(modulePkgMap);
+ }
+
+ return null;
+ }
+
+ private void dumpCandidateMap(Map<Requirement, Set<Capability>>
candidateMap)
+ {
+ System.out.println("=== CANDIDATE MAP ===");
+ for (Module module : m_modules)
+ {
+ if (!module.isResolved())
+ {
+ System.out.println(" " + module);
+ for (Requirement req : module.getRequirements())
+ {
+ Set<Capability> candidates = candidateMap.get(req);
+ if ((candidates != null) && (candidates.size() > 0))
+ {
+ System.out.println(" " + req + ": " + candidates);
+ }
+ }
+ }
+ }
+ }
+
+ 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);
+ 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());
+ }
+ }
+
+ private void findConsistentCandidates(
+ Module module, List<Requirement> incomingReqs, Map<Requirement,
Set<Capability>> candidateMap,
+ Map<Module, Packages> modulePkgMap, Map<Module, Object> cycleMap)
+ {
+ 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 the module is resolved, then it is consistent by definition,
+ // so just return.
+ if (module.isResolved())
+ {
+ return;
+ }
+ // If the module is in the cycle map, then just return.
+ else if (cycleMap.containsKey(module))
+ {
+ return;
+ }
+ cycleMap.put(module, module);
+
+System.out.println("+++ RESOLVING " + module);
+ calculateExportedPackages(module, incomingReqs, modulePkgMap);
+
+ List<Requirement> reqs = module.getRequirements();
+ 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(); )
+ {
+ Capability candCap = it.next();
+System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
+ try
+ {
+ // Try to resolve the candidate.
+ findConsistentCandidates(
+ candCap.getModule(),
+ outgoingReqs,
+ candidateMap,
+ modulePkgMap,
+ cycleMap);
+
+ // If we are here, the candidate resolved. Try to merge
+ // the candidate's 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();
+// it.remove();
+ if (!it.hasNext() && !req.isOptional())
+ {
+// candidateMap.remove(req);
+ throw new ResolveException("Unresolved constraint "
+ + req + " in " + module);
+ }
+ }
+ }
+ }
+ }
+
+ private void populateCandidates(
+ Module module, Map<Requirement, Set<Capability>> candidateMap,
Set<Module> cycles)
+ {
+ 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);
+ }
+
+ // Detect cycles.
+ if (cycles.contains(module))
+ {
+ return;
+ }
+ cycles.add(module);
+
+ // Find candidates for all requirements for the target module.
+ List<Requirement> reqs = module.getRequirements();
+ for (Requirement req : reqs)
+ {
+ Set<Capability> candidates = findCandidates(req);
+ for (Iterator<Capability> itCandCap = candidates.iterator();
itCandCap.hasNext(); )
+ {
+ Capability candCap = itCandCap.next();
+ if (!candCap.getModule().isResolved())
+ {
+ try
+ {
+ populateCandidates(candCap.getModule(), candidateMap,
cycles);
+ }
+ catch (ResolveException ex)
+ {
+System.out.println("RE: Candidate not resolveable: " + ex);
+ itCandCap.remove();
+ }
+ }
+ }
+ if ((candidates.size() == 0) && !req.isOptional())
+ {
+ throw new RuntimeException("Unable to resolve " + module
+ + ": missing requirement " + req);
+ }
+ else if (candidates.size() > 0)
+ {
+ candidateMap.put(req, candidates);
+ }
+ }
+ }
+
+ private static Set<Capability> createCandidateSet()
+ {
+ return new TreeSet(new Comparator() {
+ public int compare(Object arg1, Object arg2)
+ {
+ Capability cap1 = (Capability) arg1;
+ Capability cap2 = (Capability) arg2;
+ if (cap1.getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ int c = ((Comparable)
cap1.getAttribute(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
+
.getValue()).compareTo(cap2.getAttribute(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
+ .getValue());
+ if (c == 0)
+ {
+ Version v1 =
(cap1.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE) == null)
+ ? Version.emptyVersion
+ : (Version)
cap1.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE).getValue();
+ Version v2 =
(cap1.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE) == null)
+ ? Version.emptyVersion
+ : (Version)
cap1.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE).getValue();
+ // Compare these in reverse order, since we want
+ // highest version to have priority.
+ c = v2.compareTo(v1);
+ if (c == 0)
+ {
+ c =
cap1.getModule().getName().compareTo(cap2.getModule().getName());
+ }
+ }
+ return c;
+ }
+// TODO: PROTO2 RESOLVER - Need to change this to handle arbitrary capabilities
+// that may not have a natural ordering.
+ // Assume everything else is a package capability.
+ else
+ {
+ int c = ((Comparable)
cap1.getAttribute(Capability.PACKAGE_ATTR).getValue())
+
.compareTo(cap2.getAttribute(Capability.PACKAGE_ATTR).getValue());
+ if (c == 0)
+ {
+ Version v1 =
(cap1.getAttribute(Capability.VERSION_ATTR) == null)
+ ? Version.emptyVersion
+ : (Version)
cap1.getAttribute(Capability.VERSION_ATTR).getValue();
+ Version v2 =
(cap1.getAttribute(Capability.VERSION_ATTR) == null)
+ ? Version.emptyVersion
+ : (Version)
cap1.getAttribute(Capability.VERSION_ATTR).getValue();
+ // Compare these in reverse order, since we want
+ // highest version to have priority.
+ c = v2.compareTo(v1);
+ if (c == 0)
+ {
+ c =
cap1.getModule().getName().compareTo(cap2.getModule().getName());
+ }
+ }
+ return c;
+ }
+ }
+ });
+ }
+
+ private Set<Capability> findCandidates(Requirement req)
+ {
+ 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);
+ }
+
+ Set<Capability> result = createCandidateSet();
+
+ if (req.getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ result.addAll(m_modCapSet.match(req.getFilter()));
+ }
+ else if (req.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ result.addAll(m_pkgCapSet.match(req.getFilter()));
+ }
+
+ return result;
+ }
+
+ private 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 (int i = 0; i < caps.size(); i++)
+ {
+// TODO: PROTO2 RESOLVER - 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 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)
+ && m_pkgCapSet.matches(cap, reqs.get(i).getFilter()))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void mergeCandidatePackages(
+ Module current, List<Requirement> blameReqs,
+ Capability candCap, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ 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 (candCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ mergeCandidatePackage(
+ current, false, new Blame(blameReqs, candCap), modulePkgMap,
candidateMap);
+ }
+ else if (candCap.getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ // Get the candidate's package space to determine which packages
+ // will be visible to the current module.
+ Packages candPkgs = modulePkgMap.get(candCap.getModule());
+
+// TODO: PROTO2 RESOLVER - For now assume only exports, but eventually we also
+// have to support re-exported packages.
+ for (Entry<String, Blame> entry :
candPkgs.m_exportedPkgs.entrySet())
+ {
+ mergeCandidatePackage(
+ current,
+ true,
+ new Blame(blameReqs, entry.getValue().m_cap),
+ modulePkgMap,
+ candidateMap);
+ }
+ }
+ }
+
+ private void mergeCandidatePackage(
+ Module current, boolean requires,
+ Blame candBlame, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ 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
(candBlame.m_cap.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();
+ Packages candPkgs = modulePkgMap.get(candBlame.m_cap.getModule());
+
+ // 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.
+
+ //
+ // 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);
+
+ 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))))
+ {
+dumpModulePkgs(current, currentPkgs);
+ throw new ResolveException("Constraint violation between "
+ + current + " and " + candBlame.m_cap.getModule()
+ + " for " + pkgName);
+ }
+
+ //
+ // Second, check to see if the capability conflicts with
+ // any existing uses constraints
+ //
+
+ 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.
+ Packages currentPkgsCopy = new Packages(currentPkgs);
+
+ if (requires)
+ {
+ if (currentRequiredBlames == null)
+ {
+ currentRequiredBlames = new ArrayList<Blame>();
+ currentPkgsCopy.m_requiredPkgs.put(pkgName,
currentRequiredBlames);
+ }
+// TODO: PROTO2 RESOLVER - This is potentially modifying the original, we need
to modify a copy.
+ currentRequiredBlames.add(candBlame);
+ }
+ else
+ {
+ currentPkgsCopy.m_importedPkgs.put(pkgName, candBlame);
+ }
+
+ // Verify and merge the candidate's transitive uses constraints.
+ verifyAndMergeUses(current, currentPkgsCopy, candBlame,
modulePkgMap, candidateMap);
+
+ // If we are here, then there were no conflict, so we should update
+ // the module's package space.
+ 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);
+ }
+ }
+
+ private void checkExistingUsesConstraints(
+ Module current, String pkgName, List<Blame> currentUsedBlames,
+ Blame candBlame, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ for (int i = 0; (currentUsedBlames != null) && (i <
currentUsedBlames.size()); i++)
+ {
+System.out.println("+++ CHECK " + candBlame + " IN EXISTING " +
currentUsedBlames.get(i));
+ if (!isCompatible(currentUsedBlames.get(i).m_cap, candBlame.m_cap,
modulePkgMap))
+ {
+ // Try to remove the previously selected candidate associated
+ // with the requirement blamed for adding the constraint. This
+ // blamed requirement may be null if the bundle itself is
+ // exports the package imposing the uses constraint.
+ if ((currentUsedBlames.get(i).m_reqs != null)
+ && (currentUsedBlames.get(i).m_reqs.size() != 0))
+ {
+ // Permutate the candidate map.
+ for (int reqIdx = 0; reqIdx <
currentUsedBlames.get(i).m_reqs.size(); reqIdx++)
+ {
+ Map<Requirement, Set<Capability>> copy =
copyCandidateMap(candidateMap);
+ Set<Capability> candidates =
+
copy.get(currentUsedBlames.get(i).m_reqs.get(reqIdx));
+ Iterator it = candidates.iterator();
+ it.next();
+ it.remove();
+// TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy.
+ if (candidates.size() > 0)
+ {
+ m_candidatePermutations.add(copy);
+ }
+ }
+ }
+
+ throw new ResolveException("Constraint violation for package
'" + pkgName
+ + "' when resolving module " + current
+ + " between existing constraint "
+ + currentUsedBlames.get(i)
+ + " and candidate constraint "
+ + candBlame);
+ }
+ }
+ }
+
+// TODO: PROTO2 RESOLVER - We end up with duplicates in uses constraints,
+// see scenario 2 for an example.
+ private void verifyAndMergeUses(
+ Module current, Packages currentPkgs,
+ Blame candBlame, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+System.out.println("+++ VERIFYING USES " + current + " FOR " + candBlame);
+ 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);
+ }
+
+ for (Capability candCapSource : getPackageSources(candBlame.m_cap,
modulePkgMap))
+ {
+ for (String usedPkgName : candCapSource.getUses())
+ {
+ Blame currentExportedBlame =
currentPkgs.m_exportedPkgs.get(usedPkgName);
+ Blame currentImportedBlame =
currentPkgs.m_importedPkgs.get(usedPkgName);
+// TODO: PROTO3 RESOLVER - What do we do with required packages?
+ List<Blame> currentRequiredBlames =
currentPkgs.m_requiredPkgs.get(usedPkgName);
+
+ Packages sourcePkgs =
modulePkgMap.get(candCapSource.getModule());
+ Blame sourceBlame = sourcePkgs.m_exportedPkgs.get(usedPkgName);
+ sourceBlame = (sourceBlame != null)
+ ? sourceBlame
+ : sourcePkgs.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 (sourceBlame == null)
+ {
+ return;
+ }
+
+ // If there is no current mapping for this package, then
+ // we can just return.
+ if ((currentExportedBlame == null)
+ && (currentImportedBlame == null)
+ && (currentRequiredBlames == 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 " + sourceBlame);
+// usedCaps.add(new Blame(candBlame.m_reqs,
sourceBlame.m_cap));
+ usedCaps.add(sourceBlame);
+ return;
+ }
+ else if ((currentExportedBlame != null)
+ && !isCompatible(currentExportedBlame.m_cap,
sourceBlame.m_cap, modulePkgMap))
+ {
+ throw new ResolveException("Constraint violation for
package '" + usedPkgName
+ + "' when resolving module " + current
+ + " between existing constraint "
+ + currentExportedBlame
+ + " and candidate constraint "
+ + sourceBlame);
+ }
+ else if ((currentImportedBlame != null)
+ && !isCompatible(currentImportedBlame.m_cap,
sourceBlame.m_cap, modulePkgMap))
+ {
+System.out.println("+++ CIB " + currentImportedBlame + " SB " + sourceBlame);
+ // Try to remove the previously selected candidate
associated
+ // with the requirement blamed for adding the constraint.
This
+ // Permutate the candidate map.
+ if (currentImportedBlame.m_reqs.size() != 0)
+ {
+ // Permutate the candidate map.
+ for (int reqIdx = 0; reqIdx <
currentImportedBlame.m_reqs.size(); reqIdx++)
+ {
+ Map<Requirement, Set<Capability>> copy =
copyCandidateMap(candidateMap);
+ Set<Capability> candidates =
+
copy.get(currentImportedBlame.m_reqs.get(reqIdx));
+ Iterator it = candidates.iterator();
+ it.next();
+ it.remove();
+// TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy.
+ if (candidates.size() > 0)
+ {
+ m_candidatePermutations.add(copy);
+ }
+ }
+ }
+
+ throw new ResolveException("Constraint violation for
package '" + usedPkgName
+ + "' when resolving module " + current
+ + " between existing constraint "
+ + currentImportedBlame
+ + " and candidate constraint "
+ + sourceBlame);
+ }
+
+ // Verify the candidate's uses constraints do not conflict.
+ verifyAndMergeUses(current, currentPkgs, sourceBlame,
modulePkgMap, candidateMap);
+ }
+ }
+ }
+
+ private static boolean isCompatible(
+ Capability currentCap, Capability candCap, Map<Module, Packages>
modulePkgMap)
+ {
+ if ((currentCap != null) && (candCap != null))
+ {
+ List<Capability> currentSources = getPackageSources(currentCap,
modulePkgMap);
+ List<Capability> candSources = getPackageSources(candCap,
modulePkgMap);
+System.out.println("+++ currentSources " + currentSources + " - candSources "
+ candSources);
+ return currentSources.containsAll(candSources) ||
candSources.containsAll(currentSources);
+ }
+ return true;
+ }
+
+ private static List<Capability> getPackageSources(
+ Capability cap, Map<Module, Packages> modulePkgMap)
+ {
+ List<Capability> sources = null;
+ if (cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ Packages pkgs = modulePkgMap.get(cap.getModule());
+ sources = new ArrayList<Capability>();
+ sources.add(cap);
+ String pkgName =
cap.getAttribute(Capability.PACKAGE_ATTR).getValue().toString();
+ List<Blame> required = pkgs.m_requiredPkgs.get(pkgName);
+ if (required != null)
+ {
+ for (Blame blame : required)
+ {
+ sources.add(blame.m_cap);
+ }
+ }
+ }
+ return sources;
+ }
+
+ private static Map<Requirement, Set<Capability>> copyCandidateMap(
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ Map<Requirement, Set<Capability>> copy =
+ new HashMap<Requirement, Set<Capability>>();
+ for (Entry<Requirement, Set<Capability>> entry :
candidateMap.entrySet())
+ {
+ Set<Capability> candidates = createCandidateSet();
+ candidates.addAll(entry.getValue());
+ copy.put(entry.getKey(), candidates);
+ }
+ return copy;
+ }
+
+ private 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 Packages()
+ {
+ }
+
+ public Packages(Packages packages)
+ {
+ m_exportedPkgs.putAll(packages.m_exportedPkgs);
+ m_importedPkgs.putAll(packages.m_importedPkgs);
+ m_requiredPkgs.putAll(packages.m_requiredPkgs);
+ m_usedPkgs.putAll(packages.m_usedPkgs);
+ }
+ }
+
+ private class Blame
+ {
+ public final List<Requirement> m_reqs;
+ public final Capability m_cap;
+
+ public Blame(List<Requirement> reqs, Capability cap)
+ {
+ m_reqs = reqs;
+ m_cap = cap;
+ }
+
+ public String toString()
+ {
+ return m_cap.getModule() + "." +
m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue()
+ + " BLAMED ON " + m_reqs;
+ }
+
+ public boolean equals(Object o)
+ {
+ return (o instanceof Blame) && m_reqs.equals(((Blame) o).m_reqs)
+ && m_cap.equals(((Blame) o).m_cap);
+ }
+ }
+}
\ No newline at end of file