felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rickh...@apache.org
Subject svn commit: r918500 [3/4] - in /felix/trunk/framework/src/main/java/org/apache/felix: framework/ framework/capabilityset/ framework/resolver/ framework/searchpolicy/ moduleloader/
Date Wed, 03 Mar 2010 15:04:42 GMT
Copied: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java (from r915677, felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java)
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java?p2=felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java&p1=felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java&r1=915677&r2=918500&rev=918500&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java Wed Mar  3 15:04:41 2010
@@ -1,1641 +1,1422 @@
 /*
- * 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.
+ *  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.framework.searchpolicy;
+package org.apache.felix.framework.resolver;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-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.StringTokenizer;
+import java.util.TreeSet;
+import org.apache.felix.framework.FelixResolverState;
 import org.apache.felix.framework.Logger;
-import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.Capability;
-import org.apache.felix.framework.util.manifestparser.R4Attribute;
-import org.apache.felix.framework.util.manifestparser.R4Directive;
+import org.apache.felix.framework.capabilityset.Attribute;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.CapabilitySet;
+import org.apache.felix.framework.capabilityset.Directive;
+import org.apache.felix.framework.capabilityset.Requirement;
 import org.apache.felix.framework.util.manifestparser.R4Library;
-import org.apache.felix.framework.util.manifestparser.Requirement;
-import org.apache.felix.moduleloader.ICapability;
-import org.apache.felix.moduleloader.IModule;
-import org.apache.felix.moduleloader.IRequirement;
-import org.apache.felix.moduleloader.IWire;
+import org.apache.felix.framework.util.manifestparser.RequirementImpl;
 import org.osgi.framework.Constants;
 
-public class Resolver
+// 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 ResolverImpl implements Resolver
 {
     private final Logger m_logger;
 
     // Execution environment.
+// TODO: FELIX3 - Move EE checking to ResolverState interface.
     private final String m_fwkExecEnvStr;
     private final Set m_fwkExecEnvSet;
 
+    private static final Map<String, Long> m_invokeCounts = new HashMap<String, Long>();
+    private static boolean m_isInvokeCount = false;
+
     // Reusable empty array.
-    private static final IWire[] m_emptyWires = new IWire[0];
+    private static final List<Wire> m_emptyWires = new ArrayList<Wire>(0);
 
-    public Resolver(Logger logger, String fwkExecEnvStr)
+    public ResolverImpl(Logger logger, String fwkExecEnvStr)
     {
+System.out.println("+++ PROTO3 RESOLVER");
         m_logger = logger;
         m_fwkExecEnvStr = (fwkExecEnvStr != null) ? fwkExecEnvStr.trim() : null;
         m_fwkExecEnvSet = parseExecutionEnvironments(fwkExecEnvStr);
+
+        String v = System.getProperty("invoke.count");
+        m_isInvokeCount = (v == null) ? false : Boolean.valueOf(v);
     }
 
-    // Returns a map of resolved bundles where the key is the module
-    // and the value is an array of wires.
-    public Map resolve(ResolverState state, IModule rootModule) throws ResolveException
-    {
-        // If the module is already resolved, then we can just return.
-        if (rootModule.isResolved())
-        {
-            return null;
-        }
-
-        // This variable maps an unresolved module to a list of candidate
-        // sets, where there is one candidate set for each requirement that
-        // must be resolved. A candidate set contains the potential canidates
-        // available to resolve the requirement and the currently selected
-        // candidate index.
-        Map candidatesMap = new HashMap();
-
-        // The first step is to populate the candidates map. This
-        // will use the target module to populate the candidates map
-        // with all potential modules that need to be resolved as a
-        // result of resolving the target module. The key of the
-        // map is a potential module to be resolved and the value is
-        // a list of candidate sets, one for each of the module's
-        // requirements, where each candidate set contains the potential
-        // candidates for resolving the requirement. Not all modules in
-        // this map will be resolved, only the target module and
-        // any candidates selected to resolve its requirements and the
-        // transitive requirements this implies.
-        populateCandidatesMap(state, candidatesMap, rootModule);
-
-        // The next step is to use the candidates map to determine if
-        // the class space for the root module is consistent. This
-        // is an iterative process that transitively walks the "uses"
-        // relationships of all packages visible from the root module
-        // checking for conflicts. If a conflict is found, it "increments"
-        // the configuration of currently selected potential candidates
-        // and tests them again. If this method returns, then it has found
-        // a consistent set of candidates; otherwise, a resolve exception
-        // is thrown if it exhausts all possible combinations and could
-        // not find a consistent class space.
-        findConsistentClassSpace(state, candidatesMap, rootModule);
-
-        // The final step is to create the wires for the root module and
-        // transitively all modules that are to be resolved from the
-        // selected candidates for resolving the root module's imports.
-        // When this call returns, each module's wiring and resolved
-        // attributes are set. The resulting wiring map is used below
-        // to fire resolved events outside of the synchronized block.
-        // The resolved module wire map maps a module to its array of
-        // wires.
-        return populateWireMap(state, candidatesMap, rootModule, new HashMap());
-    }
-
-    // TODO: RESOLVER - Fix this return type.
-    // Return candidate wire in result[0] and wire map in result[1]
-    public Object[] resolveDynamicImport(ResolverState state, IModule importer, String pkgName)
-        throws ResolveException
+    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)
+    {
+        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, List<Wire>> wireMap = new HashMap<Module, List<Wire>>();
+
+        Map<Module, Packages> modulePkgMap = new HashMap<Module, Packages>();
+
+        if (!module.isResolved())
+        {
+            m_candidatePermutations.clear();
+
+//System.out.println("+++ RESOLVING " + module);
+            Map<Requirement, Set<Capability>> candidateMap =
+                new HashMap<Requirement, Set<Capability>>();
+
+            populateCandidates(state, module, m_fwkExecEnvStr, m_fwkExecEnvSet,
+                candidateMap, new HashMap<Module, Object>());
+            m_candidatePermutations.add(candidateMap);
+
+            ResolveException rethrow = null;
+
+            do
+            {
+                rethrow = null;
+
+                candidateMap = m_candidatePermutations.remove(0);
+//dumpCandidateMap(state, 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);
+
+            wireMap =
+                populateWireMap(module, modulePkgMap, wireMap,
+                candidateMap);
+        }
+
+        if (m_isInvokeCount)
+        {
+            System.out.println("INVOKE COUNTS " + m_invokeCounts);
+        }
+
+        return wireMap;
+    }
+
+    public Map<Module, List<Wire>> resolve(ResolverState state, Module module, String pkgName)
     {
-        ICapability candidate = null;
-        Map resolvedModuleWireMap = null;
+        Capability candidate = null;
 
         // We can only create a dynamic import if the following
         // conditions are met:
-        // 1. The package in question is not already imported.
-        // 2. The package in question is not accessible via require-bundle.
-        // 3. The package in question is not exported by the bundle.
-        // 4. The package in question matches a dynamic import of the bundle.
+        // 1. The specified module is resolved.
+        // 2. The package in question is not already imported.
+        // 3. The package in question is not accessible via require-bundle.
+        // 4. The package in question is not exported by the bundle.
+        // 5. The package in question matches a dynamic import of the bundle.
         // The following call checks all of these conditions and returns
         // a matching dynamic requirement if possible.
-        IRequirement dynReq = findAllowedDynamicImport(importer, pkgName);
-        if (dynReq != null)
+        Map<Requirement, Set<Capability>> candidateMap =
+            new HashMap<Requirement, Set<Capability>>();
+        if (isAllowedDynamicImport(state, module, pkgName, candidateMap))
         {
-            // Create a new requirement based on the dynamic requirement,
-            // but substitute the precise package name for which we are
-            // looking, because it is not possible to use the potentially
-            // wildcarded version in the dynamic requirement.
-            R4Directive[] dirs = ((Requirement) dynReq).getDirectives();
-            R4Attribute[] attrs = ((Requirement) dynReq).getAttributes();
-            R4Attribute[] newAttrs = new R4Attribute[attrs.length];
-            System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
-            for (int attrIdx = 0; attrIdx < newAttrs.length; attrIdx++)
+            m_candidatePermutations.clear();
+
+            Map<Module, List<Wire>> wireMap = new HashMap<Module, List<Wire>>();
+
+            Map<Module, Packages> modulePkgMap = new HashMap<Module, Packages>();
+
+//System.out.println("+++ DYNAMICALLY RESOLVING " + module + " - " + pkgName);
+            populateDynamicCandidates(state, module,
+                m_fwkExecEnvStr, m_fwkExecEnvSet, candidateMap);
+            m_candidatePermutations.add(candidateMap);
+            ResolveException rethrow = null;
+
+            do
             {
-                if (newAttrs[attrIdx].getName().equals(ICapability.PACKAGE_PROPERTY))
-                {
-                    newAttrs[attrIdx] = new R4Attribute(
-                        ICapability.PACKAGE_PROPERTY, pkgName, false);
-                    break;
-                }
-            }
-            IRequirement target = new Requirement(ICapability.PACKAGE_NAMESPACE, dirs, newAttrs);
+                rethrow = null;
 
-            // See if there is a candidate exporter that satisfies the
-            // constrained dynamic requirement.
-            try
-            {
-                // Get "resolved" and "unresolved" candidates and put
-                // the "resolved" candidates first.
-                List candidates = state.getResolvedCandidates(target, importer);
-                candidates.addAll(state.getUnresolvedCandidates(target, importer));
-
-                // Take the first candidate that can resolve.
-                for (int candIdx = 0;
-                    (candidate == null) && (candIdx < candidates.size());
-                    candIdx++)
+                candidateMap = m_candidatePermutations.remove(0);
+//dumpCandidateMap(state, candidateMap);
+
+                try
                 {
-                    try
-                    {
-                        // If a map is returned, then the candidate resolved
-                        // consistently with the importer.
-                        resolvedModuleWireMap =
-                            resolveDynamicImportCandidate(
-                                state, ((ICapability) candidates.get(candIdx)).getModule(),
-                                importer);
-                        if (resolvedModuleWireMap != null)
-                        {
-                            candidate = (ICapability) candidates.get(candIdx);
-                        }
-                    }
-                    catch (ResolveException ex)
-                    {
-                        // Ignore candidates that cannot resolve.
-                    }
+                    findConsistentDynamicCandidate(
+                        module,
+                        new ArrayList(),
+                        candidateMap,
+                        modulePkgMap);
                 }
-
-                if (candidate != null)
+                catch (ResolveException ex)
                 {
-                    // Create the wire and add it to the module.
-                    Object[] result = new Object[2];
-                    result[0] = new R4Wire(
-                        importer, dynReq, candidate.getModule(),
-                        candidate);
-                    result[1] = resolvedModuleWireMap;
-                    return result;
+                    rethrow = ex;
+                    System.out.println("RE: " + ex);
                 }
             }
-            catch (Exception ex)
+            while ((rethrow != null) && (m_candidatePermutations.size() > 0));
+
+            if (rethrow != null)
             {
-                m_logger.log(Logger.LOG_ERROR, "Unable to dynamically import package.", ex);
+                throw rethrow;
             }
+//dumpModulePkgMap(modulePkgMap);
+            wireMap =
+                populateDynamicWireMap(
+                    module, pkgName, modulePkgMap, wireMap, candidateMap);
+
+//System.out.println("+++ DYNAMIC SUCCESS: " + wireMap.get(module));
+            return wireMap;
         }
 
+//System.out.println("+++ DYNAMIC FAILURE");
         return null;
     }
 
-    public static IRequirement findAllowedDynamicImport(IModule importer, String pkgName)
-    {
-        // We cannot import the default package, so return null in that case.
-        if (pkgName.length() == 0)
+    // TODO: FELIX3 - It would be nice to make this private.
+    // TODO: FELIX3 - At a minimum, figure out a different way than passing in the
+    //       candidate map.
+    public static boolean isAllowedDynamicImport(
+        ResolverState state, Module module, String pkgName, Map<Requirement,
+        Set<Capability>> candidateMap)
+    {
+        // Unresolved modules cannot dynamically import, nor can the default
+        // package be dynamically imported.
+        if (!module.isResolved() || pkgName.length() == 0)
         {
-            return null;
+            return false;
         }
 
         // If any of the module exports this package, then we cannot
         // attempt to dynamically import it.
-        ICapability[] caps = importer.getCapabilities();
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
+        List<Capability> caps = module.getCapabilities();
+        for (int i = 0; (caps != null) && (i < caps.size()); i++)
         {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                && caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
+            if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+                && caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
             {
-                return null;
+                return false;
             }
         }
         // If any of our wires have this package, then we cannot
         // attempt to dynamically import it.
-        IWire[] wires = importer.getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        List<Wire> wires = module.getWires();
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
-            if (wires[i].hasPackage(pkgName))
+            if (wires.get(i).hasPackage(pkgName))
             {
-                return null;
+                return false;
             }
         }
 
         // Loop through the importer's dynamic requirements to determine if
         // there is a matching one for the package from which we want to
         // load a class.
-        IRequirement[] dynamics = importer.getDynamicRequirements();
+        List<Directive> dirs = new ArrayList(0);
+        List<Attribute> attrs = new ArrayList(1);
+        attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
+        Requirement req = new RequirementImpl(Capability.PACKAGE_NAMESPACE, dirs, attrs);
+        Set<Capability> candidates = state.getCandidates(module, req, false);
+        List<Requirement> dynamics = module.getDynamicRequirements();
+
+        // First find a dynamic requirement that matches the capabilities.
+        Requirement dynReq = null;
         for (int dynIdx = 0;
-            (dynamics != null) && (dynIdx < dynamics.length);
+            (candidates.size() > 0) && (dynReq == null) && (dynIdx < dynamics.size());
             dynIdx++)
         {
-            // First check to see if the dynamic requirement matches the
-            // package name; this means we have to do wildcard matching.
-            String dynPkgName = ((Requirement) dynamics[dynIdx]).getTargetName();
-            boolean wildcard = (dynPkgName.lastIndexOf(".*") >= 0);
-            // Remove the "*", but keep the "." if wildcarded.
-            dynPkgName = (wildcard)
-                ? dynPkgName.substring(0, dynPkgName.length() - 1) : dynPkgName;
-            // If the dynamic requirement matches the package name, then
-            // create a new requirement for the specific package.
-            if (dynPkgName.equals("*") ||
-                pkgName.equals(dynPkgName) ||
-                (wildcard && pkgName.startsWith(dynPkgName)))
+            for (Iterator<Capability> itCand = candidates.iterator();
+                (dynReq == null) && itCand.hasNext(); )
             {
-                return dynamics[dynIdx];
+                Capability cap = itCand.next();
+                if (CapabilitySet.matches(cap, dynamics.get(dynIdx).getFilter()))
+                {
+                    dynReq = dynamics.get(dynIdx);
+                }
             }
         }
 
-        return null;
-    }
-
-    private Map resolveDynamicImportCandidate(
-        ResolverState state, IModule provider, IModule importer)
-        throws ResolveException
-    {
-        // If the provider of the dynamically imported package is not
-        // resolved, then we need to calculate the candidates to resolve
-        // it and see if there is a consistent class space for the
-        // provider. If there is no consistent class space, then a resolve
-        // exception is thrown.
-        Map candidatesMap = new HashMap();
-        if (!provider.isResolved())
-        {
-            populateCandidatesMap(state, candidatesMap, provider);
-            findConsistentClassSpace(state, candidatesMap, provider);
-        }
-
-        // If the provider can be successfully resolved, then verify that
-        // its class space is consistent with the existing class space of the
-        // module that instigated the dynamic import.
-        Map moduleMap = new HashMap();
-        Map importerPkgMap = getModulePackages(moduleMap, importer, candidatesMap);
-
-        // Now we need to calculate the "uses" constraints of every package
-        // accessible to the provider module based on its current candidates.
-        Map usesMap = calculateUsesConstraints(provider, moduleMap, candidatesMap);
-
-        // Verify that none of the provider's implied "uses" constraints
-        // in the uses map conflict with anything in the importing module's
-        // package map.
-        for (Iterator iter = usesMap.entrySet().iterator(); iter.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) iter.next();
-
-            // For the given "used" package, get that package from the
-            // importing module's package map, if present.
-            ResolvedPackage rp = (ResolvedPackage) importerPkgMap.get(entry.getKey());
-
-            // If the "used" package is also visible to the importing
-            // module, make sure there is no conflicts in the implied
-            // "uses" constraints.
-            if (rp != null)
-            {
-                // Clone the resolve package so we can modify it.
-                rp = (ResolvedPackage) rp.clone();
-
-                // Loop through all implied "uses" constraints for the current
-                // "used" package and verify that all packages are
-                // compatible with the packages of the importing module's
-                // package map.
-                List constraintList = (List) entry.getValue();
-                for (int constIdx = 0; constIdx < constraintList.size(); constIdx++)
-                {
-                    // Get a specific "uses" constraint for the current "used"
-                    // package.
-                    ResolvedPackage rpUses = (ResolvedPackage) constraintList.get(constIdx);
-                    // Determine if the implied "uses" constraint is compatible with
-                    // the improting module's packages for the given "used"
-                    // package. They are compatible if one is the subset of the other.
-                    // Retain the union of the two sets if they are compatible.
-                    if (rpUses.isSubset(rp))
-                    {
-                        // Do nothing because we already have the superset.
-                    }
-                    else if (rp.isSubset(rpUses))
-                    {
-                        // Keep the superset, i.e., the union.
-                        rp.m_capList.clear();
-                        rp.m_capList.addAll(rpUses.m_capList);
-                    }
-                    else
-                    {
-                        m_logger.log(
-                            Logger.LOG_DEBUG,
-                            "Constraint violation for " + importer
-                            + " detected; module can see "
-                            + rp + " and " + rpUses);
-                        return null;
-                    }
+        // If we found a matching dynamic requirement, then filter out
+        // any candidates that do not match it.
+        if (dynReq != null)
+        {
+            for (Iterator<Capability> itCand = candidates.iterator(); itCand.hasNext(); )
+            {
+                Capability cap = itCand.next();
+                if (!CapabilitySet.matches(cap, dynReq.getFilter()))
+                {
+                    itCand.remove();
                 }
             }
+            
+            if (candidates.size() > 0)
+            {
+                candidateMap.put(dynReq, candidates);
+            }
+        }
+        else
+        {
+            candidates.clear();
         }
 
-        return populateWireMap(state, candidatesMap, provider, new HashMap());
+        return !candidates.isEmpty();
     }
 
-    private void populateCandidatesMap(
-        ResolverState state, Map candidatesMap, IModule targetModule)
-        throws ResolveException
+    private static void dumpCandidateMap(
+        ResolverState state, Map<Requirement, Set<Capability>> candidateMap)
     {
-        // Detect cycles.
-        if (candidatesMap.containsKey(targetModule))
+        System.out.println("=== BEGIN CANDIDATE MAP ===");
+        for (Module module : ((FelixResolverState) state).getModules())
         {
-            return;
-        }
-
-        // Verify that any required execution environment is satisfied.
-        verifyExecutionEnvironment(m_fwkExecEnvStr, m_fwkExecEnvSet, targetModule);
-
-        // Verify that any native libraries match the current platform.
-        verifyNativeLibraries(targetModule);
-
-        // Finally, resolve any dependencies the module may have.
-
-        // Add target module to the candidates map so we can detect cycles.
-        candidatesMap.put(targetModule, null);
-
-        // Create list to hold the resolving candidate sets for the target
-        // module's requirements.
-        List candSetList = new ArrayList();
-
-        // Loop through each requirement and calculate its resolving
-        // set of candidates.
-        IRequirement[] reqs = targetModule.getRequirements();
-        for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
-        {
-            // Get the candidates from the "resolved" and "unresolved"
-            // package maps. The "resolved" candidates have higher priority
-            // than "unresolved" ones, so put the "resolved" candidates
-            // at the front of the list of candidates.
-            List candidates = state.getResolvedCandidates(reqs[reqIdx], targetModule);
-            candidates.addAll(state.getUnresolvedCandidates(reqs[reqIdx], targetModule));
-
-            // If we have candidates, then we need to recursively populate
-            // the resolver map with each of them.
-            ResolveException rethrow = null;
-            if (candidates.size() > 0)
+            System.out.println("  " + module
+                 + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
+            for (Requirement req : module.getRequirements())
             {
-                for (Iterator it = candidates.iterator(); it.hasNext(); )
+                Set<Capability> candidates = candidateMap.get(req);
+                if ((candidates != null) && (candidates.size() > 0))
                 {
-                    ICapability candidate = (ICapability) it.next();
-
-                    try
-                    {
-                        // Only populate the resolver map with modules that
-                        // are not already resolved.
-                        if (!candidate.getModule().isResolved())
-                        {
-                            populateCandidatesMap(
-                                state, candidatesMap, candidate.getModule());
-                        }
-                    }
-                    catch (ResolveException ex)
-                    {
-                        // If we received a resolve exception, then the
-                        // current candidate is not resolvable for some
-                        // reason and should be removed from the list of
-                        // candidates. For now, just null it.
-                        it.remove();
-                        rethrow = ex;
-                    }
+                    System.out.println("    " + req + ": " + candidates);
                 }
             }
-
-            // If no candidates exist at this point, then throw a
-            // resolve exception unless the import is optional.
-            if ((candidates.size() == 0) && !reqs[reqIdx].isOptional())
-            {
-                // Remove invalid candidate and any cycle byproduct resolved modules.
-                removeInvalidCandidate(targetModule, candidatesMap, new ArrayList());
-
-                // If we have received an exception while trying to populate
-                // the candidates map, rethrow that exception since it might
-                // be useful. NOTE: This is not necessarily the "only"
-                // correct exception, since it is possible that multiple
-                // candidates were not resolvable, but it is better than
-                // nothing.
-                if (rethrow != null)
-                {
-                    throw rethrow;
-                }
-                else
+            for (Requirement req : module.getDynamicRequirements())
+            {
+                Set<Capability> candidates = candidateMap.get(req);
+                if ((candidates != null) && (candidates.size() > 0))
                 {
-                    throw new ResolveException(
-                        "Unable to resolve.", targetModule, reqs[reqIdx]);
+                    System.out.println("    " + req + ": " + candidates);
                 }
             }
-            else if (candidates.size() > 0)
-            {
-                candSetList.add(
-                    new CandidateSet(targetModule, reqs[reqIdx], candidates));
-            }
         }
-
-        // Now that the module's candidates have been calculated, add the
-        // candidate set list to the candidates map to be used for calculating
-        // uses constraints and ultimately wires.
-        candidatesMap.put(targetModule, candSetList);
+        System.out.println("=== END CANDIDATE MAP ===");
     }
 
-    private static void removeInvalidCandidate(
-        IModule invalidModule, Map candidatesMap, List invalidList)
+    private static void dumpModulePkgMap(Map<Module, Packages> modulePkgMap)
     {
-// TODO: PERFORMANCE - This could be quicker if we kept track of who depended on whom,
-//       or only those modules used as candidates or those in a cycle.
+        System.out.println("+++MODULE PKG MAP+++");
+        for (Entry<Module, Packages> entry : modulePkgMap.entrySet())
+        {
+            dumpModulePkgs(entry.getKey(), entry.getValue());
+        }
+    }
 
-        // Remove the invalid module's  candidates set list from the candidates map,
-        // since it should only contain entries for validly resolved modules.
-        candidatesMap.remove(invalidModule);
+    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());
+        }
+    }
 
-        // Loop through each candidate set list in the candidates map to try
-        // to find references to the invalid module.
-        for (Iterator itCandidatesMap = candidatesMap.entrySet().iterator();
-            itCandidatesMap.hasNext(); )
+    private static void populateCandidates(
+        ResolverState state, Module module, String fwkExecEnvStr, Set fwkExecEnvSet,
+        Map<Requirement, Set<Capability>> candidateMap, Map<Module, Object> resultCache)
+    {
+        if (m_isInvokeCount)
         {
-            Map.Entry entry = (Map.Entry) itCandidatesMap.next();
-            IModule module = (IModule) entry.getKey();
-            List candSetList = (List) entry.getValue();
-            if (candSetList != null)
-            {
-                // Loop through each candidate set in the candidate set list
-                // to search for the invalid module.
-                for (Iterator itCandSetList = candSetList.iterator(); itCandSetList.hasNext(); )
-                {
-                    // Loop through the candidate in the candidate set and remove
-                    // the invalid module if it is found.
-                    CandidateSet cs = (CandidateSet) itCandSetList.next();
-                    for (Iterator itCandidates = cs.m_candidates.iterator();
-                        itCandidates.hasNext(); )
-                    {
-                        // If the invalid module is a candidate, then remove it from
-                        // the candidate set.
-                        ICapability candCap = (ICapability) itCandidates.next();
-                        if (candCap.getModule().equals(invalidModule))
-                        {
-                            itCandidates.remove();
+            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 there are no more candidates in the candidate set, then
-                            // remove it from the candidate set list.
-                            if (cs.m_candidates.size() == 0)
-                            {
-                                itCandSetList.remove();
+        // Determine if we've already calculated this module's candidates.
+        // The result cache will have one of three values:
+        //   1. A resolve exception if we've already attempted to populate the
+        //      module's candidates but were unsuccessful.
+        //   2. Boolean.TRUE indicating we've already attempted to populate the
+        //      module's candidates and were successful.
+        //   3. An array containing the cycle count, current map of candidates
+        //      for already processed requirements, and a list of remaining
+        //      requirements whose candidates still need to be calculated.
+        // For case 1, rethrow the exception. For case 3, simply return immediately.
+        // For case 3, this means we have a cycle so we should continue to populate
+        // the candidate where we left off and not record any results globally
+        // until we've popped completely out of the cycle.
 
-                                // If the requirement is not optional, then add the module
-                                // to a list which will be removed after removing the current
-                                // invalid module.
-                                if (!cs.m_requirement.isOptional() && (module != invalidModule)
-                                    && !invalidList.contains(module))
-                                {
-                                    invalidList.add(module);
-                                }
-                            }
-                            break;
-                        }
-                    }
-                }
-            }
-        }
+        // Keeps track of the number of times we've reentered this method
+        // for the current module.
+        Integer cycleCount = null;
+
+        // Keeps track of the candidates we've already calculated for the
+        // current module's requirements.
+        Map<Requirement, Set<Capability>> localCandidateMap = null;
+
+        // Keeps track of the current module's requirements for which we
+        // haven't yet found candidates.
+        List<Requirement> remainingReqs = null;
+
+        // Get the cache value for the current module.
+        Object cacheValue = resultCache.get(module);
 
-        if (!invalidList.isEmpty())
+        // This is case 1.
+        if (cacheValue instanceof ResolveException)
         {
-            while (!invalidList.isEmpty())
-            {
-                IModule m = (IModule) invalidList.remove(0);
-                removeInvalidCandidate(m, candidatesMap, invalidList);
-            }
+            throw (ResolveException) cacheValue;
+        }
+        // This is case 2.
+        else if (cacheValue instanceof Boolean)
+        {
+            return;
+        }
+        // This is case 3.
+        else if (cacheValue != null)
+        {
+            cycleCount = (Integer) ((Object[]) cacheValue)[0];
+            ((Object[]) cacheValue)[0] = new Integer(cycleCount.intValue() + 1);
+            cycleCount = (Integer) ((Object[]) cacheValue)[0];
+            localCandidateMap = (Map) ((Object[]) cacheValue)[1];
+            remainingReqs = (List) ((Object[]) cacheValue)[2];
         }
-    }
 
-    // This flag indicates whether candidates have been rotated due to a
-    // "uses" constraint conflict. If so, then it is not necessary to perform
-    // a permutation, since rotating the candidates selected a new permutation.
-    // This part of an attempt to perform smarter permutations.
-    private boolean m_candidatesRotated = false;
+        // If there is no cache value for the current module, then this is
+        // the first time we are attempting to populate its candidates, so
+        // do some one-time checks and initialization.
+        if ((remainingReqs == null) && (localCandidateMap == null))
+        {
+            // Verify that any required execution environment is satisfied.
+            verifyExecutionEnvironment(fwkExecEnvStr, fwkExecEnvSet, module);
 
-    private void findConsistentClassSpace(
-        ResolverState state, Map candidatesMap, IModule rootModule)
-        throws ResolveException
-    {
-        List candidatesList = null;
+            // Verify that any native libraries match the current platform.
+            verifyNativeLibraries(module);
+
+            // Record cycle count.
+            cycleCount = new Integer(0);
 
-        // The reusable module map maps a module to a map of
-        // resolved packages that are accessible by the given
-        // module. The set of resolved packages is calculated
-        // from the current candidates of the candidates map
-        // and the module's metadata.
-        Map moduleMap = new HashMap();
-
-        // Reusable map used to test for cycles.
-        Map cycleMap = new HashMap();
-
-        // Test the current potential candidates to determine if they
-        // are consistent. Keep looping until we find a consistent
-        // set or an exception is thrown.
-        while (!isSingletonConsistent(state, rootModule, moduleMap, candidatesMap) ||
-            !isClassSpaceConsistent(rootModule, moduleMap, cycleMap, candidatesMap))
-        {
-            // The incrementCandidateConfiguration() method requires
-            // ordered access to the candidates map, so we will create
-            // a reusable list once right here.
-            if (candidatesList == null)
-            {
-                candidatesList = new ArrayList();
-                for (Iterator iter = candidatesMap.entrySet().iterator();
-                    iter.hasNext(); )
-                {
-                    Map.Entry entry = (Map.Entry) iter.next();
-                    candidatesList.add(entry.getValue());
-                }
-
-                // Sort the bundles candidate sets according to a weighting
-                // based on how many multi-candidate requirements each has.
-                // The idea is to push bundles with more potential candidate
-                // permutations to the front so we can permutate over them
-                // more quickly, since they are likely to have more issues.
-                Collections.sort(candidatesList, new Comparator() {
-                    public int compare(Object o1, Object o2)
+            // Store candidates in a local map first, just in case the module
+            // is not resolvable.
+            localCandidateMap = new HashMap();
+
+            // Create a modifiable list of the module's requirements.
+            remainingReqs = new ArrayList(module.getRequirements());
+
+            // Add these value to the result cache so we know we are
+            // in the middle of populating candidates for the current
+            // module.
+            resultCache.put(module,
+                cacheValue = new Object[] { cycleCount, localCandidateMap, remainingReqs });
+        }
+
+        // If we have requirements remaining, then find candidates for them.
+        while (remainingReqs.size() > 0)
+        {
+            Requirement req = remainingReqs.remove(0);
+
+            // Get satisfying candidates and populate their candidates if necessary.
+            Set<Capability> candidates = state.getCandidates(module, req, true);
+            for (Iterator<Capability> itCandCap = candidates.iterator(); itCandCap.hasNext(); )
+            {
+                Capability candCap = itCandCap.next();
+                if (!candCap.getModule().isResolved())
+                {
+                    try
                     {
-                        int w1 = calculateWeight((List) o1);
-                        int w2 = calculateWeight((List) o2);
-                        if (w1 < w2)
-                        {
-                            return -1;
-                        }
-                        else if (w1 > w2)
-                        {
-                            return 1;
-                        }
-                        return 0;
+                        populateCandidates(state, candCap.getModule(),
+                            fwkExecEnvStr, fwkExecEnvSet, candidateMap, resultCache);
                     }
-
-                    private int calculateWeight(List candSetList)
+                    catch (ResolveException ex)
                     {
-                        int weight = 0;
-                        for (int csIdx = 0; csIdx < candSetList.size(); csIdx++)
-                        {
-                            CandidateSet cs = (CandidateSet) candSetList.get(csIdx);
-                            if ((cs.m_candidates != null) && (cs.m_candidates.size() > 1))
-                            {
-                                weight += cs.m_candidates.size();
-                            }
-                        }
-                        return -weight;
+System.out.println("RE: Candidate not resolveable: " + ex);
+                        // Remove the candidate since we weren't able to
+                        // populate its candidates.
+                        itCandCap.remove();
                     }
-                });
+                }
             }
 
-            // Increment the candidate configuration to a new permutation so
-            // we can test again, unless some candidates have been rotated.
-            // In that case, we re-test the current permutation, since rotating
-            // the candidates effectively selects a new permutation.
-            if (!m_candidatesRotated)
+            // If there are no candidates for the current requirement
+            // and it is not optional, then create, cache, and throw
+            // a resolve exception.
+            if ((candidates.size() == 0) && !req.isOptional())
             {
-                incrementCandidateConfiguration(candidatesList);
+                ResolveException ex =
+                    new ResolveException("Unable to resolve " + module
+                        + ": missing requirement " + req, module, req);
+                resultCache.put(module, ex);
+                throw ex;
             }
-            else
+            // If we actually have candidates for the requirement, then
+            // add them to the local candidate map.
+            else if (candidates.size() > 0)
             {
-                m_candidatesRotated = false;
+                localCandidateMap.put(req, candidates);
             }
-
-            // Clear the module map.
-            moduleMap.clear();
-
-            // Clear the cycle map.
-            cycleMap.clear();
         }
-    }
 
-    /**
-     * This methd checks to see if the target module and any of the candidate
-     * modules to resolve its dependencies violate any singleton constraints.
-     * Actually, it just creates a map of resolved singleton modules and then
-     * delegates all checking to another recursive method.
-     *
-     * @param targetModule the module that is the root of the tree of modules to check.
-     * @param moduleMap a map to cache the package space of each module.
-     * @param candidatesMap a map containing the all candidates to resolve all
-     *        dependencies for all modules.
-     * @return <tt>true</tt> if all candidates are consistent with respect to singletons,
-     *         <tt>false</tt> otherwise.
-    **/
-    private boolean isSingletonConsistent(
-        ResolverState state, IModule targetModule, Map moduleMap, Map candidatesMap)
-    {
-        // Create a map of all resolved singleton modules.
-        Map singletonMap = new HashMap();
-        IModule[] modules = state.getModules();
-        for (int i = 0; (modules != null) && (i < modules.length); i++)
+        // If we are exiting from a cycle then decrement
+        // cycle counter, otherwise record the result.
+        if (cycleCount.intValue() > 0)
         {
-            if (modules[i].isResolved() && isSingleton(modules[i]))
+            ((Object[]) cacheValue)[0] = new Integer(cycleCount.intValue() - 1);
+        }
+        else if (cycleCount.intValue() == 0)
+        {
+            // Record that the module was successfully populated.
+            resultCache.put(module, Boolean.TRUE);
+
+            // Merge local candidate map into global candidate map.
+            if (localCandidateMap.size() > 0)
             {
-                String symName = modules[i].getSymbolicName();
-                singletonMap.put(symName, symName);
+                candidateMap.putAll(localCandidateMap);
             }
         }
-
-        return areCandidatesSingletonConsistent(
-            state, targetModule, singletonMap, moduleMap, new HashMap(), candidatesMap);
     }
 
