felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rickh...@apache.org
Subject svn commit: r893287 - in /felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver: Main.java proto2/ proto2/Proto2Resolver.java
Date Tue, 22 Dec 2009 19:44:53 GMT
Author: rickhall
Date: Tue Dec 22 19:44:53 2009
New Revision: 893287

URL: http://svn.apache.org/viewvc?rev=893287&view=rev
Log:
Rewrite of new resolver algorithm to try to clean it up and make it
work better for require-bundle.

Added:
    felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto2/
    felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto2/Proto2Resolver.java
Modified:
    felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/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=893287&r1=893286&r2=893287&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 Tue
Dec 22 19:44:53 2009
@@ -27,6 +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.prototype.ProtoResolver;
 
 public class Main
@@ -37,18 +38,23 @@
     {
         if (args.length > 2)
         {
-            System.out.println("[-legacy] [scenario-number]");
+            System.out.println("[-legacy | -proto] [scenario-number]");
             System.exit(0);
         }
 
         String scenario = "1";
         boolean legacy = false;
+        boolean proto = false;
         for (int i = 0; i < args.length; i++)
         {
             if (args[i].equals("-legacy"))
             {
                 legacy = true;
             }
+            else if (args[i].equals("-proto"))
+            {
+                legacy = true;
+            }
             else
             {
                 scenario = args[i];
@@ -58,7 +64,19 @@
         List<Module> moduleList = new ArrayList<Module>();
         Module targetModule = setupScenario(moduleList, scenario);
 
-        Resolver resolver = (legacy) ? new FelixResolver(moduleList) : new ProtoResolver(moduleList);
+        Resolver resolver = null;
+        if (legacy)
+        {
+            resolver = new FelixResolver(moduleList);
+        }
+        else if (proto)
+        {
+            resolver = new ProtoResolver(moduleList);
+        }
+        else
+        {
+            resolver = new Proto2Resolver(moduleList);
+        }
 
         try
         {
@@ -101,7 +119,7 @@
 
     // SOLUTION:
     // A: bar->B, baz->E
-    // B: woz->D
+    // B: woz->C
     // E: dit->F
     private static Module scenario1(List<Module> moduleList)
     {
@@ -143,7 +161,7 @@
     }
 
     // SOLUTION:
-    // A: bar->B, woz->E
+    // A: bar->B, woz->C
     private static Module scenario2(List<Module> moduleList)
     {
         Module m, target;
@@ -611,7 +629,8 @@
         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").using("foo"))
+//                .providing(new CapabilityImpl(m, Capability.PACKAGE_NAMESPACE).with("package=bar").using("foo"))
+                .providing(new CapabilityImpl(m, Capability.PACKAGE_NAMESPACE).with("package=bar"))
                 .requiring(new RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=foo").with("version=[1.0.0,2.0.0)")));
         // Bundle C
         moduleList.add(
@@ -622,7 +641,8 @@
         // Bundle D
         moduleList.add(
             (m = new Module("D"))
-                .providing(new CapabilityImpl(m, Capability.PACKAGE_NAMESPACE).with("package=foo").with("version=1.0.0")));
+                .providing(new CapabilityImpl(m, Capability.PACKAGE_NAMESPACE).with("package=foo").with("version=1.0.0"))
+                .providing(new CapabilityImpl(m, Capability.PACKAGE_NAMESPACE).with("package=woz").with("version=1.0.0")));
         // Bundle E
         moduleList.add(
             (m = new Module("E"))
@@ -630,4 +650,36 @@
 
         return target;
     }
+
+    private static Module scenario13(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=bar"))
+                .requiring(new RequirementImpl(Capability.PACKAGE_NAMESPACE).with("package=woz")));
+        // 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")));
+        // 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")));
+        // Bundle D
+        moduleList.add(
+            (m = new Module("D"))
+                .providing(new CapabilityImpl(m, Capability.PACKAGE_NAMESPACE).with("package=woz").with("version=1.0.0")));
+        // Bundle E
+        moduleList.add(
+            (m = new Module("E"))
+                .providing(new CapabilityImpl(m, Capability.PACKAGE_NAMESPACE).with("package=woz").with("version=2.0.0")));
+
+        return target;
+    }
 }
\ No newline at end of file

Added: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto2/Proto2Resolver.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto2/Proto2Resolver.java?rev=893287&view=auto
==============================================================================
--- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto2/Proto2Resolver.java
(added)
+++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/proto2/Proto2Resolver.java
Tue Dec 22 19:44:53 2009
@@ -0,0 +1,587 @@
+/*
+ *  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.proto2;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+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 Proto2Resolver 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 Proto2Resolver(List<Module> modules)
+    {
+System.out.println("+++ PROTO2 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);
+    }
+
+    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);
+        }
+
+        Map<Module, Packages> modulePkgMap;
+        resolveRoot(
+            module,
+            new HashMap<Requirement, Set<Capability>>(),
+            modulePkgMap = new HashMap<Module, Packages>(),
+            new HashMap<Module, Object>());
+
+dumpModulePkgMap(modulePkgMap);
+
+        return null;
+    }
+
+    private 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 void dumpModulePkgs(Module module, Packages packages)
+    {
+        System.out.println(module);
+        System.out.println("  EXPORTED");
+        for (Entry<String, Constraint> entry : packages.m_exportedPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+        System.out.println("  IMPORTED");
+        for (Entry<String, Constraint> entry : packages.m_importedPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+        System.out.println("  REQUIRED");
+        for (Entry<String, Constraint> entry : packages.m_requiredPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+        System.out.println("  USED");
+        for (Entry<String, List<Constraint>> entry : packages.m_usedPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+    }
+
+    private void resolveRoot(
+        Module module, 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 (!module.isResolved())
+        {
+            if (cycleMap.containsKey(module))
+            {
+                return;
+            }
+            cycleMap.put(module, module);
+System.out.println("+++ RESOLVING " + module);
+            calculateExportedPackages(module, modulePkgMap);
+
+            populateCandidates(module, candidateMap);
+
+            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;
+                }
+                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.
+                        resolveRoot(candCap.getModule(), candidateMap, modulePkgMap, cycleMap);
+
+                        // If we are here, the candidate resolved. Try to merge
+                        // the candidate's into the target module's packages.
+                        mergeCandidatePackages(module, candCap, modulePkgMap);
+
+                        // 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 mergeCandidatePackages(
+        Module current, Capability candCap, 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 (candCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+        {
+System.out.println("+++ MERGING " + candCap + " INTO " + current);
+            String pkgName = (String)
+                candCap.getAttribute(Capability.PACKAGE_ATTR).getValue();
+
+            Packages candPkgs = modulePkgMap.get(candCap.getModule());
+            Constraint candConstraint = candPkgs.m_exportedPkgs.get(pkgName);
+
+            Packages currentPkgs = modulePkgMap.get(current);
+            Constraint currentExportedConstraint = currentPkgs.m_exportedPkgs.get(pkgName);
+            Constraint currentImportedConstraint = currentPkgs.m_importedPkgs.get(pkgName);
+            Constraint currentRequiredConstraint = currentPkgs.m_requiredPkgs.get(pkgName);
+
+            if (((currentExportedConstraint != null)
+                    && !currentExportedConstraint.m_sources.containsAll(candConstraint.m_sources))
+                || ((currentImportedConstraint != null)
+                    && !currentImportedConstraint.m_sources.containsAll(candConstraint.m_sources))
+                || ((currentRequiredConstraint != null)
+                    && !currentRequiredConstraint.m_sources.containsAll(candConstraint.m_sources)))
+            {
+                throw new ResolveException("Constraint violation between "
+                    + current + " and " + candCap.getModule()
+                    + " for " + pkgName);
+            }
+
+            List<Constraint> currentUsedSources = currentPkgs.m_usedPkgs.get(pkgName);
+            checkExistingUsesConstraints(current, pkgName, currentUsedSources, candConstraint);
+
+            Packages currentPkgsCopy = new Packages(currentPkgs);
+
+            // Add the candidate package to the current set of packages.
+            currentPkgsCopy.m_importedPkgs.put(pkgName, candConstraint);
+
+            // Verify the candidate's uses constraints do not conflict.
+            for (Capability cap : candConstraint.m_sources)
+            {
+                for (String usedPkg : cap.getUses())
+                {
+                    verifyUses(current, currentPkgsCopy, candCap, modulePkgMap, usedPkg);
+                }
+            }
+
+            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<Constraint> existingConstraints,
+        Constraint candConstraint)
+    {
+if (pkgName.equals("foo"))
+{
+    System.out.println("+++ CHECKING " + pkgName + " - " + existingConstraints + " - " +
candConstraint.m_sources);
+}
+        for (int i = 0; (existingConstraints != null) && (i < existingConstraints.size());
i++)
+        {
+            if (!existingConstraints.get(i).m_sources.containsAll(candConstraint.m_sources))
+            {
+                throw new ResolveException("Constraint violation for package '" + pkgName
+                    + "' when resolving module " + current
+                    + " between existing constraint "
+                    + existingConstraints.get(i).m_capability.getModule()
+                    + " " + existingConstraints.get(i).m_sources
+                    + " and candidate constraint " + candConstraint.m_capability.getModule()
+                    + " " + candConstraint.m_sources);
+            }
+        }
+    }
+
+// TODO: PROTO2 RESOLVER - We end up with duplicates in uses constraints,
+//       see scenario 2 for an example.
+    private void verifyUses(
+        Module current, Packages currentPkgs,
+        Capability candCap, Map<Module, Packages> modulePkgMap,
+        String pkgName)
+    {
+        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);
+        }
+        Constraint currentExportedConstraint = currentPkgs.m_exportedPkgs.get(pkgName);
+        Constraint currentImportedConstraint = currentPkgs.m_importedPkgs.get(pkgName);
+        Constraint currentRequiredConstraint = currentPkgs.m_requiredPkgs.get(pkgName);
+
+        Packages candPkgs = modulePkgMap.get(candCap.getModule());
+        Constraint candConstraint = candPkgs.m_exportedPkgs.get(pkgName);
+        candConstraint = (candConstraint != null)
+            ? candConstraint
+            : candPkgs.m_importedPkgs.get(pkgName);
+        candConstraint = (candConstraint != null)
+            ? candConstraint
+            : candPkgs.m_requiredPkgs.get(pkgName);
+
+        // 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 (candConstraint == null)
+        {
+            return;
+        }
+
+        // If there is no current mapping for this package, then
+        // we can just return.
+        if ((currentExportedConstraint == null)
+            && (currentImportedConstraint == null)
+            && (currentRequiredConstraint == null))
+        {
+            List<Constraint> constraints = currentPkgs.m_usedPkgs.get(pkgName);
+            if (constraints == null)
+            {
+                constraints = new ArrayList<Constraint>();
+                currentPkgs.m_usedPkgs.put(pkgName, constraints);
+            }
+            constraints.add(candConstraint);
+            return;
+        }
+
+        if ((currentExportedConstraint != null)
+            && !currentExportedConstraint.m_sources.containsAll(candConstraint.m_sources))
+        {
+            throw new ResolveException("Constraint violation for package '" + pkgName
+                + "' when resolving module " + current
+                + " between existing constraint "
+                + currentExportedConstraint.m_capability.getModule()
+                + " " + currentExportedConstraint.m_sources
+                + " and candidate constraint " + candConstraint.m_capability.getModule()
+                + " " + candConstraint.m_sources);
+        }
+        else if ((currentImportedConstraint != null)
+            && !currentImportedConstraint.m_sources.containsAll(candConstraint.m_sources))
+        {
+            throw new ResolveException("Constraint violation for package '" + pkgName
+                + "' when resolving module " + current
+                + " between existing constraint "
+                + currentImportedConstraint.m_capability.getModule()
+                + " " + currentImportedConstraint.m_sources
+                + " and candidate constraint " + candConstraint.m_capability.getModule()
+                + " " + candConstraint.m_sources);
+        }
+
+        // Verify the candidate's uses constraints do not conflict.
+        for (Capability cap : candConstraint.m_sources)
+        {
+            for (String usedPkg : cap.getUses())
+            {
+                verifyUses(current, currentPkgs, cap, modulePkgMap, usedPkg);
+            }
+        }
+    }
+
+    private void populateCandidates(Module module, 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);
+        }
+
+        // Find candidates for all requirements for the target module.
+        List<Requirement> reqs = module.getRequirements();
+        for (Requirement req : reqs)
+        {
+            // If we are using a permutated candidate map, then the target
+            // module's candidates may have already been calculated, so use
+            // those instead, otherwise find the matching providers.
+            if (candidateMap.get(req) == null)
+            {
+                Set<Capability> candidates = findCandidates(req);
+                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);
+                }
+System.out.println("+++ " + req + " = " + candidates);
+            }
+        }
+    }
+
+    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 = 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;
+                }
+            }
+        });
+
+        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, 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)))
+                {
+                    List<Capability> sources = new ArrayList<Capability>();
+                    sources.add(caps.get(i));
+                    packages.m_exportedPkgs.put(
+                        (String) caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue(),
+                        new Constraint(caps.get(i), sources));
+                }
+            }
+        }
+
+        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 class Packages
+    {
+        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);
+        }
+
+        public final Map<String, Constraint> m_exportedPkgs
+            = new HashMap<String, Constraint>();
+        public final Map<String, Constraint> m_importedPkgs
+            = new HashMap<String, Constraint>();
+        public final Map<String, Constraint> m_requiredPkgs
+            = new HashMap<String, Constraint>();
+        public final Map<String, List<Constraint>> m_usedPkgs
+            = new HashMap<String, List<Constraint>>();
+    }
+
+    private class Constraint
+    {
+        public final Capability m_capability;
+        public final List<Capability> m_sources;
+        public Constraint(Capability capability, List<Capability> sources)
+        {
+            m_capability = capability;
+            m_sources = sources;
+        }
+
+        public String toString()
+        {
+            return m_capability + " SOURCES " + m_sources;
+        }
+    }
+}
\ No newline at end of file



Mime
View raw message