-    /**
-     * This method recursive checks the target module and all of its transitive
-     * dependency modules to verify that they do not violate a singleton constraint.
-     * If the target module is a singleton, then it checks that againts existing
-     * singletons. Then it checks all current unresolved candidates recursively.
-     *
-     * @param targetModule the module that is the root of the tree of modules to check.
-     * @param singletonMap the current map of singleton symbolic names.
-     * @param moduleMap a map to cache the package space of each module.
-     * @param cycleMap a map to detect cycles.
-     * @param candidatesMap a map containing the all candidates to resolve all
-     *        dependencies for all modules.
-     * @return <tt>true</tt> if all candidates are consistent with respect to singletons,
-     *         <tt>false</tt> otherwise.
-    **/
-    private boolean areCandidatesSingletonConsistent(
-        ResolverState state, IModule targetModule,
-        Map singletonMap, Map moduleMap, Map cycleMap, Map candidatesMap)
+    private static void populateDynamicCandidates(
+        ResolverState state, Module module,
+        String fwkExecEnvStr, Set fwkExecEnvSet,
+        Map<Requirement, Set<Capability>> candidateMap)
     {
-        // If we are in a cycle, then assume true for now.
-        if (cycleMap.get(targetModule) != null)
+        if (m_isInvokeCount)
         {
-            return true;
+            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);
         }
 
-        // Record the target module in the cycle map.
-        cycleMap.put(targetModule, targetModule);
-
-        // Check to see if the targetModule violates a singleton.
-        // If not and it is a singleton, then add it to the singleton
-        // map since it will constrain other singletons.
-        String symName = targetModule.getSymbolicName();
-        boolean isSingleton = isSingleton(targetModule);
-        if (isSingleton && singletonMap.containsKey(symName))
+        // There should be one entry in the candidate map, which are the
+        // the candidates for the matching dynamic requirement. Get the
+        // matching candidates and populate their candidates if necessary.
+        Entry<Requirement, Set<Capability>> entry = candidateMap.entrySet().iterator().next();
+        Requirement dynReq = entry.getKey();
+        Set<Capability> candidates = entry.getValue();
+        for (Iterator<Capability> itCandCap = candidates.iterator(); itCandCap.hasNext(); )
         {
-            return false;
+            Capability candCap = itCandCap.next();
+            if (!candCap.getModule().isResolved())
+            {
+                try
+                {
+                    populateCandidates(state, candCap.getModule(),
+                        fwkExecEnvStr, fwkExecEnvSet, candidateMap,
+                        new HashMap<Module, Object>());
+                }
+                catch (ResolveException ex)
+                {
+System.out.println("RE: Candidate not resolveable: " + ex);
+                    itCandCap.remove();
+                }
+            }
         }
-        else if (isSingleton)
+
+// TODO: FELIX3 - Since we reuse the same dynamic requirement, is it possible
+//       that some sort of cycle could cause us to try to match another set
+//       of candidates to the same requirement?
+        if (candidates.size() == 0)
         {
-            singletonMap.put(symName, symName);
+            candidateMap.remove(dynReq);
+            throw new ResolveException("Dynamic import failed.", module, dynReq);
         }
 
-        // Get the package space of the target module.
-        Map pkgMap = null;
-        try
+        // Add existing wires as candidates.
+        for (Wire wire : module.getWires())
         {
-            pkgMap = getModulePackages(moduleMap, targetModule, candidatesMap);
+            Set<Capability> cs = new TreeSet();
+            cs.add(wire.getCapability());
+            candidateMap.put(wire.getRequirement(), cs);
         }
-        catch (ResolveException ex)
+    }
+
+    private void findConsistentCandidates(
+        Module module, List<Requirement> incomingReqs,
+        Map<Requirement, Set<Capability>> candidateMap,
+        Map<Module, Packages> modulePkgMap,
+        Map<Module, Object> cycleMap)
+    {
+        if (m_isInvokeCount)
         {
-            m_logger.log(
-                Logger.LOG_DEBUG,
-                "Constraint violation for " + targetModule + " detected.",
-                ex);
-            return false;
+            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);
         }
 
-        // Loop through all of the target module's accessible packages and
-        // verify that all packages are consistent.
-        for (Iterator iter = pkgMap.entrySet().iterator(); iter.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) iter.next();
-            // Get the resolved package, which contains the set of all
-            // packages for the given package.
-            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
-            // Loop through each capability and test if it is consistent.
-            for (int capIdx = 0; capIdx < rp.m_capList.size(); capIdx++)
-            {
-                // If the module for this capability is not resolved, then
-                // we have to see if resolving it would violate a singleton
-                // constraint.
-                ICapability cap = (ICapability) rp.m_capList.get(capIdx);
-                if (!cap.getModule().isResolved())
-                {
-                    return areCandidatesSingletonConsistent(
-                        state, cap.getModule(), singletonMap, moduleMap, cycleMap, candidatesMap);
-                }
-            }
-        }
+        Integer cycleCount = null;
 
-        return true;
-    }
+        Object o = cycleMap.get(module);
 
-    /**
-     * Returns true if the specified module is a singleton
-     * (i.e., directive singleton:=true in Bundle-SymbolicName).
-     *
-     * @param module the module to check for singleton status.
-     * @return true if the module is a singleton, false otherwise.
-    **/
-    private static boolean isSingleton(IModule module)
-    {
-        final ICapability[] modCaps = Util.getCapabilityByNamespace(
-                module, Capability.MODULE_NAMESPACE);
-        if (modCaps == null || modCaps.length == 0)
+        if (o instanceof Boolean)
         {
-            // this should never happen?
-            return false;
+            return;
         }
-        final R4Directive[] dirs = ((Capability) modCaps[0]).getDirectives();
-        for (int dirIdx = 0; (dirs != null) && (dirIdx < dirs.length); dirIdx++)
+        else if (o == null)
         {
-            if (dirs[dirIdx].getName().equalsIgnoreCase(Constants.SINGLETON_DIRECTIVE)
-                && Boolean.valueOf(dirs[dirIdx].getValue()).booleanValue())
+            List list;
+            if (module.isResolved())
             {
-                return true;
+                list = new ArrayList(module.getWires());
+            }
+            else
+            {
+                list = new ArrayList(module.getRequirements());
             }
+            cycleMap.put(module, o = new Object[] { cycleCount = new Integer(0), list });
+            calculateExportedPackages(module, incomingReqs, modulePkgMap);
         }
-        return false;
-    }
-
-    private boolean isClassSpaceConsistent(
-        IModule targetModule, Map moduleMap, Map cycleMap, Map candidatesMap)
-    {
-//System.out.println("isClassSpaceConsistent("+targetModule+")");
-        // If we are in a cycle, then assume true for now.
-        if (cycleMap.get(targetModule) != null)
+        else
         {
-            return true;
+            cycleCount = (Integer) ((Object[]) o)[0];
+            ((Object[]) o)[0] = new Integer(cycleCount.intValue() + 1);
+            cycleCount = (Integer) ((Object[]) o)[0];
         }
 
-        // Record the target module in the cycle map.
-        cycleMap.put(targetModule, targetModule);
+//System.out.println("+++ RESOLVING " + module);
 
-        // Get the package map for the target module, which is a
-        // map of all packages accessible to the module and their
-        // associated capabilities.
-        Map pkgMap = null;
-        try
+        if (module.isResolved())
         {
-            pkgMap = getModulePackages(moduleMap, targetModule, candidatesMap);
+            List<Wire> wires = (List<Wire>) ((Object[]) o)[1];
+
+            while (wires.size() > 0)
+            {
+                Wire wire = wires.remove(0);
+
+                // Try to resolve the candidate.
+                findConsistentCandidates(
+                    wire.getCapability().getModule(),
+                    incomingReqs,
+                    candidateMap,
+                    modulePkgMap,
+                    cycleMap);
+
+                // 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);
+            }
         }
-        catch (ResolveException ex)
+        else
         {
-            m_logger.log(
-                Logger.LOG_DEBUG,
-                "Constraint violation for " + targetModule + " detected.",
-                ex);
-            return false;
-        }
+            List<Requirement> reqs = (List<Requirement>) ((Object[]) o)[1];
 
-        // Loop through all of the target module's accessible packages and
-        // verify that all packages are consistent.
-        for (Iterator iter = pkgMap.entrySet().iterator(); iter.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) iter.next();
-            // Get the resolved package, which contains the set of all
-            // capabilities for the given package.
-            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
-            // Loop through each capability and test if it is consistent.
-            for (int capIdx = 0; capIdx < rp.m_capList.size(); capIdx++)
+            while (reqs.size() > 0)
             {
-                ICapability cap = (ICapability) rp.m_capList.get(capIdx);
-                if (!isClassSpaceConsistent(cap.getModule(), moduleMap, cycleMap, candidatesMap))
+                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.
+                if (candCaps == null)
                 {
-                    return false;
+                    continue;
                 }
-            }
-        }
 
-        // Now we need to calculate the "uses" constraints of every package
-        // accessible to the target module based on the current candidates.
-        Map usesMap = null;
-        try
-        {
-            usesMap = calculateUsesConstraints(targetModule, moduleMap, candidatesMap);
-        }
-        catch (ResolveException ex)
-        {
-            m_logger.log(
-                Logger.LOG_DEBUG,
-                "Constraint violation for " + targetModule + " detected.",
-                ex);
-            return false;
-        }
+                List<Requirement> outgoingReqs = new ArrayList<Requirement>(incomingReqs);
+                outgoingReqs.add(req);
 
-        // Verify that none of the implied "uses" constraints in the uses map
-        // conflict with anything in the target module's package map.
-        for (Iterator iter = usesMap.entrySet().iterator(); iter.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) iter.next();
-
-            // For the given "used" package, get that package from the
-            // target module's package map, if present.
-            ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
-
-            // If the "used" package is also visible to the target module,
-            // make sure there is no conflicts in the implied "uses"
-            // constraints.
-            if (rp != null)
-            {
-                // Clone the resolve package so we can modify it.
-                rp = (ResolvedPackage) rp.clone();
-
-                // Loop through all implied "uses" constraints for the current
-                // "used" package and verify that all packages are
-                // compatible with the packages of the root module's
-                // package map.
-                List constraintList = (List) entry.getValue();
-                for (int constIdx = 0; constIdx < constraintList.size(); constIdx++)
-                {
-                    // Get a specific "uses" constraint for the current "used"
-                    // package.
-                    ResolvedPackage rpUses = (ResolvedPackage) constraintList.get(constIdx);
-                    // Determine if the implied "uses" constraint is compatible with
-                    // the target module's packages for the given "used"
-                    // package. They are compatible if one is the subset of the other.
-                    // Retain the union of the two sets if they are compatible.
-                    if (rpUses.isSubset(rp))
-                    {
-                        // Do nothing because we already have the superset.
-                    }
-                    else if (rp.isSubset(rpUses))
+                for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
+                {
+                    Capability candCap = it.next();
+//System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
+                    try
                     {
-                        // Keep the superset, i.e., the union.
-                        rp.m_capList.clear();
-                        rp.m_capList.addAll(rpUses.m_capList);
+                        // Try to resolve the candidate.
+                        findConsistentCandidates(
+                            candCap.getModule(),
+                            outgoingReqs,
+                            candidateMap,
+                            modulePkgMap,
+                            cycleMap);
+
+                        // 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;
                     }
-                    else
+                    catch (ResolveException ex)
                     {
-                        m_logger.log(
-                            Logger.LOG_DEBUG,
-                            "Constraint violation for " + targetModule
-                            + " detected; module can see "
-                            + rp + " and " + rpUses);
-
-                        // If the resolved package has a candidate set, then
-                        // attempt to directly rotate the candidates to fix the
-                        // "uses" constraint conflict. The idea is rather than
-                        // blinding incrementing to the next permutation, we will
-                        // try to target the permutation to the bundle with a
-                        // conflict, which in some cases will be smarter. Only
-                        // rotate the candidates if we have more than one and we
-                        // haven't already rotated them completely.
-                        if ((rp.m_cs != null) && (rp.m_cs.m_candidates.size() > 1)
-                            && (rp.m_cs.m_rotated < rp.m_cs.m_candidates.size()))
+System.out.println("RE: " + ex);
+ex.printStackTrace();
+
+// TODO: FELIX3 RESOLVER - Is it ok to remove the failed candidate? By removing
+//       it we keep the candidateMap up to date with the selected candidate, but
+//       theoretically this eliminates some potential combinations. Are those
+//       combinations guaranteed to be failures so eliminating them is ok?
+                        it.remove();
+                        if (!it.hasNext() && !req.isOptional())
                         {
-                            // Rotate candidates.
-                            ICapability first = (ICapability) rp.m_cs.m_candidates.get(0);
-                            for (int i = 1; i < rp.m_cs.m_candidates.size(); i++)
-                            {
-                                rp.m_cs.m_candidates.set(i - 1, rp.m_cs.m_candidates.get(i));
-                            }
-                            rp.m_cs.m_candidates.set(rp.m_cs.m_candidates.size() - 1, first);
-                            rp.m_cs.m_rotated++;
-                            m_candidatesRotated = true;
+                            throw new ResolveException("Unresolved constraint "
+                                + req + " in " + module, module, req);
                         }
-
-                        return false;
                     }
                 }
             }
         }
 
-        return true;
+        // 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)
+        {
+            // Record that the module was successfully populated.
+            cycleMap.put(module, Boolean.TRUE);
+        }
     }
 
-    private static Map calculateUsesConstraints(
-        IModule targetModule, Map moduleMap, Map candidatesMap)
-        throws ResolveException
-    {
-//System.out.println("calculateUsesConstraints("+targetModule+")");
-        // Map to store calculated uses constraints. This maps a
-        // package name to a list of resolved packages, where each
-        // resolved package represents a constraint on anyone
-        // importing the given package name. This map is returned
-        // by this method.
-        Map usesMap = new HashMap();
-
-        // Re-usable map to detect cycles.
-        Map cycleMap = new HashMap();
-
-        // Get all packages accessible by the target module.
-        Map pkgMap = getModulePackages(moduleMap, targetModule, candidatesMap);
-
-        // Each package accessible from the target module is potentially
-        // comprised of one or more capabilities. The "uses" constraints
-        // implied by all capabilities must be calculated and combined to
-        // determine the complete set of implied "uses" constraints for
-        // each package accessible by the target module.
-        for (Iterator iter = pkgMap.entrySet().iterator(); iter.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) iter.next();
-            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
-            for (int capIdx = 0; capIdx < rp.m_capList.size(); capIdx++)
-            {
-                usesMap = calculateUsesConstraints(
-                    (ICapability) rp.m_capList.get(capIdx),
-                    moduleMap, usesMap, cycleMap, candidatesMap);
-            }
-        }
-        return usesMap;
-    }
-
-    private static Map calculateUsesConstraints(
-        ICapability capTarget, Map moduleMap, Map usesMap,
-        Map cycleMap, Map candidatesMap)
-        throws ResolveException
+    private void findConsistentDynamicCandidate(
+        Module module, List<Requirement> incomingReqs,
+        Map<Requirement, Set<Capability>> candidateMap,
+        Map<Module, Packages> modulePkgMap)
     {
-//System.out.println("calculateUsesConstraints2("+psTarget.m_module+")");
-        // If we are in a cycle, then return for now.
-        if (cycleMap.get(capTarget) != null)
+        if (m_isInvokeCount)
         {
-            return usesMap;
+            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);
         }
 
-        // Record the target capability in the cycle map.
-        cycleMap.put(capTarget, capTarget);
+//System.out.println("+++ RESOLVING " + module);
+        calculateExportedPackages(module, incomingReqs, modulePkgMap);
 
-        // Get all packages accessible from the module of the
-        // target capability.
-        Map pkgMap = getModulePackages(moduleMap, capTarget.getModule(), candidatesMap);
-
-        // Cast to implementation class to get access to cached data.
-        Capability cap = (Capability) capTarget;
-
-        // Loop through all "used" packages of the capability.
-        for (int i = 0; i < cap.getUses().length; i++)
+        List<Requirement> reqs = new ArrayList(module.getRequirements());
+        reqs.addAll(module.getDynamicRequirements());
+        for (Requirement req : reqs)
         {
-            // The target capability's module should have a resolved package
-            // for the "used" package in its set of accessible packages,
-            // since it claims to use it, so get the associated resolved
-            // package.
-            ResolvedPackage rp = (ResolvedPackage) pkgMap.get(cap.getUses()[i]);
+            // 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);
 
-            // In general, the resolved package should not be null,
-            // but check for safety.
-            if (rp != null)
+            for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
             {
-                // First, iterate through all capabilities for the resolved
-                // package associated with the current "used" package and calculate
-                // and combine the "uses" constraints for each package.
-                for (int srcIdx = 0; srcIdx < rp.m_capList.size(); srcIdx++)
+                Capability candCap = it.next();
+//System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
+                try
                 {
-                    usesMap = calculateUsesConstraints(
-                        (ICapability) rp.m_capList.get(srcIdx),
-                        moduleMap, usesMap, cycleMap, candidatesMap);
-                }
+                    // Try to resolve the candidate.
+                    findConsistentCandidates(
+                        candCap.getModule(),
+                        outgoingReqs,
+                        candidateMap,
+                        modulePkgMap,
+                        new HashMap());
+
+                    // 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);
 
-                // Then, add the resolved package for the current "used" package
-                // as a "uses" constraint too; add it to an existing constraint
-                // list if the current "used" package is already in the uses map.
-                List constraintList = (List) usesMap.get(cap.getUses()[i]);
-                if (constraintList == null)
+                    // If we are here, we merged the candidate successfully,
+                    // so we can continue with the next requirement
+                    break;
+                }
+                catch (ResolveException ex)
                 {
-                    constraintList = new ArrayList();
+System.out.println("RE: " + ex);
+ex.printStackTrace();
+// TODO: FELIX3 RESOLVER - Is it ok to remove the failed candidate? By removing
+//       it we keep the candidateMap up to date with the selected candidate, but
+//       theoretically this eliminates some potential combinations. Are those
+//       combinations guaranteed to be failures so eliminating them is ok?
+                    it.remove();
+                    if (!it.hasNext() && !req.isOptional())
+                    {
+                        throw new ResolveException("Unresolved constraint "
+                            + req + " in " + module, module, req);
+                    }
                 }
-                constraintList.add(rp);
-                usesMap.put(cap.getUses()[i], constraintList);
             }
         }
-
-        return usesMap;
     }
 
-    private static Map getModulePackages(Map moduleMap, IModule module, Map candidatesMap)
-        throws ResolveException
+    private static void calculateExportedPackages(
+        Module module, List<Requirement> incomingReqs, Map<Module, Packages> modulePkgMap)
     {
-        Map map = (Map) moduleMap.get(module);
-
-        if (map == null)
+        if (m_isInvokeCount)
         {
-            map = calculateModulePackages(module, candidatesMap);
-            moduleMap.put(module, map);
+            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);
         }
-        return map;
-    }
 
-    /**
-     * <p>
-     * Calculates the module's set of accessible packages and their
-     * assocaited package capabilities. This method uses the current candidates
-     * for resolving the module's requirements from the candidate map
-     * to calculate the module's accessible packages.
-     * </p>
-     * @param module the module whose package map is to be calculated.
-     * @param candidatesMap the map of potential candidates for resolving
-     *        the module's requirements.
-     * @return a map of the packages accessible to the specified module where
-     *         the key of the map is the package name and the value of the map
-     *         is a ResolvedPackage.
-    **/
-    private static Map calculateModulePackages(IModule module, Map candidatesMap)
-        throws ResolveException
-    {
-//System.out.println("calculateModulePackages("+module+")");
-        Map importedPackages = calculateImportedPackages(module, candidatesMap);
-        Map exportedPackages = calculateExportedPackages(module);
-        Map requiredPackages = calculateRequiredPackages(module, candidatesMap);
-
-        // Merge exported packages into required packages. If a package is both
-        // exported and required, then append the exported package to the end of
-        // the require packages; otherwise just add it to the package map.
-        for (Iterator i = exportedPackages.entrySet().iterator(); i.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) i.next();
-            ResolvedPackage rpReq = (ResolvedPackage) requiredPackages.get(entry.getKey());
-            if (rpReq != null)
-            {
-                // Merge exported and required packages, avoiding duplicate
-                // packages and maintaining ordering.
-                ResolvedPackage rpExport = (ResolvedPackage) entry.getValue();
-                rpReq.merge(rpExport);
-            }
-            else
-            {
-                requiredPackages.put(entry.getKey(), entry.getValue());
-            }
-        }
-
-        // Merge imported packages into required packages. Imports overwrite
-        // any required and/or exported package.
-        for (Iterator i = importedPackages.entrySet().iterator(); i.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) i.next();
-            requiredPackages.put(entry.getKey(), entry.getValue());
-        }
-
-        return requiredPackages;
-    }
+        Packages packages = new Packages();
 
-    private static Map calculateImportedPackages(IModule targetModule, Map candidatesMap)
-        throws ResolveException
-    {
-        return (candidatesMap.get(targetModule) == null)
-            ? calculateImportedPackagesResolved(targetModule)
-            : calculateImportedPackagesUnresolved(targetModule, candidatesMap);
-    }
+        List<Capability> caps = module.getCapabilities();
 
-    private static Map calculateImportedPackagesUnresolved(IModule targetModule, Map candidatesMap)
-        throws ResolveException
-    {
-//System.out.println("calculateImportedPackagesUnresolved("+targetModule+")");
-        Map pkgMap = new HashMap();
-
-        // Get the candidate set list to get all candidates for
-        // all of the target module's requirements.
-        List candSetList = (List) candidatesMap.get(targetModule);
-
-        // Loop through all candidate sets that represent import dependencies
-        // for the target module and add the current candidate's packages
-        // to the imported package map.
-        for (int candSetIdx = 0;
-            (candSetList != null) && (candSetIdx < candSetList.size());
-            candSetIdx++)
+        if (caps.size() > 0)
         {
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-            ICapability candCap = (ICapability) cs.m_candidates.get(cs.m_idx);
-
-            if (candCap.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            for (int i = 0; i < caps.size(); i++)
             {
-                String pkgName = (String)
-                    candCap.getProperties().get(ICapability.PACKAGE_PROPERTY);
-
-                ResolvedPackage rp = new ResolvedPackage(pkgName, cs);
-                rp.m_capList.add(candCap);
-                pkgMap.put(rp.m_name, rp);
+// TODO: PROTO3 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)));
+                }
             }
         }
 
-        return pkgMap;
+        modulePkgMap.put(module, packages);
     }
 
-    private static Map calculateImportedPackagesResolved(IModule targetModule)
-        throws ResolveException
+    private static boolean hasOverlappingImport(Module module, Capability cap)
     {
-//System.out.println("calculateImportedPackagesResolved("+targetModule+")");
-        Map pkgMap = new HashMap();
-
-        // Loop through the target module's wires for package
-        // dependencies and add the resolved packages to the
-        // imported package map.
-        IWire[] wires = targetModule.getWires();
-        for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
+        if (m_isInvokeCount)
         {
-            if (wires[wireIdx].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                String pkgName = (String)
-                    wires[wireIdx].getCapability().getProperties().get(ICapability.PACKAGE_PROPERTY);
-                ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
-                rp = (rp == null) ? new ResolvedPackage(pkgName, null) : rp;
-                rp.m_capList.add(wires[wireIdx].getCapability());
-                pkgMap.put(rp.m_name, rp);
-            }
+            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);
         }
 
-        return pkgMap;
-    }
-
-    private static Map calculateExportedPackages(IModule targetModule)
-    {
-//System.out.println("calculateExportedPackages("+targetModule+")");
-        Map pkgMap = new HashMap();
-
-        // Loop through the target module's capabilities that represent
-        // exported packages and add them to the exported package map.
-        ICapability[] caps = targetModule.getCapabilities();
-        for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+        List<Requirement> reqs = module.getRequirements();
+        for (int i = 0; i < reqs.size(); i++)
         {
-            if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            if (reqs.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+                && CapabilitySet.matches(cap, reqs.get(i).getFilter()))
             {
-                String pkgName = (String)
-                    caps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
-                rp = (rp == null) ? new ResolvedPackage(pkgName, null) : rp;
-                rp.m_capList.add(caps[capIdx]);
-                pkgMap.put(rp.m_name, rp);
+                return true;
             }
         }
-
-        return pkgMap;
-    }
-
-    private static Map calculateRequiredPackages(IModule targetModule, Map candidatesMap)
-    {
-        return (candidatesMap.get(targetModule) == null)
-            ? calculateRequiredPackagesResolved(targetModule)
-            : calculateRequiredPackagesUnresolved(targetModule, candidatesMap);
+        return false;
     }
 
-    private static Map calculateRequiredPackagesUnresolved(IModule targetModule, Map candidatesMap)
+    private void mergeCandidatePackages(
+        Module current, List<Requirement> outgoingReqs,
+        Capability candCap, Map<Module, Packages> modulePkgMap,
+        Map<Requirement, Set<Capability>> candidateMap)
     {
-//System.out.println("calculateRequiredPackagesUnresolved("+targetModule+")");
-        Map pkgMap = new HashMap();
+        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);
+        }
 
-        // Loop through target module's candidate list for candidates
-        // for its module dependencies and merge re-exported packages.
-        List candSetList = (List) candidatesMap.get(targetModule);
-        for (int candSetIdx = 0;
-            (candSetList != null) && (candSetIdx < candSetList.size());
-            candSetIdx++)
+        if (candCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+        {
+            mergeCandidatePackage(
+                current, false, new Blame(outgoingReqs, candCap), modulePkgMap, candidateMap);
+        }
+        else if (candCap.getNamespace().equals(Capability.MODULE_NAMESPACE))
         {
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-            ICapability candCap = (ICapability) cs.m_candidates.get(cs.m_idx);
+            // Get the candidate's package space to determine which packages
+            // will be visible to the current module.
+            Packages candPkgs = modulePkgMap.get(candCap.getModule());
 
-            // If the capabaility is a module dependency, then flatten it to packages.
-            if (candCap.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+// TODO: PROTO3 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())
             {
-                // Calculate transitively required packages.
-                Map cycleMap = new HashMap();
-                cycleMap.put(targetModule, targetModule);
-                Map requireMap =
-                    calculateExportedAndReexportedPackages(
-                        candCap, candidatesMap, cycleMap);
-
-                // Take the flattened required package map for the current
-                // module dependency and merge it into the existing map
-                // of required packages.
-                for (Iterator reqIter = requireMap.entrySet().iterator(); reqIter.hasNext(); )
+                mergeCandidatePackage(
+                    current,
+                    true,
+                    new Blame(outgoingReqs, entry.getValue().m_cap),
+                    modulePkgMap,
+                    candidateMap);
+            }
+            for (Entry<String, List<Blame>> entry : candPkgs.m_requiredPkgs.entrySet())
+            {
+                List<Blame> blames = entry.getValue();
+                for (Blame blame : blames)
                 {
-                    Map.Entry entry = (Map.Entry) reqIter.next();
-                    ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
-                    if (rp != null)
+// TODO: FELIX3 RESOLVER - Since a single module requirement can include many packages,
+//       it is likely we call merge too many times for the same module req. If we knew
+//       which candidates were being used to resolve this candidate's module dependencies,
+//       then we could just try to merge them directly. This info would also help in
+//       in creating wires, since we ultimately want to create wires for the selected
+//       candidates, which we are trying to deduce from the package space, but if we
+//       knew the selected candidates, we'd be done.
+                    if (blame.m_cap.getModule().equals(current))
                     {
-                        // Merge required packages, avoiding duplicate
-                        // packages and maintaining ordering.
-                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
-                        rp.merge(rpReq);
+                        continue;
                     }
-                    else
+
+                    Directive dir = blame.m_reqs.get(blame.m_reqs.size() - 1)
+                        .getDirective(Constants.VISIBILITY_DIRECTIVE);
+                    if ((dir != null) && dir.getValue().equals(Constants.VISIBILITY_REEXPORT))
                     {
-                        pkgMap.put(entry.getKey(), entry.getValue());
+                        mergeCandidatePackage(
+                            current,
+                            true,
+                            new Blame(outgoingReqs, blame.m_cap),
+                            modulePkgMap,
+                            candidateMap);
                     }
                 }
             }
         }
-
-        return pkgMap;
     }
 
-    private static Map calculateRequiredPackagesResolved(IModule targetModule)
+    private void mergeCandidatePackage(
+        Module current, boolean requires,
+        Blame candBlame, Map<Module, Packages> modulePkgMap,
+        Map<Requirement, Set<Capability>> candidateMap)
     {
-//System.out.println("calculateRequiredPackagesResolved("+targetModule+")");
-        Map pkgMap = new HashMap();
-
-        // Loop through target module's wires for module dependencies
-        // and merge re-exported packages.
-        IWire[] wires = targetModule.getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
-        {
-            // If the wire is a module dependency, then flatten it to packages.
-            if (wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {

[... 923 lines stripped ...]


Mime
View raw message