Reimplement resolver to improve "worst case" performance. (FELIX-2037, FELIX-2035)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@918500 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
index 8f89e6e..a158306 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -19,53 +19,105 @@
 package org.apache.felix.framework;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import org.apache.felix.framework.searchpolicy.ResolveException;
-import org.apache.felix.framework.searchpolicy.Resolver;
+import java.util.Set;
+import java.util.TreeSet;
+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.resolver.Module;
+import org.apache.felix.framework.capabilityset.Requirement;
+import org.apache.felix.framework.resolver.Wire;
+import org.apache.felix.framework.resolver.CandidateComparator;
+import org.apache.felix.framework.resolver.ResolveException;
+import org.apache.felix.framework.resolver.Resolver;
 import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.VersionRange;
-import org.apache.felix.framework.util.manifestparser.R4Attribute;
-import org.apache.felix.framework.util.manifestparser.R4Directive;
-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.osgi.framework.BundlePermission;
 import org.osgi.framework.Constants;
-import org.osgi.framework.PackagePermission;
 import org.osgi.framework.Version;
 
 public class FelixResolverState implements Resolver.ResolverState
 {
     private final Logger m_logger;
     // List of all modules.
-    private final List m_moduleList = new ArrayList();
-    // Map of fragment symbolic names to list of fragment modules sorted by version.
-    private final Map m_fragmentMap = new HashMap();
-    // Maps a package name to a list of exporting capabilities.
-    private final Map m_unresolvedPkgIndex = new HashMap();
-    // Maps a package name to a list of exporting capabilities.
-    private final Map m_resolvedPkgIndex = new HashMap();
-    // Maps a module to a list of capabilities.
-    private final Map m_resolvedCapMap = new HashMap();
+    private final List<Module> m_modules;
+    // Capability set for modules.
+    private final CapabilitySet m_modCapSet;
+    // Capability set for packages.
+    private final CapabilitySet m_pkgCapSet;
+    // Capability set for hosts.
+    private final CapabilitySet m_hostCapSet;
+    // Maps fragment symbolic names to list of fragment modules sorted by version.
+    private final Map<String, List<Module>> m_fragmentMap = new HashMap();
+    // Maps singleton symbolic names to list of modules sorted by version.
+    private final Map<String, List<Module>> m_singletons = new HashMap();
 
     public FelixResolverState(Logger logger)
     {
         m_logger = logger;
+        m_modules = new ArrayList<Module>();
+
+        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);
+
+        indices = new ArrayList();
+        indices.add(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
+        m_hostCapSet = new CapabilitySet(indices);
     }
 
-    public synchronized void addModule(IModule module)
+    public synchronized void addModule(Module module)
     {
-        if (Util.isFragment(module))
+        if (isSingleton(module))
         {
-            addFragment(module);
+            // Find the currently selected singleton, which is either the
+            // highest version or the resolved one.
+            List<Module> modules = m_singletons.get(module.getSymbolicName());
+            // Get the highest version.
+            Module current = ((modules != null) && !modules.isEmpty()) ? modules.get(0) : null;
+            // Now check to see if there is a resolved one instead.
+            for (int i = 0; (modules != null) && (i < modules.size()); i++)
+            {
+                if (modules.get(i).isResolved())
+                {
+                    current = modules.get(i);
+                }
+            }
+
+            // Index the new singleton.
+            Module highest = indexModule(m_singletons, module);
+            // If the currently selected singleton is not resolved and
+            // the newly added singleton is a higher version, then select
+            // it instead.
+            if ((current != null) && !current.isResolved() && (current != highest))
+            {
+                if (Util.isFragment(current))
+                {
+                    removeFragment(current);
+                }
+                else
+                {
+                    removeHost(current);
+                }
+            }
+            else if (current != null)
+            {
+                module = null;
+            }
         }
-        else
+
+        if ((module != null) && Util.isFragment(module))
+        {
+             addFragment(module);
+        }
+        else if (module != null)
         {
             addHost(module);
         }
@@ -76,8 +128,20 @@
 //dumpPackageIndex(m_resolvedPkgIndex);
     }
 
-    public synchronized void removeModule(IModule module)
+    public synchronized void removeModule(Module module)
     {
+        // If this module is a singleton, then remove it from the
+        // singleton map.
+        List<Module> modules = m_singletons.get(module.getSymbolicName());
+        if (modules != null)
+        {
+            modules.remove(module);
+            if (modules.size() == 0)
+            {
+                m_singletons.remove(module.getSymbolicName());
+            }
+        }
+
         if (Util.isFragment(module))
         {
             removeFragment(module);
@@ -88,10 +152,75 @@
         }
     }
 
-    private void addFragment(IModule fragment)
+    public void detachFragment(Module host, Module fragment)
+    {
+        List<Module> fragments = ((ModuleImpl) host).getFragments();
+        fragments.remove(fragment);
+        try
+        {
+            ((ModuleImpl) host).attachFragments(fragments);
+        }
+        catch (Exception ex)
+        {
+            // Try to clean up by removing all fragments.
+            try
+            {
+                ((ModuleImpl) host).attachFragments(null);
+            }
+            catch (Exception ex2)
+            {
+            }
+            m_logger.log(Logger.LOG_ERROR,
+                "Serious error attaching fragments.", ex);
+        }
+    }
+
+    public void checkSingleton(Module module)
+    {
+        // Check if this module is a singleton.
+        List<Module> modules = m_singletons.get(module.getSymbolicName());
+        if ((modules != null) && modules.contains(module))
+        {
+            // If it is, check if there is already a resolved singleton.
+            for (int i = 0; (modules != null) && (i < modules.size()); i++)
+            {
+                if (modules.get(i).isResolved())
+                {
+                    throw new ResolveException(
+                        "Only one singleton can be resolved at a time.", null, null);
+                }
+            }
+
+            // If not, check to see if it is the selected singleton.
+            Module current = (modules.size() > 0) ? modules.get(0) : null;
+            if ((current != null) && (current != module))
+            {
+                // If it is not the selected singleton, remove the selected
+                // singleton and select the specified one instead.
+                if (Util.isFragment(current))
+                {
+                    removeFragment(current);
+                }
+                else
+                {
+                    removeHost(current);
+                }
+                if (Util.isFragment(module))
+                {
+                     addFragment(module);
+                }
+                else if (module != null)
+                {
+                    addHost(module);
+                }
+            }
+        }
+    }
+
+    private void addFragment(Module fragment)
     {
 // TODO: FRAGMENT - This should check to make sure that the host allows fragments.
-        IModule bestFragment = indexFragment(m_fragmentMap, fragment);
+        Module bestFragment = indexModule(m_fragmentMap, fragment);
 
         // If the newly added fragment is the highest version for
         // its given symbolic name, then try to merge it to any
@@ -107,20 +236,20 @@
             List matchingHosts = getMatchingHosts(fragment);
             for (int hostIdx = 0; hostIdx < matchingHosts.size(); hostIdx++)
             {
-                IModule host = ((ICapability) matchingHosts.get(hostIdx)).getModule();
+                Module host = ((Capability) matchingHosts.get(hostIdx)).getModule();
 
                 // Get the fragments currently attached to the host so we
                 // can remove the older version of the current fragment, if any.
-                IModule[] fragments = ((ModuleImpl) host).getFragments();
-                List fragmentList = new ArrayList();
+                List<Module> fragments = ((ModuleImpl) host).getFragments();
+                List<Module> fragmentList = new ArrayList();
                 for (int fragIdx = 0;
-                    (fragments != null) && (fragIdx < fragments.length);
+                    (fragments != null) && (fragIdx < fragments.size());
                     fragIdx++)
                 {
-                    if (!fragments[fragIdx].getSymbolicName().equals(
+                    if (!fragments.get(fragIdx).getSymbolicName().equals(
                         bestFragment.getSymbolicName()))
                     {
-                        fragmentList.add(fragments[fragIdx]);
+                        fragmentList.add(fragments.get(fragIdx));
                     }
                 }
 
@@ -130,7 +259,7 @@
                     (index < 0) && (listIdx < fragmentList.size());
                     listIdx++)
                 {
-                    IModule f = (IModule) fragmentList.get(listIdx);
+                    Module f = fragmentList.get(listIdx);
                     if (bestFragment.getBundle().getBundleId()
                         < f.getBundle().getBundleId())
                     {
@@ -141,30 +270,21 @@
                     (index < 0) ? fragmentList.size() : index, bestFragment);
 
                 // Remove host's existing exported packages from index.
-                ICapability[] caps = host.getCapabilities();
-                for (int i = 0; (caps != null) && (i < caps.length); i++)
+                List<Capability> caps = host.getCapabilities();
+                for (int i = 0; (caps != null) && (i < caps.size()); i++)
                 {
-                    if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                    if (caps.get(i).getNamespace().equals(Capability.MODULE_NAMESPACE))
                     {
-                        // Get package name.
-                        String pkgName = (String)
-                            caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                        // Remove from "unresolved" package map.
-                        List capList = (List) m_unresolvedPkgIndex.get(pkgName);
-                        if (capList != null)
-                        {
-                            capList.remove(caps[i]);
-                        }
+                        m_modCapSet.removeCapability(caps.get(i));
+                    }
+                    else if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+                    {
+                        m_pkgCapSet.removeCapability(caps.get(i));
                     }
                 }
 
-                // Check if fragment conflicts with existing metadata.
-                checkForConflicts(host, fragmentList);
-
                 // Attach the fragments to the host.
-                fragments = (fragmentList.size() == 0)
-                    ? null
-                    : (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]);
+                fragments = (fragmentList.size() == 0) ? null : fragmentList;
                 try
                 {
                     ((ModuleImpl) host).attachFragments(fragments);
@@ -185,18 +305,22 @@
 
                 // Reindex the host's exported packages.
                 caps = host.getCapabilities();
-                for (int i = 0; (caps != null) && (i < caps.length); i++)
+                for (int i = 0; (caps != null) && (i < caps.size()); i++)
                 {
-                    if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                    if (caps.get(i).getNamespace().equals(Capability.MODULE_NAMESPACE))
                     {
-                        indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
+                        m_modCapSet.addCapability(caps.get(i));
+                    }
+                    else if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+                    {
+                        m_pkgCapSet.addCapability(caps.get(i));
                     }
                 }
             }
         }
     }
 
-    private void removeFragment(IModule fragment)
+    private void removeFragment(Module fragment)
     {
         // Get fragment list, which may be null for system bundle fragments.
         List fragList = (List) m_fragmentMap.get(fragment.getSymbolicName());
@@ -216,71 +340,60 @@
             List matchingHosts = getMatchingHosts(fragment);
             for (int hostIdx = 0; hostIdx < matchingHosts.size(); hostIdx++)
             {
-                IModule host = ((ICapability) matchingHosts.get(hostIdx)).getModule();
+                Module host = ((Capability) matchingHosts.get(hostIdx)).getModule();
 
                 // Check to see if the removed fragment was actually merged with
                 // the host, since it might not be if it wasn't the highest version.
                 // If it was, recalculate the fragments for the host.
-                IModule[] fragments = ((ModuleImpl) host).getFragments();
-                for (int fragIdx = 0;
-                    (fragments != null) && (fragIdx < fragments.length);
-                    fragIdx++)
+                List<Module> fragments = ((ModuleImpl) host).getFragments();
+                if (fragments.contains(fragment))
                 {
-                    if (!fragments[fragIdx].equals(fragment))
+                    List fragmentList = getMatchingFragments(host);
+
+                    // Remove host's existing exported packages from index.
+                    List<Capability> caps = host.getCapabilities();
+                    for (int i = 0; (caps != null) && (i < caps.size()); i++)
                     {
-                        List fragmentList = getMatchingFragments(host);
-
-                        // Remove host's existing exported packages from index.
-                        ICapability[] caps = host.getCapabilities();
-                        for (int i = 0; (caps != null) && (i < caps.length); i++)
+                        if (caps.get(i).getNamespace().equals(Capability.MODULE_NAMESPACE))
                         {
-                            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                            {
-                                // Get package name.
-                                String pkgName = (String)
-                                    caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                                // Remove from "unresolved" package map.
-                                List capList = (List) m_unresolvedPkgIndex.get(pkgName);
-                                if (capList != null)
-                                {
-                                    capList.remove(caps[i]);
-                                }
-                            }
+                            m_modCapSet.removeCapability(caps.get(i));
                         }
+                        else if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+                        {
+                            m_pkgCapSet.removeCapability(caps.get(i));
+                        }
+                    }
 
-                        // Check if fragment conflicts with existing metadata.
-                        checkForConflicts(host, fragmentList);
-
-                        // Attach the fragments to the host.
-                        fragments = (fragmentList.size() == 0)
-                            ? null
-                            : (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]);
+                    // Attach the fragments to the host.
+                    try
+                    {
+                        ((ModuleImpl) host).attachFragments(fragmentList);
+                    }
+                    catch (Exception ex)
+                    {
+                        // Try to clean up by removing all fragments.
                         try
                         {
-                            ((ModuleImpl) host).attachFragments(fragments);
+                            ((ModuleImpl) host).attachFragments(null);
                         }
-                        catch (Exception ex)
+                        catch (Exception ex2)
                         {
-                            // Try to clean up by removing all fragments.
-                            try
-                            {
-                                ((ModuleImpl) host).attachFragments(null);
-                            }
-                            catch (Exception ex2)
-                            {
-                            }
-                            m_logger.log(Logger.LOG_ERROR,
-                                "Serious error attaching fragments.", ex);
                         }
+                        m_logger.log(Logger.LOG_ERROR,
+                            "Serious error attaching fragments.", ex);
+                    }
 
-                        // Reindex the host's exported packages.
-                        caps = host.getCapabilities();
-                        for (int i = 0; (caps != null) && (i < caps.length); i++)
+                    // Reindex the host's exported packages.
+                    caps = host.getCapabilities();
+                    for (int i = 0; (caps != null) && (i < caps.size()); i++)
+                    {
+                        if (caps.get(i).getNamespace().equals(Capability.MODULE_NAMESPACE))
                         {
-                            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                            {
-                                indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
-                            }
+                            m_modCapSet.addCapability(caps.get(i));
+                        }
+                        else if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+                        {
+                            m_pkgCapSet.addCapability(caps.get(i));
                         }
                     }
                 }
@@ -288,105 +401,20 @@
         }
     }
 
-    public void unmergeFragment(IModule module)
+    public void unmergeFragment(Module fragment)
     {
-        if (!Util.isFragment(module))
+        if (!Util.isFragment(fragment))
         {
             return;
         }
 
-        // Get fragment list, which may be null for system bundle fragments.
-        List fragList = (List) m_fragmentMap.get(module.getSymbolicName());
-        if (fragList != null)
-        {
-            // Remove from fragment map.
-            fragList.remove(module);
-            if (fragList.size() == 0)
-            {
-                m_fragmentMap.remove(module.getSymbolicName());
-            }
-
-            // If we have any matching hosts, then remove fragment while
-            // removing any older version of the new fragment. Also remove host's
-            // existing capabilities from the package index and reindex its new
-            // ones after attaching the fragment.
-            List matchingHosts = getMatchingHosts(module);
-            for (int hostIdx = 0; hostIdx < matchingHosts.size(); hostIdx++)
-            {
-                IModule host = ((ICapability) matchingHosts.get(hostIdx)).getModule();
-                // Find any unresolved hosts into which the fragment is merged
-                // and unmerge it.
-                IModule[] fragments = ((ModuleImpl) host).getFragments();
-                for (int fragIdx = 0;
-                    !host.isResolved() && (fragments != null) && (fragIdx < fragments.length);
-                    fragIdx++)
-                {
-                    if (!fragments[fragIdx].equals(module))
-                    {
-                        List fragmentList = getMatchingFragments(host);
-
-                        // Remove host's existing exported packages from index.
-                        ICapability[] caps = host.getCapabilities();
-                        for (int i = 0; (caps != null) && (i < caps.length); i++)
-                        {
-                            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                            {
-                                // Get package name.
-                                String pkgName = (String)
-                                    caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                                // Remove from "unresolved" package map.
-                                List capList = (List) m_unresolvedPkgIndex.get(pkgName);
-                                if (capList != null)
-                                {
-                                    capList.remove(caps[i]);
-                                }
-                            }
-                        }
-
-                        // Check if fragment conflicts with existing metadata.
-                        checkForConflicts(host, fragmentList);
-
-                        // Attach the fragments to the host.
-                        fragments = (fragmentList.size() == 0)
-                            ? null
-                            : (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]);
-                        try
-                        {
-                            ((ModuleImpl) host).attachFragments(fragments);
-                        }
-                        catch (Exception ex)
-                        {
-                            // Try to clean up by removing all fragments.
-                            try
-                            {
-                                ((ModuleImpl) host).attachFragments(null);
-                            }
-                            catch (Exception ex2)
-                            {
-                            }
-                            m_logger.log(Logger.LOG_ERROR,
-                                "Serious error attaching fragments.", ex);
-                        }
-
-                        // Reindex the host's exported packages.
-                        caps = host.getCapabilities();
-                        for (int i = 0; (caps != null) && (i < caps.length); i++)
-                        {
-                            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                            {
-                                indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
-                            }
-                        }
-                    }
-                }
-            }
-        }
+        removeFragment(fragment);
     }
 
-    private List getMatchingHosts(IModule fragment)
+    private List getMatchingHosts(Module fragment)
     {
         // Find the fragment's host requirement.
-        IRequirement hostReq = getFragmentHostRequirement(fragment);
+        Requirement hostReq = getFragmentHostRequirement(fragment);
 
         // Create a list of all matching hosts for this fragment.
         List matchingHosts = new ArrayList();
@@ -399,32 +427,26 @@
                 return matchingHosts;
             }
         }
-        for (int hostIdx = 0; (hostReq != null) && (hostIdx < m_moduleList.size()); hostIdx++)
+
+        Set<Capability> hostCaps = m_hostCapSet.match(hostReq.getFilter(), true);
+
+        for (Capability hostCap : hostCaps)
         {
-            IModule host = (IModule) m_moduleList.get(hostIdx);
             // Only look at unresolved hosts, since we don't support
             // dynamic attachment of fragments.
-            if (host.isResolved()
-                || ((BundleImpl) host.getBundle()).isStale()
-                || ((BundleImpl) host.getBundle()).isRemovalPending())
+            if (hostCap.getModule().isResolved()
+                || ((BundleImpl) hostCap.getModule().getBundle()).isStale()
+                || ((BundleImpl) hostCap.getModule().getBundle()).isRemovalPending())
             {
                 continue;
             }
 
-            // Find the host capability for the current host.
-            ICapability hostCap = Util.getSatisfyingCapability(host, hostReq);
-
-            // If there is no host capability in the current module,
-            // then just ignore it.
-            if (hostCap == null)
-            {
-                continue;
-            }
-            
             if (sm != null)
             {
-                if (!((BundleProtectionDomain) host.getSecurityContext()).impliesDirect(new BundlePermission(host.getSymbolicName(), 
-                    BundlePermission.HOST)))
+                if (!((BundleProtectionDomain) hostCap.getModule()
+                        .getSecurityContext()).impliesDirect(
+                            new BundlePermission(hostCap.getModule().getSymbolicName(),
+                            BundlePermission.HOST)))
                 {
                     continue;
                 }
@@ -436,280 +458,28 @@
         return matchingHosts;
     }
 
-    private void checkForConflicts(IModule host, List fragmentList)
-    {
-        if ((fragmentList == null) || (fragmentList.size() == 0))
-        {
-            return;
-        }
-
-        // Verify the fragments do not have conflicting imports.
-        // For now, just check for duplicate imports, but in the
-        // future we might want to make this more fine grained.
-        // First get the host's imported packages.
-        final int MODULE_IDX = 0, REQ_IDX = 1;
-        Map ipMerged = new HashMap();
-        Map rbMerged = new HashMap();
-        IRequirement[] reqs = host.getRequirements();
-        for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
-        {
-            if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                ipMerged.put(
-                    ((Requirement) reqs[reqIdx]).getTargetName(),
-                    new Object[] { host, reqs[reqIdx] });
-            }
-            else if (reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                rbMerged.put(
-                    ((Requirement) reqs[reqIdx]).getTargetName(),
-                    new Object[] { host, reqs[reqIdx] });
-            }
-        }
-        // Loop through each fragment verifying it does not conflict.
-        // Add its package and bundle dependencies if they do not
-        // conflict or remove the fragment if it does conflict.
-        for (Iterator it = fragmentList.iterator(); it.hasNext(); )
-        {
-            IModule fragment = (IModule) it.next();
-            reqs = fragment.getRequirements();
-            Map ipFragment = new HashMap();
-            Map rbFragment = new HashMap();
-            for (int reqIdx = 0;
-                (reqs != null) && (reqIdx < reqs.length);
-                reqIdx++)
-            {
-                if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                    || reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
-                {
-                    String targetName = ((Requirement) reqs[reqIdx]).getTargetName();
-                    Map mergedReqMap =
-                        (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                            ? ipMerged : rbMerged;
-                    Map fragmentReqMap =
-                        (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                            ? ipFragment : rbFragment;
-                    Object[] existing = (Object[]) mergedReqMap.get(targetName);
-                    if (existing == null)
-                    {
-                        fragmentReqMap.put(targetName, new Object[] { fragment, reqs[reqIdx] });
-                    }
-                    else if (isRequirementConflicting(
-                        (Requirement) existing[REQ_IDX], (Requirement) reqs[reqIdx]))
-                    {
-                        ipFragment.clear();
-                        rbFragment.clear();
-                        it.remove();
-                        m_logger.log(
-                            Logger.LOG_DEBUG,
-                            "Excluding fragment " + fragment.getSymbolicName()
-                            + " from " + host.getSymbolicName()
-                            + " due to conflict with "
-                            + (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                                ? "imported package " : "required bundle ")
-                            + targetName + " from "
-                            + ((IModule) existing[MODULE_IDX]).getSymbolicName());
-                        // No need to finish processing current fragment.
-                        break;
-                    }
-                    else
-                    {
-                        // If there is an overlapping requirement for the existing
-                        // target, then try to calculate the intersecting requirement
-                        // and set the existing requirement to that instead. This
-                        // makes it so version ranges do not have to be exact, just
-                        // overlapping.
-                        Requirement intersection = calculateVersionIntersection(
-                            (Requirement) existing[REQ_IDX], (Requirement) reqs[reqIdx]);
-                        if (intersection != existing[REQ_IDX])
-                        {
-                            existing[REQ_IDX] = intersection;
-                        }
-                    }
-                }
-            }
-
-            // Merge non-conflicting requirements into overall set
-            // of requirements and continue checking for conflicts
-            // with the next fragment.
-            for (Iterator it2 = ipFragment.entrySet().iterator(); it2.hasNext(); )
-            {
-                Map.Entry entry = (Map.Entry) it2.next();
-                ipMerged.put(entry.getKey(), entry.getValue());
-            }
-            for (Iterator it2 = rbFragment.entrySet().iterator(); it2.hasNext(); )
-            {
-                Map.Entry entry = (Map.Entry) it2.next();
-                rbMerged.put(entry.getKey(), entry.getValue());
-            }
-        }
-    }
-
-    private boolean isRequirementConflicting(
-        Requirement existing, Requirement additional)
-    {
-        // If the namespace is not the same, then they do NOT conflict.
-        if (!existing.getNamespace().equals(additional.getNamespace()))
-        {
-            return false;
-        }
-        // If the target name is not the same, then they do NOT conflict.
-        if (!existing.getTargetName().equals(additional.getTargetName()))
-        {
-            return false;
-        }
-        // If the existing version range floor is greater than the additional
-        // version range's floor, then they are inconflict since we cannot
-        // widen the constraint.
-        if (!existing.getTargetVersionRange().intersects(
-            additional.getTargetVersionRange()))
-        {
-            return true;
-        }
-        // If optionality is not the same, then they conflict, unless
-        // the existing requirement is not optional, then it doesn't matter
-        // what subsequent requirements are since non-optional is stronger
-        // than optional.
-        if (existing.isOptional() && !additional.isOptional())
-        {
-            return true;
-        }
-        // Verify directives are the same.
-        final R4Directive[] exDirs = (existing.getDirectives() == null)
-            ? new R4Directive[0] : existing.getDirectives();
-        final R4Directive[] addDirs = (additional.getDirectives() == null)
-            ? new R4Directive[0] : additional.getDirectives();
-        // Put attributes in a map, since ordering is arbitrary.
-        final Map exDirMap = new HashMap();
-        for (int i = 0; i < exDirs.length; i++)
-        {
-            exDirMap.put(exDirs[i].getName(), exDirs[i]);
-        }
-        // If attribute values do not match, then they conflict.
-        for (int i = 0; i < addDirs.length; i++)
-        {
-            // Ignore resolution directive, since we've already tested it above.
-            if (!addDirs[i].getName().equals(Constants.RESOLUTION_DIRECTIVE))
-            {
-                final R4Directive exDir = (R4Directive) exDirMap.get(addDirs[i].getName());
-                if ((exDir == null) ||
-                    !exDir.getValue().equals(addDirs[i].getValue()))
-                {
-                    return true;
-                }
-            }
-        }
-        // Verify attributes are the same.
-        final R4Attribute[] exAttrs = (existing.getAttributes() == null)
-            ? new R4Attribute[0] : existing.getAttributes();
-        final R4Attribute[] addAttrs = (additional.getAttributes() == null)
-            ? new R4Attribute[0] : additional.getAttributes();
-        // Put attributes in a map, since ordering is arbitrary.
-        final Map exAttrMap = new HashMap();
-        for (int i = 0; i < exAttrs.length; i++)
-        {
-            exAttrMap.put(exAttrs[i].getName(), exAttrs[i]);
-        }
-        // If attribute values do not match, then they conflict.
-        for (int i = 0; i < addAttrs.length; i++)
-        {
-            // Ignore version property, since we've already tested it above.
-            if (!(additional.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                && addAttrs[i].getName().equals(ICapability.VERSION_PROPERTY))
-                && !(additional.getNamespace().equals(ICapability.MODULE_NAMESPACE)
-                    && addAttrs[i].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE)))
-            {
-                final R4Attribute exAttr = (R4Attribute) exAttrMap.get(addAttrs[i].getName());
-                if ((exAttr == null) ||
-                    !exAttr.getValue().equals(addAttrs[i].getValue()) ||
-                    (exAttr.isMandatory() != addAttrs[i].isMandatory()))
-                {
-                    return true;
-                }
-            }
-        }
-        // They do no conflict.
-        return false;
-    }
-
-    static Requirement calculateVersionIntersection(
-        Requirement existing, Requirement additional)
-    {
-        Requirement intersection = existing;
-        int existVersionIdx = -1, addVersionIdx = -1;
-
-        // Find the existing version attribute.
-        for (int i = 0; (existVersionIdx < 0) && (i < existing.getAttributes().length); i++)
-        {
-            if ((existing.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                && existing.getAttributes()[i].getName().equals(ICapability.VERSION_PROPERTY))
-                || (existing.getNamespace().equals(ICapability.MODULE_NAMESPACE)
-                    && existing.getAttributes()[i].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE)))
-            {
-                existVersionIdx = i;
-            }
-        }
-
-        // Find the additional version attribute.
-        for (int i = 0; (addVersionIdx < 0) && (i < additional.getAttributes().length); i++)
-        {
-            if ((additional.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                && additional.getAttributes()[i].getName().equals(ICapability.VERSION_PROPERTY))
-                || (additional.getNamespace().equals(ICapability.MODULE_NAMESPACE)
-                    && additional.getAttributes()[i].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE)))
-            {
-                addVersionIdx = i;
-            }
-        }
-
-        // Use the additional requirement's version range if it
-        // has one and the existing requirement does not.
-        if ((existVersionIdx == -1) && (addVersionIdx != -1))
-        {
-            intersection = additional;
-        }
-        // If both requirements have version ranges, then create
-        // a new requirement with an intersecting version range.
-        else if ((existVersionIdx != -1) && (addVersionIdx != -1))
-        {
-            VersionRange vr = ((VersionRange) existing.getAttributes()[existVersionIdx].getValue())
-                .intersection((VersionRange) additional.getAttributes()[addVersionIdx].getValue());
-            R4Attribute[] attrs = existing.getAttributes();
-            R4Attribute[] newAttrs = new R4Attribute[attrs.length];
-            System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
-            newAttrs[existVersionIdx] = new R4Attribute(
-                attrs[existVersionIdx].getName(), vr, false);
-            intersection = new Requirement(
-                existing.getNamespace(),
-                existing.getDirectives(),
-                newAttrs);
-        }
-
-        return intersection;
-    }
-
-    private void addHost(IModule host)
+    private void addHost(Module host)
     {
         // When a module is added, we first need to pre-merge any potential fragments
         // into the host and then second create an aggregated list of unresolved
         // capabilities to simplify later processing when resolving bundles.
-        m_moduleList.add(host);
+        m_modules.add(host);
+        List<Capability> caps = Util.getCapabilityByNamespace(host, Capability.HOST_NAMESPACE);
+        if (caps.size() > 0)
+        {
+            m_hostCapSet.addCapability(caps.get(0));
+        }
 
         //
         // First, merge applicable fragments.
         //
 
-        List fragmentList = getMatchingFragments(host);
+        List<Module> fragments = getMatchingFragments(host);
 
         // Attach any fragments we found for this host.
-        if (fragmentList.size() > 0)
+        if (fragments.size() > 0)
         {
-            // Check if fragment conflicts with existing metadata.
-            checkForConflicts(host, fragmentList);
-
             // Attach the fragments to the host.
-            IModule[] fragments =
-                (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]);
             try
             {
                 ((ModuleImpl) host).attachFragments(fragments);
@@ -733,52 +503,47 @@
         // Second, index module's capabilities.
         //
 
-        ICapability[] caps = host.getCapabilities();
+        caps = host.getCapabilities();
 
         // Add exports to unresolved package map.
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
+        for (int i = 0; (caps != null) && (i < caps.size()); i++)
         {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            if (caps.get(i).getNamespace().equals(Capability.MODULE_NAMESPACE))
             {
-                indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
+                m_modCapSet.addCapability(caps.get(i));
+            }
+            else if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+            {
+                m_pkgCapSet.addCapability(caps.get(i));
             }
         }
     }
 
-    private void removeHost(IModule host)
+    private void removeHost(Module host)
     {
         // We need remove the host's exports from the "resolved" and
         // "unresolved" package maps, remove its dependencies on fragments
         // and exporters, and remove it from the module list.
-        m_moduleList.remove(host);
-
-        // Remove exports from package maps.
-        ICapability[] caps = host.getCapabilities();
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
+        m_modules.remove(host);
+        List<Capability> caps = Util.getCapabilityByNamespace(host, Capability.HOST_NAMESPACE);
+        if (caps.size() > 0)
         {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                // Get package name.
-                String pkgName = (String)
-                    caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                // Remove from "unresolved" package map.
-                List capList = (List) m_unresolvedPkgIndex.get(pkgName);
-                if (capList != null)
-                {
-                    capList.remove(caps[i]);
-                }
-
-                // Remove from "resolved" package map.
-                capList = (List) m_resolvedPkgIndex.get(pkgName);
-                if (capList != null)
-                {
-                    capList.remove(caps[i]);
-                }
-            }
+            m_hostCapSet.removeCapability(caps.get(0));
         }
 
-        // Remove the module from the "resolved" map.
-        m_resolvedCapMap.remove(host);
+        // Remove exports from package maps.
+        caps = host.getCapabilities();
+        for (int i = 0; (caps != null) && (i < caps.size()); i++)
+        {
+            if (caps.get(i).getNamespace().equals(Capability.MODULE_NAMESPACE))
+            {
+                m_modCapSet.removeCapability(caps.get(i));
+            }
+            else if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+            {
+                m_pkgCapSet.removeCapability(caps.get(i));
+            }
+        }
 
         // Set fragments to null, which will remove the module from all
         // of its dependent fragment modules.
@@ -795,11 +560,11 @@
         ((ModuleImpl) host).setWires(null);
     }
 
-    private List getMatchingFragments(IModule host)
+    private List getMatchingFragments(Module host)
     {
         // Find the host capability for the current host.
-        ICapability[] caps = Util.getCapabilityByNamespace(host, ICapability.HOST_NAMESPACE);
-        ICapability hostCap = (caps.length == 0) ? null : caps[0];
+        List<Capability> caps = Util.getCapabilityByNamespace(host, Capability.HOST_NAMESPACE);
+        Capability hostCap = (caps.size() == 0) ? null : caps.get(0);
 
         // If we have a host capability, then loop through all fragments trying to
         // find ones that match.
@@ -816,10 +581,10 @@
         {
             Map.Entry entry = (Map.Entry) it.next();
             List fragments = (List) entry.getValue();
-            IModule fragment = null;
+            Module fragment = null;
             for (int i = 0; (fragment == null) && (i < fragments.size()); i++)
             {
-                IModule f = (IModule) fragments.get(i);
+                Module f = (Module) fragments.get(i);
                 if (!((BundleImpl) f.getBundle()).isStale()
                     && !((BundleImpl) f.getBundle()).isRemovalPending())
                 {
@@ -839,11 +604,11 @@
                     continue;
                 }
             }
-            IRequirement hostReq = getFragmentHostRequirement(fragment);
+            Requirement hostReq = getFragmentHostRequirement(fragment);
 
             // If we have a host requirement, then loop through each host and
             // see if it matches the host requirement.
-            if ((hostReq != null) && hostReq.isSatisfied(hostCap))
+            if ((hostReq != null) && CapabilitySet.matches(hostCap, hostReq.getFilter()))
             {
                 // Now add the new fragment in bundle ID order.
                 int index = -1;
@@ -851,7 +616,7 @@
                     (index < 0) && (listIdx < fragmentList.size());
                     listIdx++)
                 {
-                    IModule existing = (IModule) fragmentList.get(listIdx);
+                    Module existing = (Module) fragmentList.get(listIdx);
                     if (fragment.getBundle().getBundleId()
                         < existing.getBundle().getBundleId())
                     {
@@ -866,16 +631,16 @@
         return fragmentList;
     }
 
-    public synchronized IModule findHost(IModule rootModule) throws ResolveException
+    public synchronized Module findHost(Module rootModule) throws ResolveException
     {
-        IModule newRootModule = rootModule;
+        Module newRootModule = rootModule;
         if (Util.isFragment(rootModule))
         {
             List matchingHosts = getMatchingHosts(rootModule);
-            IModule currentBestHost = null;
+            Module currentBestHost = null;
             for (int hostIdx = 0; hostIdx < matchingHosts.size(); hostIdx++)
             {
-                IModule host = ((ICapability) matchingHosts.get(hostIdx)).getModule();
+                Module host = ((Capability) matchingHosts.get(hostIdx)).getModule();
                 if (currentBestHost == null)
                 {
                     currentBestHost = host;
@@ -897,16 +662,16 @@
         return newRootModule;
     }
 
-    private IRequirement getFragmentHostRequirement(IModule fragment)
+    private static Requirement getFragmentHostRequirement(Module fragment)
     {
         // Find the fragment's host requirement.
-        IRequirement[] reqs = fragment.getRequirements();
-        IRequirement hostReq = null;
-        for (int reqIdx = 0; (hostReq == null) && (reqIdx < reqs.length); reqIdx++)
+        List<Requirement> reqs = fragment.getRequirements();
+        Requirement hostReq = null;
+        for (int reqIdx = 0; (hostReq == null) && (reqIdx < reqs.size()); reqIdx++)
         {
-            if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+            if (reqs.get(reqIdx).getNamespace().equals(Capability.HOST_NAMESPACE))
             {
-                hostReq = reqs[reqIdx];
+                hostReq = reqs.get(reqIdx);
             }
         }
         return hostReq;
@@ -918,60 +683,31 @@
      * to capture additional capabilities.
      * @param module The module being refresh, which should always be the system bundle.
     **/
-    synchronized void refreshSystemBundleModule(IModule module)
+    synchronized void refreshSystemBundleModule(Module module)
     {
         // The system bundle module should always be resolved, so we only need
         // to update the resolved capability map.
-        ICapability[] caps = module.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++)
         {
-            List resolvedCaps = (List) m_resolvedCapMap.get(module);
-            if (resolvedCaps == null)
+            if (caps.get(i).getNamespace().equals(Capability.MODULE_NAMESPACE))
             {
-                m_resolvedCapMap.put(module, resolvedCaps = new ArrayList());
+                m_modCapSet.addCapability(caps.get(i));
             }
-            if (!resolvedCaps.contains(caps[i]))
+            else if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
             {
-                resolvedCaps.add(caps[i]);
-            }
-
-            // If the capability is a package, then add the exporter module
-            // of the wire to the "resolved" package index and remove it
-            // from the "unresolved" package index.
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                // Add to "resolved" package index.
-                indexPackageCapability(m_resolvedPkgIndex, caps[i]);
+                m_pkgCapSet.addCapability(caps.get(i));
             }
         }
     }
 
-    private void dumpPackageIndex(Map pkgIndex)
+// TODO: FELIX3 - Try to eliminate this.
+    public synchronized List<Module> getModules()
     {
-        for (Iterator i = pkgIndex.entrySet().iterator(); i.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) i.next();
-            List capList = (List) entry.getValue();
-            if (capList.size() > 0)
-            {
-                if (!((capList.size() == 1) && ((ICapability) capList.get(0)).getModule().getId().equals("0")))
-                {
-                    System.out.println("  " + entry.getKey());
-                    for (int j = 0; j < capList.size(); j++)
-                    {
-                        System.out.println("    " + ((ICapability) capList.get(j)).getModule());
-                    }
-                }
-            }
-        }
+        return m_modules;
     }
 
-    public synchronized IModule[] getModules()
-    {
-        return (IModule[]) m_moduleList.toArray(new IModule[m_moduleList.size()]);
-    }
-
-    public synchronized void moduleResolved(IModule module)
+    public synchronized void moduleResolved(Module module)
     {
         if (module.isResolved())
         {
@@ -983,40 +719,22 @@
             // module and not another module. If it points to another module
             // then the capability should be ignored, since the framework
             // decided to honor the import and discard the export.
-            ICapability[] caps = module.getCapabilities();
+            List<Capability> caps = module.getCapabilities();
 
-            // First remove all existing capabilities from the "unresolved" map.
-            for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
-            {
-                if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                {
-                    // Get package name.
-                    String pkgName = (String)
-                        caps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                    // Remove the module's capability for the package.
-                    List capList = (List) m_unresolvedPkgIndex.get(pkgName);
-                    capList.remove(caps[capIdx]);
-                }
-            }
-
-            // Next create a copy of the module's capabilities so we can
+            // Create a copy of the module's capabilities so we can
             // null out any capabilities that should be ignored.
-            ICapability[] capsCopy = (caps == null) ? null : new ICapability[caps.length];
-            if (capsCopy != null)
-            {
-                System.arraycopy(caps, 0, capsCopy, 0, caps.length);
-            }
+            List<Capability> capsCopy = (caps == null) ? null : new ArrayList(caps);
             // Loop through the module's capabilities to determine which ones
             // can be ignored by seeing which ones satifies the wire requirements.
 // TODO: RB - Bug here because a requirement for a package need not overlap the
 //            capability for that package and this assumes it does. This might
 //            require us to introduce the notion of a substitutable capability.
-            IWire[] wires = module.getWires();
-            for (int capIdx = 0; (capsCopy != null) && (capIdx < capsCopy.length); capIdx++)
+            List<Wire> wires = module.getWires();
+            for (int capIdx = 0; (capsCopy != null) && (capIdx < caps.size()); capIdx++)
             {
                 // Loop through all wires to see if the current capability
                 // satisfies any of the wire requirements.
-                for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
+                for (int wireIdx = 0; (wires != null) && (wireIdx < wires.size()); wireIdx++)
                 {
                     // If one of the module's capabilities satifies the requirement
                     // for an existing wire, this means the capability was
@@ -1024,9 +742,10 @@
                     // the module's capability was not used. Therefore, we should
                     // null it here so it doesn't get added the list of resolved
                     // capabilities for this module.
-                    if (wires[wireIdx].getRequirement().isSatisfied(capsCopy[capIdx]))
+                    if (CapabilitySet.matches(
+                        caps.get(capIdx), wires.get(wireIdx).getRequirement().getFilter()))
                     {
-                        capsCopy[capIdx] = null;
+                        capsCopy.remove(caps.get(capIdx));
                         break;
                     }
                 }
@@ -1034,276 +753,72 @@
 
             // Now loop through all capabilities and add them to the "resolved"
             // capability and package index maps, ignoring any that were nulled out.
-            for (int capIdx = 0; (capsCopy != null) && (capIdx < capsCopy.length); capIdx++)
+// TODO: FELIX3 - This is actually reversed, we need to remove exports that were imported.
+/*
+            for (int capIdx = 0; (capsCopy != null) && (capIdx < capsCopy.size()); capIdx++)
             {
-                if (capsCopy[capIdx] != null)
+                if (capsCopy.get(capIdx).getNamespace().equals(Capability.MODULE_NAMESPACE))
                 {
-                    List resolvedCaps = (List) m_resolvedCapMap.get(module);
-                    if (resolvedCaps == null)
-                    {
-                        m_resolvedCapMap.put(module, resolvedCaps = new ArrayList());
-                    }
-                    if (!resolvedCaps.contains(capsCopy[capIdx]))
-                    {
-                        resolvedCaps.add(capsCopy[capIdx]);
-                    }
-
-                    // If the capability is a package, then add the exporter module
-                    // of the wire to the "resolved" package index and remove it
-                    // from the "unresolved" package index.
-                    if (capsCopy[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                    {
-                        // Add to "resolved" package index.
-                        indexPackageCapability(m_resolvedPkgIndex, capsCopy[capIdx]);
-                    }
+                    m_modCapSet.addCapability(capsCopy.get(capIdx));
+                }
+                else if (capsCopy.get(capIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+                {
+                    m_pkgCapSet.addCapability(capsCopy.get(capIdx));
                 }
             }
+*/
         }
-
-//System.out.println("UNRESOLVED PACKAGES:");
-//dumpPackageIndex(m_unresolvedPkgIndex);
-//System.out.println("RESOLVED PACKAGES:");
-//dumpPackageIndex(m_resolvedPkgIndex);
     }
 
-    public synchronized List getResolvedCandidates(IRequirement req, IModule reqModule)
+    public Set<Capability> getCandidates(Module module, Requirement req, boolean obeyMandatory)
     {
-        // Synchronized on the module manager to make sure that no
-        // modules are added, removed, or resolved.
-        List candidates = new ArrayList();
-        if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-            && (((Requirement) req).getTargetName() != null))
-        {
-            String pkgName = ((Requirement) req).getTargetName();
-            List capList = (List) m_resolvedPkgIndex.get(pkgName);
+        Set<Capability> result = new TreeSet(new CandidateComparator());
 
-            for (int capIdx = 0; (capList != null) && (capIdx < capList.size()); capIdx++)
-            {
-                ICapability cap = (ICapability) capList.get(capIdx);
-                if (req.isSatisfied(cap))
-                {
-                    if (System.getSecurityManager() != null)
-                    {
-                        if (reqModule != ((ICapability) capList.get(capIdx)).getModule())
-                        {
-                            if ((!((BundleProtectionDomain)((ICapability) 
-                                capList.get(capIdx)).getModule().getSecurityContext()).impliesDirect(
-                                new PackagePermission(((Requirement) req).getTargetName(), PackagePermission.EXPORTONLY))) ||
-                                !((reqModule == null) ||
-                                ((BundleProtectionDomain) reqModule.getSecurityContext()).impliesDirect(
-                                new PackagePermission(((Requirement) req).getTargetName(), ((ICapability) 
-                                capList.get(capIdx)).getModule().getBundle(),PackagePermission.IMPORT))
-                                ))
-                            {
-                                continue;
-                            }
-                        }
-                    }
-                    candidates.add(cap);
-                }
-            }
-        }
-        else
+        if (req.getNamespace().equals(Capability.MODULE_NAMESPACE))
         {
-            Iterator i = m_resolvedCapMap.entrySet().iterator();
-            while (i.hasNext())
-            {
-                Map.Entry entry = (Map.Entry) i.next();
-                IModule module = (IModule) entry.getKey();
-                List caps = (List) entry.getValue();
-                for (int capIdx = 0; (caps != null) && (capIdx < caps.size()); capIdx++)
-                {
-                    ICapability cap = (ICapability) caps.get(capIdx);
-                    if (req.isSatisfied(cap))
-                    {
-                        if (System.getSecurityManager() != null)
-                        {
-                            if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) && (
-                                !((BundleProtectionDomain) cap.getModule().getSecurityContext()).impliesDirect(
-                                new PackagePermission((String) cap.getProperties().get(ICapability.PACKAGE_PROPERTY), PackagePermission.EXPORTONLY)) ||
-                                !((reqModule == null) ||
-                                ((BundleProtectionDomain) reqModule.getSecurityContext()).impliesDirect(
-                                new PackagePermission((String) cap.getProperties().get(ICapability.PACKAGE_PROPERTY), cap.getModule().getBundle(),PackagePermission.IMPORT))
-                                )))
-                            {
-                                if (reqModule != cap.getModule())
-                                {
-                                    continue;
-                                }
-                            }
-                            if (req.getNamespace().equals(ICapability.MODULE_NAMESPACE) && (
-                                !((BundleProtectionDomain) cap.getModule().getSecurityContext()).impliesDirect(
-                                new BundlePermission(cap.getModule().getSymbolicName(), BundlePermission.PROVIDE)) ||
-                                !((reqModule == null) ||
-                                ((BundleProtectionDomain) reqModule.getSecurityContext()).impliesDirect(
-                                new BundlePermission(reqModule.getSymbolicName(), BundlePermission.REQUIRE))
-                                )))
-                            {
-                                continue;
-                            }
-                        }
-                        candidates.add(cap);
-                    }
-                }
-            }
+            result.addAll(m_modCapSet.match(req.getFilter(), obeyMandatory));
         }
-        Collections.sort(candidates);
-        return candidates;
-    }
-
-    public synchronized List getUnresolvedCandidates(IRequirement req, IModule reqModule)
-    {
-        // Get all matching unresolved capabilities.
-        List candidates = new ArrayList();
-        if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-            (((Requirement) req).getTargetName() != null))
+        else if (req.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
         {
-            List capList = (List) m_unresolvedPkgIndex.get(((Requirement) req).getTargetName());
-            for (int capIdx = 0; (capList != null) && (capIdx < capList.size()); capIdx++)
-            {
-                // If compatible and it is not currently resolved, then add
-                // the unresolved candidate to the list.
-                if (req.isSatisfied((ICapability) capList.get(capIdx)))
-                {
-                    if (System.getSecurityManager() != null)
-                    {
-                        if (reqModule != ((ICapability) capList.get(capIdx)).getModule())
-                        {
-                            if (!((BundleProtectionDomain)((ICapability) 
-                                capList.get(capIdx)).getModule().getSecurityContext()).impliesDirect(
-                                new PackagePermission(((Requirement) req).getTargetName(), PackagePermission.EXPORTONLY)) ||
-                                !((reqModule == null) ||
-                                ((BundleProtectionDomain) reqModule.getSecurityContext()).impliesDirect(
-                                new PackagePermission(((Requirement) req).getTargetName(), ((ICapability) 
-                                capList.get(capIdx)).getModule().getBundle(),PackagePermission.IMPORT))
-                                ))
-                            {
-                                continue;
-                            }
-                        }
-                    }
-                    candidates.add(capList.get(capIdx));
-                }
-            }
-        }
-        else
-        {
-            IModule[] modules = getModules();
-            for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
-            {
-                // Get the module's export package for the target package.
-                ICapability cap = Util.getSatisfyingCapability(modules[modIdx], req);
-                // If compatible and it is not currently resolved, then add
-                // the unresolved candidate to the list.
-                if ((cap != null) && !modules[modIdx].isResolved())
-                {
-                    if (System.getSecurityManager() != null)
-                    {
-                        if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) && (
-                            !((BundleProtectionDomain) cap.getModule().getSecurityContext()).impliesDirect(
-                            new PackagePermission((String) cap.getProperties().get(ICapability.PACKAGE_PROPERTY), PackagePermission.EXPORTONLY)) ||
-                            !((reqModule == null) ||
-                            ((BundleProtectionDomain) reqModule.getSecurityContext()).impliesDirect(
-                            new PackagePermission((String) cap.getProperties().get(ICapability.PACKAGE_PROPERTY), cap.getModule().getBundle(),PackagePermission.IMPORT))
-                            )))
-                        {
-                            if (reqModule != cap.getModule())
-                            {
-                                continue;
-                            }
-                        }
-                        if (req.getNamespace().equals(ICapability.MODULE_NAMESPACE) && (
-                                !((BundleProtectionDomain) cap.getModule().getSecurityContext()).impliesDirect(
-                                new BundlePermission(cap.getModule().getSymbolicName(), BundlePermission.PROVIDE)) ||
-                                !((reqModule == null) ||
-                                ((BundleProtectionDomain) reqModule.getSecurityContext()).impliesDirect(
-                                new BundlePermission(reqModule.getSymbolicName(), BundlePermission.REQUIRE))
-                                )))
-                            {
-                                continue;
-                            }
-                    }
-                    candidates.add(cap);
-                }
-            }
+            result.addAll(m_pkgCapSet.match(req.getFilter(), obeyMandatory));
         }
 
-        // Create list of compatible providers.
-        Collections.sort(candidates);
-        return candidates;
+        return result;
     }
 
     //
     // Utility methods.
     //
 
-    private void indexPackageCapability(Map map, ICapability capability)
+    /**
+     * 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(Module module)
     {
-        if (capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+        final List<Capability> modCaps =
+            Util.getCapabilityByNamespace(
+                module, Capability.MODULE_NAMESPACE);
+        if (modCaps == null || modCaps.size() == 0)
         {
-            String pkgName = (String)
-                capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
-            List capList = (List) map.get(pkgName);
-
-            // We want to add the capability into the list of exporters
-            // in sorted order (descending version and ascending bundle
-            // identifier). Insert using a simple binary search algorithm.
-            if (capList == null)
-            {
-                capList = new ArrayList();
-                capList.add(capability);
-            }
-            else
-            {
-                Version version = (Version)
-                    capability.getProperties().get(ICapability.VERSION_PROPERTY);
-                Version middleVersion = null;
-                int top = 0, bottom = capList.size() - 1, middle = 0;
-                while (top <= bottom)
-                {
-                    middle = (bottom - top) / 2 + top;
-                    middleVersion = (Version)
-                        ((ICapability) capList.get(middle))
-                            .getProperties().get(ICapability.VERSION_PROPERTY);
-                    // Sort in reverse version order.
-                    int cmp = middleVersion.compareTo(version);
-                    if (cmp < 0)
-                    {
-                        bottom = middle - 1;
-                    }
-                    else if (cmp == 0)
-                    {
-                        // Sort further by ascending bundle ID.
-                        long middleId = ((ICapability) capList.get(middle))
-                            .getModule().getBundle().getBundleId();
-                        long exportId = capability.getModule().getBundle().getBundleId();
-                        if (middleId < exportId)
-                        {
-                            top = middle + 1;
-                        }
-                        else
-                        {
-                            bottom = middle - 1;
-                        }
-                    }
-                    else
-                    {
-                        top = middle + 1;
-                    }
-                }
-
-                // Ignore duplicates.
-                if ((top >= capList.size()) || (capList.get(top) != capability))
-                {
-                    capList.add(top, capability);
-                }
-            }
-
-            map.put(pkgName, capList);
+            return false;
         }
+        final List<Directive> dirs = modCaps.get(0).getDirectives();
+        for (int dirIdx = 0; (dirs != null) && (dirIdx < dirs.size()); dirIdx++)
+        {
+            if (dirs.get(dirIdx).getName().equalsIgnoreCase(Constants.SINGLETON_DIRECTIVE)
+                && Boolean.valueOf((String) dirs.get(dirIdx).getValue()).booleanValue())
+            {
+                return true;
+            }
+        }
+        return false;
     }
 
-    private IModule indexFragment(Map map, IModule module)
+    private static Module indexModule(Map map, Module module)
     {
         List modules = (List) map.get(module.getSymbolicName());
 
@@ -1324,7 +839,7 @@
             while (top <= bottom)
             {
                 middle = (bottom - top) / 2 + top;
-                middleVersion = ((IModule) modules.get(middle)).getVersion();
+                middleVersion = ((Module) modules.get(middle)).getVersion();
                 // Sort in reverse version order.
                 int cmp = middleVersion.compareTo(version);
                 if (cmp < 0)
@@ -1334,7 +849,7 @@
                 else if (cmp == 0)
                 {
                     // Sort further by ascending bundle ID.
-                    long middleId = ((IModule) modules.get(middle)).getBundle().getBundleId();
+                    long middleId = ((Module) modules.get(middle)).getBundle().getBundleId();
                     long exportId = module.getBundle().getBundleId();
                     if (middleId < exportId)
                     {
@@ -1360,6 +875,6 @@
 
         map.put(module.getSymbolicName(), modules);
 
-        return (IModule) modules.get(0);
+        return (Module) modules.get(0);
     }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
index bb8b007..12aab90 100644
--- a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
@@ -18,8 +18,9 @@
  */
 package org.apache.felix.framework;
 
-import org.apache.felix.framework.searchpolicy.*;
-import org.apache.felix.moduleloader.*;
+import org.apache.felix.framework.resolver.ResourceNotFoundException;
+import org.apache.felix.framework.resolver.Content;
+import org.apache.felix.framework.capabilityset.SimpleFilter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Constructor;
@@ -31,7 +32,7 @@
 import java.security.ProtectionDomain;
 import java.security.SecureClassLoader;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -42,29 +43,37 @@
 import java.util.Vector;
 import org.apache.felix.framework.Felix.FelixResolver;
 import org.apache.felix.framework.cache.JarContent;
+import org.apache.felix.framework.capabilityset.Attribute;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Directive;
+import org.apache.felix.framework.resolver.Module;
+import org.apache.felix.framework.capabilityset.Requirement;
+import org.apache.felix.framework.resolver.Wire;
+import org.apache.felix.framework.resolver.ResolveException;
+import org.apache.felix.framework.resolver.WireImpl;
+import org.apache.felix.framework.resolver.WireModuleImpl;
 import org.apache.felix.framework.util.CompoundEnumeration;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.SecureAction;
 import org.apache.felix.framework.util.SecurityManagerEx;
 import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.Capability;
+import org.apache.felix.framework.util.manifestparser.CapabilityImpl;
 import org.apache.felix.framework.util.manifestparser.ManifestParser;
 import org.apache.felix.framework.util.manifestparser.R4Library;
-import org.apache.felix.framework.util.manifestparser.Requirement;
+import org.apache.felix.framework.util.manifestparser.RequirementImpl;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.BundleReference;
 import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.Version;
 
-public class ModuleImpl implements IModule
+public class ModuleImpl implements Module
 {
     private final Logger m_logger;
     private final Map m_configMap;
     private final FelixResolver m_resolver;
     private final String m_id;
-    private final IContent m_content;
+    private final Content m_content;
     private final Map m_headerMap;
     private final URLStreamHandler m_streamHandler;
 
@@ -73,28 +82,28 @@
     private final String m_symbolicName;
     private final Version m_version;
 
-    private final ICapability[] m_capabilities;
-    private ICapability[] m_cachedCapabilities = null;
-    private final IRequirement[] m_requirements;
-    private IRequirement[] m_cachedRequirements = null;
-    private final IRequirement[] m_dynamicRequirements;
-    private IRequirement[] m_cachedDynamicRequirements = null;
-    private final R4Library[] m_nativeLibraries;
+    private final List<Capability> m_capabilities;
+    private List<Capability> m_cachedCapabilities = null;
+    private final List<Requirement> m_requirements;
+    private List<Requirement> m_cachedRequirements = null;
+    private final List<Requirement> m_dynamicRequirements;
+    private List<Requirement> m_cachedDynamicRequirements = null;
+    private final List<R4Library> m_nativeLibraries;
     private final int m_declaredActivationPolicy;
-    private final String[] m_activationIncludes;
-    private final String[] m_activationExcludes;
+    private final List<String> m_activationIncludes;
+    private final List<String> m_activationExcludes;
 
     private final Bundle m_bundle;
 
-    private IModule[] m_fragments = null;
-    private IWire[] m_wires = null;
-    private IModule[] m_dependentHosts = new IModule[0];
-    private IModule[] m_dependentImporters = new IModule[0];
-    private IModule[] m_dependentRequirers = new IModule[0];
+    private List<Module> m_fragments = null;
+    private List<Wire> m_wires = null;
+    private List<Module> m_dependentHosts = new ArrayList<Module>(0);
+    private List<Module> m_dependentImporters = new ArrayList<Module>(0);
+    private List<Module> m_dependentRequirers = new ArrayList<Module>(0);
     private volatile boolean m_isResolved = false;
 
-    private IContent[] m_contentPath;
-    private IContent[] m_fragmentContents = null;
+    private Content[] m_contentPath;
+    private Content[] m_fragmentContents = null;
     private ModuleClassLoader m_classLoader;
     private boolean m_isActivationTriggered = false;
     private ProtectionDomain m_protectionDomain = null;
@@ -184,7 +193,7 @@
 
     public ModuleImpl(
         Logger logger, Map configMap, FelixResolver resolver,
-        Bundle bundle, String id, Map headerMap, IContent content,
+        Bundle bundle, String id, Map headerMap, Content content,
         URLStreamHandler streamHandler, String[] bootPkgs,
         boolean[] bootPkgWildcards)
         throws BundleException
@@ -269,163 +278,110 @@
         return m_version;
     }
 
-    public synchronized ICapability[] getCapabilities()
+    public synchronized List<Capability> getCapabilities()
     {
         if (m_cachedCapabilities == null)
         {
             List capList = (m_capabilities == null)
-                ? new ArrayList() : new ArrayList(Arrays.asList(m_capabilities));
+                ? new ArrayList<Capability>()
+                : new ArrayList<Capability>(m_capabilities);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                ICapability[] caps = m_fragments[fragIdx].getCapabilities();
+                List<Capability> caps = m_fragments.get(fragIdx).getCapabilities();
                 for (int capIdx = 0;
-                    (caps != null) && (capIdx < caps.length);
+                    (caps != null) && (capIdx < caps.size());
                     capIdx++)
                 {
-                    if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                    if (caps.get(capIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
                     {
                         capList.add(
-                            new Capability(
+                            new CapabilityImpl(
                                 this,
-                                caps[capIdx].getNamespace(),
-                                ((Capability) caps[capIdx]).getDirectives(),
-                                ((Capability) caps[capIdx]).getAttributes()));
+                                caps.get(capIdx).getNamespace(),
+                                caps.get(capIdx).getDirectives(),
+                                caps.get(capIdx).getAttributes()));
                     }
                 }
             }
-            m_cachedCapabilities = (ICapability[])
-                capList.toArray(new ICapability[capList.size()]);
+            m_cachedCapabilities = Collections.unmodifiableList(capList);
         }
         return m_cachedCapabilities;
     }
 
-    public synchronized IRequirement[] getRequirements()
+    public synchronized List<Requirement> getRequirements()
     {
         if (m_cachedRequirements == null)
         {
-            List allReqs = new ArrayList();
-            Map pkgMap = new HashMap();
-            Map rbMap = new HashMap();
-            for (int i = 0; (m_requirements != null) && i < m_requirements.length; i++)
-            {
-                if (m_requirements[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                {
-                    pkgMap.put(
-                        ((Requirement) m_requirements[i]).getTargetName(),
-                        m_requirements[i]);
-                }
-                else if (m_requirements[i].getNamespace().equals(ICapability.MODULE_NAMESPACE))
-                {
-                    rbMap.put(
-                        ((Requirement) m_requirements[i]).getTargetName(),
-                        m_requirements[i]);
-                }
-                else
-                {
-                    allReqs.add(m_requirements[i]);
-                }
-            }
-
-            // Aggregate host and fragment bundle and package requirements.
+            List<Requirement> reqList = (m_requirements == null)
+                ? new ArrayList() : new ArrayList(m_requirements);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                IRequirement[] reqs = m_fragments[fragIdx].getRequirements();
+                List<Requirement> reqs = m_fragments.get(fragIdx).getRequirements();
                 for (int reqIdx = 0;
-                    (reqs != null) && (reqIdx < reqs.length);
+                    (reqs != null) && (reqIdx < reqs.size());
                     reqIdx++)
                 {
-                    if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                    if (reqs.get(reqIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+                        || reqs.get(reqIdx).getNamespace().equals(Capability.MODULE_NAMESPACE))
                     {
-                        // If the current fragment requirement overlaps a previously
-                        // added requirement, then calculate a new intersecting requirement.
-                        Requirement req = (Requirement) pkgMap.get(
-                            ((Requirement) reqs[reqIdx]).getTargetName());
-                        if (req != null)
-                        {
-                            req = FelixResolverState.calculateVersionIntersection(
-                                req, (Requirement) reqs[reqIdx]);
-                        }
-                        else
-                        {
-                            req = (Requirement) reqs[reqIdx];
-                        }
-                        pkgMap.put(req.getTargetName(), req);
-                    }
-                    else if (reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
-                    {
-                        // If the current fragment requirement overlaps a previously
-                        // added requirement, then calculate a new intersecting requirement.
-                        Requirement req = (Requirement) pkgMap.get(
-                            ((Requirement) reqs[reqIdx]).getTargetName());
-                        if (req != null)
-                        {
-                            req = FelixResolverState.calculateVersionIntersection(
-                                req, (Requirement) reqs[reqIdx]);
-                        }
-                        else
-                        {
-                            req = (Requirement) reqs[reqIdx];
-                        }
-                        rbMap.put(req.getTargetName(), req);
+                        reqList.add(
+                            new FragmentRequirement(
+                                reqs.get(reqIdx), m_fragments.get(fragIdx)));
                     }
                 }
             }
-            allReqs.addAll(pkgMap.values());
-            allReqs.addAll(rbMap.values());
-            m_cachedRequirements = (IRequirement[])
-                allReqs.toArray(new IRequirement[allReqs.size()]);
+            m_cachedRequirements = Collections.unmodifiableList(reqList);
         }
         return m_cachedRequirements;
     }
 
-    public synchronized IRequirement[] getDynamicRequirements()
+    public synchronized List<Requirement> getDynamicRequirements()
     {
         if (m_cachedDynamicRequirements == null)
         {
-            List reqList = (m_dynamicRequirements == null)
-                ? new ArrayList() : new ArrayList(Arrays.asList(m_dynamicRequirements));
+            List<Requirement> reqList = (m_dynamicRequirements == null)
+                ? new ArrayList() : new ArrayList(m_dynamicRequirements);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                IRequirement[] reqs = m_fragments[fragIdx].getDynamicRequirements();
+                List<Requirement> reqs = m_fragments.get(fragIdx).getDynamicRequirements();
                 for (int reqIdx = 0;
-                    (reqs != null) && (reqIdx < reqs.length);
+                    (reqs != null) && (reqIdx < reqs.size());
                     reqIdx++)
                 {
-                    if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                    if (reqs.get(reqIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
                     {
-                        reqList.add(reqs[reqIdx]);
+                        reqList.add(reqs.get(reqIdx));
                     }
                 }
             }
-            m_cachedDynamicRequirements = (IRequirement[])
-                reqList.toArray(new IRequirement[reqList.size()]);
+            m_cachedDynamicRequirements = Collections.unmodifiableList(reqList);
         }
         return m_cachedDynamicRequirements;
     }
 
-    public synchronized R4Library[] getNativeLibraries()
+    public synchronized List<R4Library> getNativeLibraries()
     {
-        R4Library[] result = null;
+        List<R4Library> result = null;
         if (m_isResolved)
         {
-            List nativeList = (m_nativeLibraries == null)
-                ? new ArrayList() : new ArrayList(Arrays.asList(m_nativeLibraries));
+            List<R4Library> nativeList = (m_nativeLibraries == null)
+                ? new ArrayList() : new ArrayList(m_nativeLibraries);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                R4Library[] libs = m_fragments[fragIdx].getNativeLibraries();
+                List<R4Library> libs = m_fragments.get(fragIdx).getNativeLibraries();
                 for (int reqIdx = 0;
-                    (libs != null) && (reqIdx < libs.length);
+                    (libs != null) && (reqIdx < libs.size());
                     reqIdx++)
                 {
-                    nativeList.add(libs[reqIdx]);
+                    nativeList.add(libs.get(reqIdx));
                 }
             }
 
@@ -434,7 +390,7 @@
             // could not be found when resolving the bundle.
             result = (nativeList.size() == 0)
                 ? null
-                : (R4Library[]) nativeList.toArray(new R4Library[nativeList.size()]);
+                : Collections.unmodifiableList(nativeList);
         }
         else
         {
@@ -465,20 +421,20 @@
         // by default, otherwise try to find one match.
         boolean included = (m_activationIncludes == null);
         for (int i = 0;
-            (!included) && (m_activationIncludes != null) && (i < m_activationIncludes.length);
+            (!included) && (m_activationIncludes != null) && (i < m_activationIncludes.size());
             i++)
         {
-            included = m_activationIncludes[i].equals(pkgName);
+            included = m_activationIncludes.get(i).equals(pkgName);
         }
 
         // If there are no exclude filters then no classes are excluded
         // by default, otherwise try to find one match.
         boolean excluded = false;
         for (int i = 0;
-            (!excluded) && (m_activationExcludes != null) && (i < m_activationExcludes.length);
+            (!excluded) && (m_activationExcludes != null) && (i < m_activationExcludes.size());
             i++)
         {
-            excluded = m_activationExcludes[i].equals(pkgName);
+            excluded = m_activationExcludes.get(i).equals(pkgName);
         }
         return included && !excluded;
     }
@@ -497,40 +453,40 @@
         return m_id;
     }
 
-    public synchronized IWire[] getWires()
+    public synchronized List<Wire> getWires()
     {
         return m_wires;
     }
 
-    public synchronized void setWires(IWire[] wires)
+    public synchronized void setWires(List<Wire> wires)
     {
         // Remove module from old wire modules' dependencies,
         // since we are no longer dependent on any the moduels
         // from the old wires.
-        for (int i = 0; (m_wires != null) && (i < m_wires.length); i++)
+        for (int i = 0; (m_wires != null) && (i < m_wires.size()); i++)
         {
-            if (m_wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            if (m_wires.get(i).getCapability().getNamespace().equals(Capability.MODULE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).removeDependentRequirer(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).removeDependentRequirer(this);
             }
-            else if (m_wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            else if (m_wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).removeDependentImporter(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).removeDependentImporter(this);
             }
         }
 
         m_wires = wires;
 
         // Add ourself as a dependent to the new wires' modules.
-        for (int i = 0; (m_wires != null) && (i < m_wires.length); i++)
+        for (int i = 0; (m_wires != null) && (i < m_wires.size()); i++)
         {
-            if (m_wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            if (m_wires.get(i).getCapability().getNamespace().equals(Capability.MODULE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).addDependentRequirer(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).addDependentRequirer(this);
             }
-            else if (m_wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            else if (m_wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).addDependentImporter(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).addDependentImporter(this);
             }
         }
     }
@@ -549,12 +505,12 @@
     // Content access methods.
     //
 
-    public IContent getContent()
+    public Content getContent()
     {
         return m_content;
     }
 
-    private synchronized IContent[] getContentPath()
+    private synchronized Content[] getContentPath()
     {
         if (m_contentPath == null)
         {
@@ -570,19 +526,19 @@
         return m_contentPath;
     }
 
-    private IContent[] initializeContentPath() throws Exception
+    private Content[] initializeContentPath() throws Exception
     {
         List contentList = new ArrayList();
         calculateContentPath(this, m_content, contentList, true);
         for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
         {
-            calculateContentPath(m_fragments[i], m_fragmentContents[i], contentList, false);
+            calculateContentPath(m_fragments.get(i), m_fragmentContents[i], contentList, false);
         }
-        return (IContent[]) contentList.toArray(new IContent[contentList.size()]);
+        return (Content[]) contentList.toArray(new Content[contentList.size()]);
     }
 
     private List calculateContentPath(
-        IModule module, IContent content, List contentList, boolean searchFragments)
+        Module module, Content content, List contentList, boolean searchFragments)
         throws Exception
     {
         // Creating the content path entails examining the bundle's
@@ -596,25 +552,25 @@
         // Find class path meta-data.
         String classPath = (String) module.getHeaders().get(FelixConstants.BUNDLE_CLASSPATH);
         // Parse the class path into strings.
-        String[] classPathStrings = ManifestParser.parseDelimitedString(
+        List<String> classPathStrings = ManifestParser.parseDelimitedString(
             classPath, FelixConstants.CLASS_PATH_SEPARATOR);
 
         if (classPathStrings == null)
         {
-            classPathStrings = new String[0];
+            classPathStrings = new ArrayList<String>(0);
         }
 
         // Create the bundles class path.
-        for (int i = 0; i < classPathStrings.length; i++)
+        for (int i = 0; i < classPathStrings.size(); i++)
         {
             // Remove any leading slash, since all bundle class path
             // entries are relative to the root of the bundle.
-            classPathStrings[i] = (classPathStrings[i].startsWith("/"))
-                ? classPathStrings[i].substring(1)
-                : classPathStrings[i];
+            classPathStrings.set(i, (classPathStrings.get(i).startsWith("/"))
+                ? classPathStrings.get(i).substring(1)
+                : classPathStrings.get(i));
 
             // Check for the bundle itself on the class path.
-            if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
+            if (classPathStrings.get(i).equals(FelixConstants.CLASS_PATH_DOT))
             {
                 localContentList.add(content);
             }
@@ -622,7 +578,7 @@
             {
                 // Try to find the embedded class path entry in the current
                 // content.
-                IContent embeddedContent = content.getEntryAsContent(classPathStrings[i]);
+                Content embeddedContent = content.getEntryAsContent(classPathStrings.get(i));
                 // If the embedded class path entry was not found, it might be
                 // in one of the fragments if the current content is the bundle,
                 // so try to search the fragments if necessary.
@@ -631,7 +587,8 @@
                         && (m_fragmentContents != null) && (fragIdx < m_fragmentContents.length);
                     fragIdx++)
                 {
-                    embeddedContent = m_fragmentContents[fragIdx].getEntryAsContent(classPathStrings[i]);
+                    embeddedContent =
+                        m_fragmentContents[fragIdx].getEntryAsContent(classPathStrings.get(i));
                 }
                 // If we found the embedded content, then add it to the
                 // class path content list.
@@ -645,7 +602,7 @@
 //       need to create an "Eventer" class like "Logger" perhaps.
                     m_logger.log(Logger.LOG_INFO,
                         "Class path entry not found: "
-                        + classPathStrings[i]);
+                        + classPathStrings.get(i));
                 }
             }
         }
@@ -840,7 +797,7 @@
         }
 
         // Check the module class path.
-        IContent[] contentPath = getContentPath();
+        Content[] contentPath = getContentPath();
         for (int i = 0;
             (url == null) &&
             (i < contentPath.length); i++)
@@ -936,15 +893,15 @@
 
         // Note that the search may be aborted if this method throws an
         // exception, otherwise it continues if a null is returned.
-        IWire[] wires = getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        List<Wire> wires = getWires();
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
-            if (wires[i] instanceof R4Wire)
+            if (wires.get(i) instanceof WireImpl)
             {
                 try
                 {
                     // If we find the class or resource, then return it.
-                    urls = wires[i].getResources(name);
+                    urls = wires.get(i).getResources(name);
                 }
                 catch (ResourceNotFoundException ex)
                 {
@@ -962,14 +919,14 @@
         // See whether we can get the resource from the required bundles and
         // regardless of whether or not this is the case continue to the next
         // step potentially passing on the result of this search (if any).
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
-            if (wires[i] instanceof R4WireModule)
+            if (wires.get(i) instanceof WireModuleImpl)
             {
                 try
                 {
                     // If we find the class or resource, then add it.
-                    urls = wires[i].getResources(name);
+                    urls = wires.get(i).getResources(name);
                 }
                 catch (ResourceNotFoundException ex)
                 {
@@ -996,10 +953,10 @@
             // At this point, the module's imports were searched and so was the
             // the module's content. Now we make an attempt to load the
             // class/resource via a dynamic import, if possible.
-            IWire wire = null;
+            Wire wire = null;
             try
             {
-                wire = m_resolver.resolveDynamicImport(this, pkgName);
+                wire = m_resolver.resolve(this, pkgName);
             }
             catch (ResolveException ex)
             {
@@ -1033,7 +990,7 @@
         // Special case "/" so that it returns a root URLs for
         // each bundle class path entry...this isn't very
         // clean or meaningful, but the Spring guys want it.
-        final IContent[] contentPath = getContentPath();
+        final Content[] contentPath = getContentPath();
         if (name.equals("/"))
         {
             for (int i = 0; i < contentPath.length; i++)
@@ -1139,8 +1096,8 @@
 
          try
          {
-             return m_secureAction.createURL(null, 
-                 FelixConstants.BUNDLE_URL_PROTOCOL + "://" +  
+             return m_secureAction.createURL(null,
+                 FelixConstants.BUNDLE_URL_PROTOCOL + "://" +
                  m_id + ":" + port + path, m_streamHandler);
          }
          catch (MalformedURLException ex)
@@ -1157,19 +1114,19 @@
     // Fragment and dependency management methods.
     //
 
-    public synchronized IModule[] getFragments()
+    public synchronized List<Module> getFragments()
     {
         return m_fragments;
     }
 
-    public synchronized void attachFragments(IModule[] fragments) throws Exception
+    public synchronized void attachFragments(List<Module> fragments) throws Exception
     {
         // Remove module from old fragment dependencies.
         // We will generally only remove module fragment
         // dependencies when we are uninstalling the module.
-        for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+        for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++)
         {
-            ((ModuleImpl) m_fragments[i]).removeDependentHost(this);
+            ((ModuleImpl) m_fragments.get(i)).removeDependentHost(this);
         }
 
         // Remove cached capabilities and requirements.
@@ -1185,12 +1142,12 @@
         // to attach to our content loader.
         if (m_fragments != null)
         {
-            IContent[] fragmentContents = new IContent[m_fragments.length];
-            for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+            Content[] fragmentContents = new Content[m_fragments.size()];
+            for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++)
             {
-                ((ModuleImpl) m_fragments[i]).addDependentHost(this);
+                ((ModuleImpl) m_fragments.get(i)).addDependentHost(this);
                 fragmentContents[i] =
-                    m_fragments[i].getContent()
+                    m_fragments.get(i).getContent()
                         .getEntryAsContent(FelixConstants.CLASS_PATH_DOT);
             }
             // Now attach the fragment contents to our content loader.
@@ -1199,7 +1156,7 @@
     }
 
     // This must be called holding the object lock.
-    private void attachFragmentContents(IContent[] fragmentContents)
+    private void attachFragmentContents(Content[] fragmentContents)
         throws Exception
     {
         // Close existing fragment contents.
@@ -1222,123 +1179,70 @@
         m_contentPath = initializeContentPath();
     }
 
-    public synchronized IModule[] getDependentHosts()
+    public synchronized List<Module> getDependentHosts()
     {
         return m_dependentHosts;
     }
 
-    public synchronized void addDependentHost(IModule module)
+    public synchronized void addDependentHost(Module module)
     {
-        m_dependentHosts = addDependent(m_dependentHosts, module);
+        if (!m_dependentHosts.contains(module))
+        {
+            m_dependentHosts.add(module);
+        }
     }
 
-    public synchronized void removeDependentHost(IModule module)
+    public synchronized void removeDependentHost(Module module)
     {
-        m_dependentHosts = removeDependent(m_dependentHosts, module);
+        m_dependentHosts.remove(module);
     }
 
-    public synchronized IModule[] getDependentImporters()
+    public synchronized List<Module> getDependentImporters()
     {
         return m_dependentImporters;
     }
 
-    public synchronized void addDependentImporter(IModule module)
+    public synchronized void addDependentImporter(Module module)
     {
-        m_dependentImporters = addDependent(m_dependentImporters, module);
+        if (!m_dependentImporters.contains(module))
+        {
+            m_dependentImporters.add(module);
+        }
     }
 
-    public synchronized void removeDependentImporter(IModule module)
+    public synchronized void removeDependentImporter(Module module)
     {
-        m_dependentImporters = removeDependent(m_dependentImporters, module);
+        m_dependentImporters.remove(module);
     }
 
-    public synchronized IModule[] getDependentRequirers()
+    public synchronized List<Module> getDependentRequirers()
     {
         return m_dependentRequirers;
     }
 
-    public synchronized void addDependentRequirer(IModule module)
+    public synchronized void addDependentRequirer(Module module)
     {
-        m_dependentRequirers = addDependent(m_dependentRequirers, module);
+        if (!m_dependentRequirers.contains(module))
+        {
+            m_dependentRequirers.add(module);
+        }
     }
 
-    public synchronized void removeDependentRequirer(IModule module)
+    public synchronized void removeDependentRequirer(Module module)
     {
-        m_dependentRequirers = removeDependent(m_dependentRequirers, module);
+        m_dependentRequirers.remove(module);
     }
 
-    public synchronized IModule[] getDependents()
+    public synchronized List<Module> getDependents()
     {
-        IModule[] dependents = new IModule[
-            m_dependentHosts.length + m_dependentImporters.length + m_dependentRequirers.length];
-        System.arraycopy(
-            m_dependentHosts,
-            0,
-            dependents,
-            0,
-            m_dependentHosts.length);
-        System.arraycopy(
-            m_dependentImporters,
-            0,
-            dependents,
-            m_dependentHosts.length,
-            m_dependentImporters.length);
-        System.arraycopy(
-            m_dependentRequirers,
-            0,
-            dependents,
-            m_dependentHosts.length + m_dependentImporters.length,
-            m_dependentRequirers.length);
+        List<Module> dependents = new ArrayList<Module>
+            (m_dependentHosts.size() + m_dependentImporters.size() + m_dependentRequirers.size());
+        dependents.addAll(m_dependentHosts);
+        dependents.addAll(m_dependentImporters);
+        dependents.addAll(m_dependentRequirers);
         return dependents;
     }
 
-    private static IModule[] addDependent(IModule[] modules, IModule module)
-    {
-        // Make sure the dependent module is not already present.
-        for (int i = 0; i < modules.length; i++)
-        {
-            if (modules[i].equals(module))
-            {
-                return modules;
-            }
-        }
-        IModule[] tmp = new IModule[modules.length + 1];
-        System.arraycopy(modules, 0, tmp, 0, modules.length);
-        tmp[modules.length] = module;
-        return tmp;
-    }
-
-    private static IModule[] removeDependent(IModule[] modules, IModule module)
-    {
-        IModule[] tmp = modules;
-
-        // Make sure the dependent module is present.
-        for (int i = 0; i < modules.length; i++)
-        {
-            if (modules[i].equals(module))
-            {
-                // If this is the module, then point to empty list.
-                if ((modules.length - 1) == 0)
-                {
-                    tmp = new IModule[0];
-                }
-                // Otherwise, we need to do some array copying.
-                else
-                {
-                    tmp = new IModule[modules.length - 1];
-                    System.arraycopy(modules, 0, tmp, 0, i);
-                    if (i < tmp.length)
-                    {
-                        System.arraycopy(modules, i + 1, tmp, i, tmp.length - i);
-                    }
-                }
-                break;
-            }
-        }
-
-        return tmp;
-    }
-
     public synchronized void close()
     {
         m_content.close();
@@ -1433,13 +1337,13 @@
         throws ClassNotFoundException, ResourceNotFoundException
     {
         // We delegate to the module's wires to find the class or resource.
-        IWire[] wires = getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        List<Wire> wires = getWires();
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
             // If we find the class or resource, then return it.
             Object result = (isClass)
-                ? (Object) wires[i].getClass(name)
-                : (Object) wires[i].getResource(name);
+                ? (Object) wires.get(i).getClass(name)
+                : (Object) wires.get(i).getResource(name);
             if (result != null)
             {
                 return result;
@@ -1456,10 +1360,10 @@
         // At this point, the module's imports were searched and so was the
         // the module's content. Now we make an attempt to load the
         // class/resource via a dynamic import, if possible.
-        IWire wire = null;
+        Wire wire = null;
         try
         {
-            wire = m_resolver.resolveDynamicImport(this, pkgName);
+            wire = m_resolver.resolve(this, pkgName);
         }
         catch (ResolveException ex)
         {
@@ -1772,8 +1676,8 @@
                 byte[] bytes = null;
 
                 // Check the module class path.
-                IContent[] contentPath = getContentPath();
-                IContent content = null;
+                Content[] contentPath = getContentPath();
+                Content content = null;
                 for (int i = 0;
                     (bytes == null) &&
                     (i < contentPath.length); i++)
@@ -1799,7 +1703,7 @@
                             int activationPolicy = 
                                 ((BundleImpl) getBundle()).isDeclaredActivationPolicyUsed()
                                 ? ((BundleImpl) getBundle()).getCurrentModule().getDeclaredActivationPolicy()
-                                : IModule.EAGER_ACTIVATION;
+                                : Module.EAGER_ACTIVATION;
 
                             // If the module is using deferred activation, then if
                             // we load this class from this module we need to activate
@@ -1810,7 +1714,7 @@
                                 ? false : isActivationTrigger(pkgName);
                             if (!m_isActivationTriggered
                                 && isTriggerClass
-                                && (activationPolicy == IModule.LAZY_ACTIVATION)
+                                && (activationPolicy == Module.LAZY_ACTIVATION)
                                 && (getBundle().getState() == Bundle.STARTING))
                             {
                                 List deferredList = (List) m_deferredActivation.get();
@@ -2027,14 +1931,14 @@
                 // native library.
                 if (result == null)
                 {
-                    R4Library[] libs = getNativeLibraries();
-                    for (int libIdx = 0; (libs != null) && (libIdx < libs.length); libIdx++)
+                    List<R4Library> libs = getNativeLibraries();
+                    for (int libIdx = 0; (libs != null) && (libIdx < libs.size()); libIdx++)
                     {
-                        if (libs[libIdx].match(m_configMap, name))
+                        if (libs.get(libIdx).match(m_configMap, name))
                         {
                             // Search bundle content first for native library.
                             result = getContent().getEntryAsNativeLibrary(
-                                libs[libIdx].getEntryName());
+                                libs.get(libIdx).getEntryName());
                             // If not found, then search fragments in order.
                             for (int i = 0;
                                 (result == null) && (m_fragmentContents != null)
@@ -2042,7 +1946,7 @@
                                 i++)
                             {
                                 result = m_fragmentContents[i].getEntryAsNativeLibrary(
-                                    libs[libIdx].getEntryName());
+                                    libs.get(libIdx).getEntryName());
                             }
                         }
                     }
@@ -2084,13 +1988,13 @@
         String importer = module.getBundle().toString();
 
         // Next, check to see if the module imports the package.
-        IWire[] wires = module.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].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-                wires[i].getCapability().getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
+            if (wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE) &&
+                wires.get(i).getCapability().getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
             {
-                String exporter = wires[i].getExporter().getBundle().toString();
+                String exporter = wires.get(i).getExporter().getBundle().toString();
 
                 StringBuffer sb = new StringBuffer("*** Package '");
                 sb.append(pkgName);
@@ -2114,7 +2018,7 @@
 
         // Next, check to see if the package was optionally imported and
         // whether or not there is an exporter available.
-        IRequirement[] reqs = module.getRequirements();
+        List<Requirement> reqs = module.getRequirements();
 /*
 * TODO: RB - Fix diagnostic message for optional imports.
         for (int i = 0; (reqs != null) && (i < reqs.length); i++)
@@ -2174,7 +2078,9 @@
         }
 */
         // Next, check to see if the package is dynamically imported by the module.
-        IRequirement pkgReq = Resolver.findAllowedDynamicImport(module, pkgName);
+// TODO: FELIX3 - Add Resolver.findAllowedDynamicImport().
+/*
+        Requirement pkgReq = Resolver.findAllowedDynamicImport(module, pkgName);
         if (pkgReq != null)
         {
             // Try to see if there is an exporter available.
@@ -2228,22 +2134,14 @@
 
             return sb.toString();
         }
-
+*/
         // Next, check to see if there are any exporters for the package at all.
-        pkgReq = null;
-        try
-        {
-            pkgReq = new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
-        }
-        catch (InvalidSyntaxException ex)
-        {
-            // This should never happen.
-        }
-        List exports =
-            resolver.getResolvedCandidates(pkgReq, module);
-        exports = (exports.size() == 0)
-            ? resolver.getUnresolvedCandidates(pkgReq, module)
-            : exports;
+        Requirement pkgReq = null;
+        List<Attribute> attrs = new ArrayList(1);
+        attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
+        pkgReq = new RequirementImpl(
+            Capability.PACKAGE_NAMESPACE, new ArrayList<Directive>(0), attrs);
+        Set<Capability> exports = resolver.getCandidates(module, pkgReq, false);
         if (exports.size() > 0)
         {
             boolean classpath = false;
@@ -2261,7 +2159,7 @@
                 // Ignore
             }
 
-            String exporter = ((ICapability) exports.get(0)).getModule().getBundle().toString();
+            String exporter = exports.iterator().next().getModule().getBundle().toString();
 
             StringBuffer sb = new StringBuffer("*** Class '");
             sb.append(name);
@@ -2345,4 +2243,46 @@
 
         return sb.toString();
     }
-}
+
+    static class FragmentRequirement implements Requirement
+    {
+        private final Requirement m_req;
+        private final Module m_fragment;
+
+        public FragmentRequirement(Requirement req, Module fragment)
+        {
+            m_req = req;
+            m_fragment = fragment;
+        }
+
+        public Module getFragment()
+        {
+            return m_fragment;
+        }
+
+        public String getNamespace()
+        {
+            return m_req.getNamespace();
+        }
+
+        public SimpleFilter getFilter()
+        {
+            return m_req.getFilter();
+        }
+
+        public boolean isOptional()
+        {
+            return m_req.isOptional();
+        }
+
+        public Directive getDirective(String name)
+        {
+            return m_req.getDirective(name);
+        }
+
+        public List<Directive> getDirectives()
+        {
+            return m_req.getDirectives();
+        }
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
new file mode 100644
index 0000000..04edb93
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
@@ -0,0 +1,499 @@
+/*
+ *  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.capabilityset;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+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;
+
+public class CapabilitySet
+{
+    private final Map<String, Map<Object, Set<Capability>>> m_indices =
+        new HashMap<String, Map<Object, Set<Capability>>>();
+    private final Set<Capability> m_capList = new HashSet<Capability>();
+
+    public CapabilitySet(List<String> indexProps)
+    {
+        for (int i = 0; (indexProps != null) && (i < indexProps.size()); i++)
+        {
+            m_indices.put(indexProps.get(i), new HashMap<Object, Set<Capability>>());
+        }
+    }
+
+    public void addCapability(Capability cap)
+    {
+        m_capList.add(cap);
+
+        // Index capability.
+        for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+        {
+            Attribute capAttr = cap.getAttribute(entry.getKey());
+            if (capAttr != null)
+            {
+                Object capValue = capAttr.getValue();
+                if (capValue.getClass().isArray())
+                {
+                    capValue = convertArrayToList(capValue);
+                }
+
+                Map<Object, Set<Capability>> index = entry.getValue();
+
+                if (capValue instanceof Collection)
+                {
+                    Collection c = (Collection) capValue;
+                    for (Object o : c)
+                    {
+                        indexCapability(index, cap, o);
+                    }
+                }
+                else
+                {
+                    indexCapability(index, cap, capValue);
+                }
+            }
+        }
+
+//        System.out.println("+++ INDICES " + m_indices);
+    }
+
+    private void indexCapability(
+        Map<Object, Set<Capability>> index, Capability cap, Object capValue)
+    {
+        Set<Capability> caps = index.get(capValue);
+        if (caps == null)
+        {
+            caps = new HashSet<Capability>();
+            index.put(capValue, caps);
+        }
+        caps.add(cap);
+    }
+
+    public void removeCapability(Capability cap)
+    {
+        if (m_capList.remove(cap))
+        {
+            for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+            {
+                Attribute capAttr = cap.getAttribute(entry.getKey());
+                if (capAttr != null)
+                {
+                    Object capValue = capAttr.getValue();
+                    if (capValue.getClass().isArray())
+                    {
+                        capValue = convertArrayToList(capValue);
+                    }
+
+                    Map<Object, Set<Capability>> index = entry.getValue();
+
+                    if (capValue instanceof Collection)
+                    {
+                        Collection c = (Collection) capValue;
+                        for (Object o : c)
+                        {
+                            deindexCapability(index, cap, o);
+                        }
+                    }
+                    else
+                    {
+                        deindexCapability(index, cap, capValue);
+                    }
+                }
+            }
+
+//            System.out.println("+++ INDICES " + m_indices);
+        }
+    }
+
+    private void deindexCapability(
+        Map<Object, Set<Capability>> index, Capability cap, Object capValue)
+    {
+        Set<Capability> caps = index.get(capValue);
+        caps.remove(cap);
+        if (caps.size() == 0)
+        {
+            index.remove(capValue);
+        }
+    }
+
+    public Set<Capability> match(SimpleFilter sf, boolean obeyMandatory)
+    {
+        Set<Capability> matches = match(m_capList, sf);
+        return (obeyMandatory)
+            ? matchMandatory(matches, sf)
+            : matches;
+    }
+
+    private Set<Capability> match(Set<Capability> caps, SimpleFilter sf)
+    {
+//System.out.println("+++ SF " + sf);
+        Set<Capability> matches = new HashSet<Capability>();
+
+        if (sf.getOperation() == SimpleFilter.AND)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For AND we calculate the intersection of each subfilter.
+            // We can short-circuit the AND operation if there are no
+            // remaining capabilities.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; (caps.size() > 0) && (i < sfs.size()); i++)
+            {
+//System.out.println("+++ REMAINING " + caps);
+                matches = match(caps, sfs.get(i));
+//System.out.println("+++ CURRENT " + matches);
+                caps = matches;
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.OR)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.addAll(match(caps, sfs.get(i)));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.NOT)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            matches.addAll(caps);
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.removeAll(match(caps, sfs.get(i)));
+            }
+        }
+        else
+        {
+            Map<Object, Set<Capability>> index = m_indices.get(sf.getName());
+            if ((sf.getOperation() == SimpleFilter.EQ) && (index != null))
+            {
+                Set<Capability> existingCaps = index.get(sf.getValue());
+                if (existingCaps != null)
+                {
+                    matches.addAll(existingCaps);
+//System.out.println("NARROWED " + caps.size() + " TO " + existingCaps.size());
+                    matches.retainAll(caps);
+                }
+            }
+            else
+            {
+//                System.out.println("+++ SEARCHING " + caps.size() + " CAPABILITIES");
+                for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+                {
+                    Capability cap = it.next();
+                    Attribute attr = cap.getAttribute(sf.getName());
+                    if (attr != null)
+                    {
+                        Object lhs = attr.getValue();
+                        if (compare(lhs, sf.getValue(), sf.getOperation()))
+                        {
+                            matches.add(cap);
+                        }
+                    }
+                }
+            }
+        }
+
+        return matches;
+    }
+
+    public static boolean matches(Capability cap, SimpleFilter sf)
+    {
+        return matchesInternal(cap, sf) && matchMandatory(cap, sf);
+    }
+
+    private static boolean matchesInternal(Capability cap, SimpleFilter sf)
+    {
+        boolean matched = true;
+
+        if (sf.getOperation() == SimpleFilter.AND)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For AND we calculate the intersection of each subfilter.
+            // We can short-circuit the AND operation if there are no
+            // remaining capabilities.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; matched && (i < sfs.size()); i++)
+            {
+                matched = matchesInternal(cap, sfs.get(i));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.OR)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            matched = false;
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; !matched && (i < sfs.size()); i++)
+            {
+                matched = matchesInternal(cap, sfs.get(i));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.NOT)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matched = !(matchesInternal(cap, sfs.get(i)));
+            }
+        }
+        else
+        {
+            matched = false;
+            Attribute attr = cap.getAttribute(sf.getName());
+            if (attr != null)
+            {
+                Object lhs = attr.getValue();
+                matched = compare(lhs, sf.getValue(), sf.getOperation());
+            }
+        }
+
+        return matched;
+    }
+
+    private static Set<Capability> matchMandatory(Set<Capability> caps, SimpleFilter sf)
+    {
+        for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+        {
+            Capability cap = it.next();
+            if (!matchMandatory(cap, sf))
+            {
+                it.remove();
+            }
+        }
+        return caps;
+    }
+
+    private static boolean matchMandatory(Capability cap, SimpleFilter sf)
+    {
+        List<Attribute> attrs = cap.getAttributes();
+        for (int attrIdx = 0; attrIdx < attrs.size(); attrIdx++)
+        {
+            if (attrs.get(attrIdx).isMandatory()
+                && !matchMandatory(attrs.get(attrIdx), sf))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean matchMandatory(Attribute attr, SimpleFilter sf)
+    {
+        if ((sf.getName() != null) && sf.getName().equals(attr.getName()))
+        {
+            return true;
+        }
+        else if (sf.getOperation() == SimpleFilter.AND)
+        {
+            List list = (List) sf.getValue();
+            for (int i = 0; i < list.size(); i++)
+            {
+                SimpleFilter sf2 = (SimpleFilter) list.get(i);
+                if ((sf2.getName() != null)
+                    && sf2.getName().equals(attr.getName()))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static final Class[] STRING_CLASS = new Class[] { String.class };
+
+    private static boolean compare(Object lhs, Object rhsUnknown, int op)
+    {
+        // If the type is comparable, then we can just return the
+        // result immediately.
+        if (lhs instanceof Comparable)
+        {
+            // The substring operator only works on string values, so if the
+            // lhs is not a string, then do an equality comparison using the
+            // original string containing wildcards.
+            if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
+            {
+                op = SimpleFilter.EQ;
+                rhsUnknown = SimpleFilter.unparseSubstring((List<String>) rhsUnknown);
+            }
+
+            Object rhs;
+            if (op == SimpleFilter.SUBSTRING)
+            {
+                rhs = rhsUnknown;
+            }
+            else
+            {
+                try
+                {
+                    rhs = coerceType(lhs, (String) rhsUnknown);
+                }
+                catch (Exception ex)
+                {
+                    return false;
+                }
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                    return (((Comparable) lhs).compareTo(rhs) == 0);
+                case SimpleFilter.GTE :
+                    return (((Comparable) lhs).compareTo(rhs) >= 0);
+                case SimpleFilter.LTE :
+                    return (((Comparable) lhs).compareTo(rhs) <= 0);
+//                case SimpleFilter.APPROX :
+//                    return compareToApprox(((Comparable) lhs), rhs);
+                case SimpleFilter.SUBSTRING :
+                    return SimpleFilter.compareSubstring((String) lhs, (List<String>) rhs);
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+        // Booleans do not implement comparable, so special case them.
+        else if (lhs instanceof Boolean)
+        {
+            Object rhs;
+            try
+            {
+                rhs = coerceType(lhs, (String) rhsUnknown);
+            }
+            catch (Exception ex)
+            {
+                return false;
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                case SimpleFilter.GTE :
+                case SimpleFilter.LTE :
+//                case SimpleFilter.APPROX:
+                    return (lhs.equals(rhs));
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+
+        // If the LHS is not a comparable or boolean, check if it is an
+        // array. If so, convert it to a list so we can treat it as a
+        // collection.
+        if (lhs.getClass().isArray())
+        {
+            lhs = convertArrayToList(lhs);
+        }
+
+        // If LHS is a collection, then call compare() on each element
+        // of the collection until a match is found.
+        if (lhs instanceof Collection)
+        {
+            for (Iterator iter = ((Collection) lhs).iterator(); iter.hasNext(); )
+            {
+                if (compare(iter.next(), rhsUnknown, op))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        // Since we cannot identify the LHS type, then we can only perform
+        // equality comparison.
+        try
+        {
+            return lhs.equals(coerceType(lhs, (String) rhsUnknown));
+        }
+        catch (Exception ex)
+        {
+            return false;
+        }
+    }
+
+    private static Object coerceType(Object lhs, String rhsString) throws Exception
+    {
+        // If the LHS expects a string, then we can just return
+        // the RHS since it is a string.
+        if (lhs.getClass() == rhsString.getClass())
+        {
+            return rhsString;
+        }
+
+        // Try to convert the RHS type to the LHS type by using
+        // the string constructor of the LHS class, if it has one.
+        Object rhs = null;
+        try
+        {
+            // The Character class is a special case, since its constructor
+            // does not take a string, so handle it separately.
+            if (lhs instanceof Character)
+            {
+                rhs = new Character(rhsString.charAt(0));
+            }
+            else
+            {
+                rhs = lhs.getClass()
+                    .getConstructor(STRING_CLASS)
+                        .newInstance(new Object[] { rhsString });
+            }
+        }
+        catch (Exception ex)
+        {
+            throw new Exception(
+                "Could not instantiate class "
+                    + lhs.getClass().getName()
+                    + " from string constructor with argument '"
+                    + rhsString + "' because " + ex);
+        }
+
+        return rhs;
+    }
+
+    /**
+     * This is an ugly utility method to convert an array of primitives
+     * to an array of primitive wrapper objects. This method simplifies
+     * processing LDAP filters since the special case of primitive arrays
+     * can be ignored.
+     * @param array An array of primitive types.
+     * @return An corresponding array using pritive wrapper objects.
+    **/
+    private static List convertArrayToList(Object array)
+    {
+        int len = Array.getLength(array);
+        List list = new ArrayList(len);
+        for (int i = 0; i < len; i++)
+        {
+            list.add(Array.get(array, i));
+        }
+        return list;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java b/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
new file mode 100644
index 0000000..b72ea49
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
@@ -0,0 +1,103 @@
+/*
+ *  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.resolver;
+
+import java.util.Comparator;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+public class CandidateComparator implements Comparator
+{
+    public int compare(Object arg1, Object arg2)
+    {
+        Capability cap1 = (Capability) arg1;
+        Capability cap2 = (Capability) arg2;
+
+        // First check resolved state, since resolved capabilities have priority
+        // over unresolved ones. Compare in reverse order since we want to sort
+        // in descending order.
+        int c = 0;
+        if (cap1.getModule().isResolved() && !cap2.getModule().isResolved())
+        {
+            c = -1;
+        }
+        else if (!cap1.getModule().isResolved() && cap2.getModule().isResolved())
+        {
+            c = 1;
+        }
+
+        // Next compare version numbers.
+        if ((c == 0) && cap1.getNamespace().equals(Capability.MODULE_NAMESPACE))
+        {
+            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 = (cap2.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE) == null)
+                    ? Version.emptyVersion
+                    : (Version) cap2.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE).getValue();
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = v2.compareTo(v1);
+            }
+        }
+// TODO: PROTO3 RESOLVER - Need to change this to handle arbitrary capabilities
+//       that may not have a natural ordering.
+        // Assume everything else is a package capability.
+        else if (c == 0)
+        {
+            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 = (cap2.getAttribute(Capability.VERSION_ATTR) == null)
+                    ? Version.emptyVersion
+                    : (Version) cap2.getAttribute(Capability.VERSION_ATTR).getValue();
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = v2.compareTo(v1);
+            }
+        }
+
+        // Finally, compare module identity.
+        if (c == 0)
+        {
+            if (cap1.getModule().getBundle().getBundleId() <
+                cap2.getModule().getBundle().getBundleId())
+            {
+                c = -1;
+            }
+            else if (cap1.getModule().getBundle().getBundleId() >
+                cap2.getModule().getBundle().getBundleId())
+            {
+                c = 1;
+            }
+        }
+
+        return c;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Content.java b/framework/src/main/java/org/apache/felix/framework/resolver/Content.java
new file mode 100644
index 0000000..3e13a19
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Content.java
@@ -0,0 +1,112 @@
+/*
+ * 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.resolver;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+
+public interface Content
+{
+    /**
+     * <p>
+     * This method must be called when the content is no longer needed so
+     * that any resourses being used (e.g., open files) can be closed. Once
+     * this method is called, the content is no longer usable. If the content
+     * is already closed, then calls on this method should have no effect.
+     * </p>
+    **/
+    void close();
+
+    /**
+     * <p>
+     * This method determines if the specified named entry is contained in
+     * the associated content. The entry name is a relative path with '/'
+     * separators.
+     * </p>
+     * @param name The name of the entry to find.
+     * @return <tt>true</tt> if a corresponding entry was found, <tt>false</tt>
+     *         otherwise.
+    **/
+    boolean hasEntry(String name);
+
+    /**
+     * <p>
+     * Returns an enumeration of entry names as <tt>String</tt> objects.
+     * An entry name is a path constructed with '/' as path element
+     * separators and is relative to the root of the content. Entry names
+     * for entries that represent directories should end with the '/'
+     * character.
+     * </p>
+     * @returns An enumeration of entry names or <tt>null</tt>.
+    **/
+    Enumeration getEntries();
+
+    /**
+     * <p>
+     * This method returns the named entry as an array of bytes.
+     * </p>
+     * @param name The name of the entry to retrieve as a byte array.
+     * @return An array of bytes if the corresponding entry was found, <tt>null</tt>
+     *         otherwise.
+    **/
+    byte[] getEntryAsBytes(String name);
+
+    /**
+     * <p>
+     * This method returns the named entry as an input stream.
+     * </p>
+     * @param name The name of the entry to retrieve as an input stream.
+     * @return An input stream if the corresponding entry was found, <tt>null</tt>
+     *         otherwise.
+     * @throws <tt>java.io.IOException</tt> if any error occurs.
+    **/
+    InputStream getEntryAsStream(String name) throws IOException;
+
+    /**
+     * <p>
+     * This method returns the named entry as an <tt>IContent</tt> Typically,
+     * this method only makes sense for entries that correspond to some form
+     * of aggregated resource (e.g., an embedded JAR file or directory), but
+     * implementations are free to interpret this however makes sense. This method
+     * should return a new <tt>IContent</tt> instance for every invocation and
+     * the caller is responsible for opening and closing the returned content
+     * object.
+     * </p>
+     * @param name The name of the entry to retrieve as an <tt>IContent</tt>.
+     * @return An <tt>IContent</tt> instance if a corresponding entry was found,
+     *         <tt>null</tt> otherwise.
+    **/
+    Content getEntryAsContent(String name);
+
+    /**
+     * <p>
+     * This method returns the named entry as a file in the file system for
+     * use as a native library. It may not be possible for all content
+     * implementations (e.g., memory only) to implement this method, in which
+     * case it is acceptable to return <tt>null</tt>. Since native libraries
+     * can only be associated with a single class loader, this method should
+     * return a unique file per request.
+     * </p>
+     * @param name The name of the entry to retrieve as a file.
+     * @return A string corresponding to the absolute path of the file if a
+     *         corresponding entry was found, <tt>null</tt> otherwise.
+    **/
+    String getEntryAsNativeLibrary(String name);
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Module.java b/framework/src/main/java/org/apache/felix/framework/resolver/Module.java
new file mode 100644
index 0000000..25258e9
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Module.java
@@ -0,0 +1,77 @@
+/*
+ *  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.resolver;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Requirement;
+import org.apache.felix.framework.util.manifestparser.R4Library;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+public interface Module
+{
+    final static int EAGER_ACTIVATION = 0;
+    final static int LAZY_ACTIVATION = 1;
+
+    // Metadata access methods.
+    Map getHeaders();
+    boolean isExtension();
+    String getSymbolicName();
+    Version getVersion();
+    List<Capability> getCapabilities();
+    List<Requirement> getRequirements();
+    List<Requirement> getDynamicRequirements();
+    List<R4Library> getNativeLibraries();
+    int getDeclaredActivationPolicy();
+
+    // Run-time data access methods.
+    Bundle getBundle();
+    String getId();
+    List<Wire> getWires();
+    boolean isResolved();
+    // TODO: FELIX3 - Shouldn't have mutable method on Module.
+    void setSecurityContext(Object securityContext);
+    Object getSecurityContext();
+
+    // Content access methods.
+    Content getContent();
+    Class getClassByDelegation(String name) throws ClassNotFoundException;
+    URL getResourceByDelegation(String name);
+    Enumeration getResourcesByDelegation(String name);
+    URL getEntry(String name);
+
+    // TODO: ML - For expediency, the index argument was added to these methods
+    // but it is not clear that this makes sense in the long run. This needs to
+    // be readdressed in the future, perhaps by the spec to clearly indicate
+    // how resources on the bundle class path are searched, which is why we
+    // need the index number in the first place -- to differentiate among
+    // resources with the same name on the bundle class path. This was previously
+    // handled as part of the resource path, but that approach is not spec
+    // compliant.
+    boolean hasInputStream(int index, String urlPath)
+        throws IOException;
+    InputStream getInputStream(int index, String urlPath)
+        throws IOException;
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java
new file mode 100755
index 0000000..e790856
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java
@@ -0,0 +1,48 @@
+/*
+ *  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.resolver;
+
+import org.apache.felix.framework.capabilityset.Requirement;
+
+public class ResolveException extends RuntimeException
+{
+    private final Module m_module;
+    private final Requirement m_req;
+
+    /**
+     * Constructs an instance of <code>ResolveException</code> with the specified detail message.
+     * @param msg the detail message.
+     */
+    public ResolveException(String msg, Module module, Requirement req)
+    {
+        super(msg);
+        m_module = module;
+        m_req = req;
+    }
+
+    public Module getModule()
+    {
+        return m_module;
+    }
+
+    public Requirement getRequirement()
+    {
+        return m_req;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java b/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
new file mode 100644
index 0000000..c8bd513
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
@@ -0,0 +1,36 @@
+/*
+ *  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.resolver;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Requirement;
+
+public interface Resolver
+{
+    Map<Module, List<Wire>> resolve(ResolverState state, Module module);
+    Map<Module, List<Wire>> resolve(ResolverState state, Module module, String pkgName);
+
+    public static interface ResolverState
+    {
+        Set<Capability> getCandidates(Module module, Requirement req, boolean obeyMandatory);
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
new file mode 100644
index 0000000..1a90baa
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
@@ -0,0 +1,1581 @@
+/*
+ *  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.resolver;
+
+import java.util.ArrayList;
+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.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.RequirementImpl;
+import org.osgi.framework.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 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 List<Wire> m_emptyWires = new ArrayList<Wire>(0);
+
+    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);
+    }
+
+    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)
+    {
+        Capability candidate = null;
+
+        // We can only create a dynamic import if the following
+        // conditions are met:
+        // 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.
+        Map<Requirement, Set<Capability>> candidateMap =
+            new HashMap<Requirement, Set<Capability>>();
+        if (isAllowedDynamicImport(state, module, pkgName, candidateMap))
+        {
+            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
+            {
+                rethrow = null;
+
+                candidateMap = m_candidatePermutations.remove(0);
+//dumpCandidateMap(state, candidateMap);
+
+                try
+                {
+                    findConsistentDynamicCandidate(
+                        module,
+                        new ArrayList(),
+                        candidateMap,
+                        modulePkgMap);
+                }
+                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 =
+                populateDynamicWireMap(
+                    module, pkgName, modulePkgMap, wireMap, candidateMap);
+
+//System.out.println("+++ DYNAMIC SUCCESS: " + wireMap.get(module));
+            return wireMap;
+        }
+
+//System.out.println("+++ DYNAMIC FAILURE");
+        return null;
+    }
+
+    // TODO: FELIX3 - It would be nice to make this private.
+    // TODO: FELIX3 - 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 false;
+        }
+
+        // If any of the module exports this package, then we cannot
+        // attempt to dynamically import it.
+        List<Capability> caps = module.getCapabilities();
+        for (int i = 0; (caps != null) && (i < caps.size()); i++)
+        {
+            if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+                && caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
+            {
+                return false;
+            }
+        }
+        // If any of our wires have this package, then we cannot
+        // attempt to dynamically import it.
+        List<Wire> wires = module.getWires();
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
+        {
+            if (wires.get(i).hasPackage(pkgName))
+            {
+                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.
+        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;
+            (candidates.size() > 0) && (dynReq == null) && (dynIdx < dynamics.size());
+            dynIdx++)
+        {
+            for (Iterator<Capability> itCand = candidates.iterator();
+                (dynReq == null) && itCand.hasNext(); )
+            {
+                Capability cap = itCand.next();
+                if (CapabilitySet.matches(cap, dynamics.get(dynIdx).getFilter()))
+                {
+                    dynReq = dynamics.get(dynIdx);
+                }
+            }
+        }
+
+        // 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 !candidates.isEmpty();
+    }
+
+    private static void dumpCandidateMap(
+        ResolverState state, Map<Requirement, Set<Capability>> candidateMap)
+    {
+        System.out.println("=== BEGIN CANDIDATE MAP ===");
+        for (Module module : ((FelixResolverState) state).getModules())
+        {
+            System.out.println("  " + module
+                 + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
+            for (Requirement req : module.getRequirements())
+            {
+                Set<Capability> candidates = candidateMap.get(req);
+                if ((candidates != null) && (candidates.size() > 0))
+                {
+                    System.out.println("    " + req + ": " + candidates);
+                }
+            }
+            for (Requirement req : module.getDynamicRequirements())
+            {
+                Set<Capability> candidates = candidateMap.get(req);
+                if ((candidates != null) && (candidates.size() > 0))
+                {
+                    System.out.println("    " + req + ": " + candidates);
+                }
+            }
+        }
+        System.out.println("=== END CANDIDATE MAP ===");
+    }
+
+    private static void dumpModulePkgMap(Map<Module, Packages> modulePkgMap)
+    {
+        System.out.println("+++MODULE PKG MAP+++");
+        for (Entry<Module, Packages> entry : modulePkgMap.entrySet())
+        {
+            dumpModulePkgs(entry.getKey(), entry.getValue());
+        }
+    }
+
+    private static void dumpModulePkgs(Module module, Packages packages)
+    {
+        System.out.println(module + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
+        System.out.println("  EXPORTED");
+        for (Entry<String, Blame> entry : packages.m_exportedPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+        System.out.println("  IMPORTED");
+        for (Entry<String, Blame> entry : packages.m_importedPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+        System.out.println("  REQUIRED");
+        for (Entry<String, List<Blame>> entry : packages.m_requiredPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+        System.out.println("  USED");
+        for (Entry<String, List<Blame>> entry : packages.m_usedPkgs.entrySet())
+        {
+            System.out.println("    " + entry.getKey() + " - " + entry.getValue());
+        }
+    }
+
+    private static void populateCandidates(
+        ResolverState state, Module module, String fwkExecEnvStr, Set fwkExecEnvSet,
+        Map<Requirement, Set<Capability>> candidateMap, Map<Module, Object> resultCache)
+    {
+        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);
+        }
+
+        // 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.
+
+        // 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);
+
+        // This is case 1.
+        if (cacheValue instanceof ResolveException)
+        {
+            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];
+        }
+
+        // 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);
+
+            // Verify that any native libraries match the current platform.
+            verifyNativeLibraries(module);
+
+            // Record cycle count.
+            cycleCount = new Integer(0);
+
+            // 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
+                    {
+                        populateCandidates(state, candCap.getModule(),
+                            fwkExecEnvStr, fwkExecEnvSet, candidateMap, resultCache);
+                    }
+                    catch (ResolveException ex)
+                    {
+System.out.println("RE: Candidate not resolveable: " + ex);
+                        // Remove the candidate since we weren't able to
+                        // populate its candidates.
+                        itCandCap.remove();
+                    }
+                }
+            }
+
+            // 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())
+            {
+                ResolveException ex =
+                    new ResolveException("Unable to resolve " + module
+                        + ": missing requirement " + req, module, req);
+                resultCache.put(module, ex);
+                throw ex;
+            }
+            // If we actually have candidates for the requirement, then
+            // add them to the local candidate map.
+            else if (candidates.size() > 0)
+            {
+                localCandidateMap.put(req, candidates);
+            }
+        }
+
+        // If we are exiting from a cycle then decrement
+        // cycle counter, otherwise record the result.
+        if (cycleCount.intValue() > 0)
+        {
+            ((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)
+            {
+                candidateMap.putAll(localCandidateMap);
+            }
+        }
+    }
+
+    private static void populateDynamicCandidates(
+        ResolverState state, Module module,
+        String fwkExecEnvStr, Set fwkExecEnvSet,
+        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);
+        }
+
+        // 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(); )
+        {
+            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();
+                }
+            }
+        }
+
+// 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)
+        {
+            candidateMap.remove(dynReq);
+            throw new ResolveException("Dynamic import failed.", module, dynReq);
+        }
+
+        // Add existing wires as candidates.
+        for (Wire wire : module.getWires())
+        {
+            Set<Capability> cs = new TreeSet();
+            cs.add(wire.getCapability());
+            candidateMap.put(wire.getRequirement(), cs);
+        }
+    }
+
+    private void findConsistentCandidates(
+        Module module, List<Requirement> incomingReqs,
+        Map<Requirement, Set<Capability>> candidateMap,
+        Map<Module, Packages> modulePkgMap,
+        Map<Module, Object> cycleMap)
+    {
+        if (m_isInvokeCount)
+        {
+            String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+            Long count = m_invokeCounts.get(methodName);
+            count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+            m_invokeCounts.put(methodName, count);
+        }
+
+        Integer cycleCount = null;
+
+        Object o = cycleMap.get(module);
+
+        if (o instanceof Boolean)
+        {
+            return;
+        }
+        else if (o == null)
+        {
+            List list;
+            if (module.isResolved())
+            {
+                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);
+        }
+        else
+        {
+            cycleCount = (Integer) ((Object[]) o)[0];
+            ((Object[]) o)[0] = new Integer(cycleCount.intValue() + 1);
+            cycleCount = (Integer) ((Object[]) o)[0];
+        }
+
+//System.out.println("+++ RESOLVING " + module);
+
+        if (module.isResolved())
+        {
+            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);
+            }
+        }
+        else
+        {
+            List<Requirement> reqs = (List<Requirement>) ((Object[]) o)[1];
+
+            while (reqs.size() > 0)
+            {
+                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)
+                {
+                    continue;
+                }
+
+                List<Requirement> outgoingReqs = new ArrayList<Requirement>(incomingReqs);
+                outgoingReqs.add(req);
+
+                for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
+                {
+                    Capability candCap = it.next();
+//System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
+                    try
+                    {
+                        // Try to resolve the candidate.
+                        findConsistentCandidates(
+                            candCap.getModule(),
+                            outgoingReqs,
+                            candidateMap,
+                            modulePkgMap,
+                            cycleMap);
+
+                        // If we are here, the candidate was consistent. Try to
+                        // merge the candidate into the target module's packages.
+                        mergeCandidatePackages(
+                            module,
+                            outgoingReqs,
+                            candCap,
+                            modulePkgMap,
+                            candidateMap);
+
+                        // If we are here, we merged the candidate successfully,
+                        // so we can continue with the next requirement
+                        break;
+                    }
+                    catch (ResolveException ex)
+                    {
+System.out.println("RE: " + ex);
+ex.printStackTrace();
+
+// 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);
+                        }
+                    }
+                }
+            }
+        }
+
+        // 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 void findConsistentDynamicCandidate(
+        Module module, List<Requirement> incomingReqs,
+        Map<Requirement, Set<Capability>> candidateMap,
+        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);
+        }
+
+//System.out.println("+++ RESOLVING " + module);
+        calculateExportedPackages(module, incomingReqs, modulePkgMap);
+
+        List<Requirement> reqs = new ArrayList(module.getRequirements());
+        reqs.addAll(module.getDynamicRequirements());
+        for (Requirement req : reqs)
+        {
+            // Get the candidates for the current requirement.
+            Set<Capability> candCaps = candidateMap.get(req);
+            // Optional requirements may not have any candidates.
+            if (candCaps == null)
+            {
+                continue;
+            }
+
+            List<Requirement> outgoingReqs = new ArrayList<Requirement>(incomingReqs);
+            outgoingReqs.add(req);
+
+            for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
+            {
+                Capability candCap = it.next();
+//System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
+                try
+                {
+                    // 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);
+
+                    // 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();
+// 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);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void calculateExportedPackages(
+        Module module, List<Requirement> incomingReqs, Map<Module, Packages> modulePkgMap)
+    {
+        if (m_isInvokeCount)
+        {
+            String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+            Long count = m_invokeCounts.get(methodName);
+            count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+            m_invokeCounts.put(methodName, count);
+        }
+
+        Packages packages = new Packages();
+
+        List<Capability> caps = module.getCapabilities();
+
+        if (caps.size() > 0)
+        {
+            for (int i = 0; i < caps.size(); i++)
+            {
+// 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)));
+                }
+            }
+        }
+
+        modulePkgMap.put(module, packages);
+    }
+
+    private static boolean hasOverlappingImport(Module module, Capability cap)
+    {
+        if (m_isInvokeCount)
+        {
+            String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+            Long count = m_invokeCounts.get(methodName);
+            count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+            m_invokeCounts.put(methodName, count);
+        }
+
+        List<Requirement> reqs = module.getRequirements();
+        for (int i = 0; i < reqs.size(); i++)
+        {
+            if (reqs.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+                && CapabilitySet.matches(cap, reqs.get(i).getFilter()))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void mergeCandidatePackages(
+        Module current, List<Requirement> outgoingReqs,
+        Capability candCap, Map<Module, Packages> modulePkgMap,
+        Map<Requirement, Set<Capability>> candidateMap)
+    {
+        if (m_isInvokeCount)
+        {
+            String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+            Long count = m_invokeCounts.get(methodName);
+            count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+            m_invokeCounts.put(methodName, count);
+        }
+
+        if (candCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+        {
+            mergeCandidatePackage(
+                current, false, new Blame(outgoingReqs, candCap), modulePkgMap, candidateMap);
+        }
+        else if (candCap.getNamespace().equals(Capability.MODULE_NAMESPACE))
+        {
+            // Get the candidate's package space to determine which packages
+            // will be visible to the current module.
+            Packages candPkgs = modulePkgMap.get(candCap.getModule());
+
+// TODO: 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())
+            {
+                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)
+                {
+// 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))
+                    {
+                        continue;
+                    }
+
+                    Directive dir = blame.m_reqs.get(blame.m_reqs.size() - 1)
+                        .getDirective(Constants.VISIBILITY_DIRECTIVE);
+                    if ((dir != null) && dir.getValue().equals(Constants.VISIBILITY_REEXPORT))
+                    {
+                        mergeCandidatePackage(
+                            current,
+                            true,
+                            new Blame(outgoingReqs, blame.m_cap),
+                            modulePkgMap,
+                            candidateMap);
+                    }
+                }
+            }
+        }
+    }
+
+    private void mergeCandidatePackage(
+        Module current, boolean requires,
+        Blame candBlame, Map<Module, Packages> modulePkgMap,
+        Map<Requirement, Set<Capability>> candidateMap)
+    {
+        if (m_isInvokeCount)
+        {
+            String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+            Long count = m_invokeCounts.get(methodName);
+            count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+            m_invokeCounts.put(methodName, count);
+        }
+
+// TODO: PROTO3 RESOLVER - Check for merging where module imports from itself,
+//       then it should be listed as an export for requiring bundles.
+        if (candBlame.m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+        {
+//System.out.println("+++ MERGING " + candBlame.m_cap + " INTO " + current);
+            String pkgName = (String)
+                candBlame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
+
+            // Since this capability represents a package, it will become
+            // a hard constraint on the module's package space, so we need
+            // to make sure it doesn't conflict with any other hard constraints
+            // or any other uses constraints.
+
+            //
+            // First, check to see if the capability conflicts with
+            // any existing hard constraints.
+            //
+
+            Packages currentPkgs = modulePkgMap.get(current);
+            Blame currentExportedBlame = currentPkgs.m_exportedPkgs.get(pkgName);
+            Blame currentImportedBlame = currentPkgs.m_importedPkgs.get(pkgName);
+            List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(pkgName);
+
+            // We don't need to worry about an import conflicting with a required
+            // bundle's export, since imported package wires are terminal the
+            // bundle will never see the exported package from the required bundle.
+// TODO: FELIX3 - See scenario 21, this seems odd.
+            if (!requires &&
+                (currentImportedBlame != null) && !currentImportedBlame.m_cap.equals(candBlame.m_cap))
+//            if (!requires &&
+//                (((currentExportedBlame != null) && !currentExportedBlame.m_cap.equals(candBlame.m_cap))
+//                || ((currentImportedBlame != null) && !currentImportedBlame.m_cap.equals(candBlame.m_cap))))
+//                || ((currentRequiredBlames != null) && !currentRequiredBlames.contains(candBlame))))
+            {
+                // Permutate the candidate map and throw a resolve exception.
+                // NOTE: This method ALWAYS throws an exception.
+                permutateCandidates(
+                    current,
+                    pkgName,
+                    currentImportedBlame,
+                    candBlame,
+                    candidateMap);
+            }
+
+            //
+            // Second, check to see if the capability conflicts with
+            // any existing uses constraints
+            //
+
+            Packages currentPkgsCopy = currentPkgs;
+
+            if (!current.isResolved())
+            {
+                List<Blame> currentUsedBlames = currentPkgs.m_usedPkgs.get(pkgName);
+                checkExistingUsesConstraints(
+                    current, pkgName, currentUsedBlames, candBlame, modulePkgMap, candidateMap);
+
+                //
+                // Last, check to see if any uses constraints implied by the
+                // candidate conflict with any of the existing hard constraints.
+                //
+
+                // For now, create a copy of the module's package space and
+                // add the current candidate to the imported packages.
+                currentPkgsCopy = new Packages(currentPkgs);
+            }
+
+            if (requires)
+            {
+                if (currentRequiredBlames == null)
+                {
+                    currentRequiredBlames = new ArrayList<Blame>();
+                    currentPkgsCopy.m_requiredPkgs.put(pkgName, currentRequiredBlames);
+                }
+// TODO: PROTO3 RESOLVER - This is potentially modifying the original, we need to modify a copy.
+                currentRequiredBlames.add(candBlame);
+            }
+            else
+            {
+                currentPkgsCopy.m_importedPkgs.put(pkgName, candBlame);
+            }
+
+            // Verify and merge the candidate's transitive uses constraints.
+            verifyAndMergeUses(
+                current,
+                currentPkgsCopy,
+                candBlame,
+                modulePkgMap,
+                candidateMap,
+                new HashMap<String, List<Module>>());
+
+            // If we are here, then there were no conflict, so we should update
+            // the module's package space.
+            if (!current.isResolved())
+            {
+                currentPkgs.m_exportedPkgs.putAll(currentPkgsCopy.m_exportedPkgs);
+                currentPkgs.m_importedPkgs.putAll(currentPkgsCopy.m_importedPkgs);
+                currentPkgs.m_requiredPkgs.putAll(currentPkgsCopy.m_requiredPkgs);
+                currentPkgs.m_usedPkgs.putAll(currentPkgsCopy.m_usedPkgs);
+            }
+//dumpModulePkgs(current, currentPkgs);
+        }
+    }
+
+    private void checkExistingUsesConstraints(
+        Module current, String pkgName, List<Blame> currentUsedBlames,
+        Blame candBlame, Map<Module, Packages> modulePkgMap,
+        Map<Requirement, Set<Capability>> candidateMap)
+    {
+        for (int i = 0; (currentUsedBlames != null) && (i < currentUsedBlames.size()); i++)
+        {
+//System.out.println("+++ CHECK " + candBlame + " IN EXISTING " + currentUsedBlames.get(i));
+            if (!isCompatible(currentUsedBlames.get(i).m_cap, candBlame.m_cap, modulePkgMap))
+            {
+                // Permutate the candidate map and throw a resolve exception.
+                // NOTE: This method ALWAYS throws an exception.
+                permutateCandidates(
+                    current,
+                    pkgName,
+                    currentUsedBlames.get(i),
+                    candBlame,
+                    candidateMap);
+            }
+        }
+    }
+
+// TODO: PROTO3 RESOLVER - We end up with duplicates in uses constraints,
+//       see scenario 2 for an example.
+    private void verifyAndMergeUses(
+        Module current, Packages currentPkgs,
+        Blame candBlame, Map<Module, Packages> modulePkgMap,
+        Map<Requirement, Set<Capability>> candidateMap,
+        Map<String, List<Module>> 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);
+        }
+
+        // Check for cycles.
+        String pkgName = (String)
+            candBlame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
+        List<Module> list = cycleMap.get(pkgName);
+        if ((list != null) && list.contains(current))
+        {
+            return;
+        }
+        list = (list == null) ? new ArrayList<Module>() : list;
+        list.add(current);
+        cycleMap.put(pkgName, list);
+
+//System.out.println("+++ VERIFYING USES " + current + " FOR " + candBlame);
+        for (Capability candSourceCap : getPackageSources(
+            candBlame.m_cap, modulePkgMap, new ArrayList<Capability>(), new HashSet<Capability>()))
+        {
+            for (String usedPkgName : candSourceCap.getUses())
+            {
+                Blame currentExportedBlame = currentPkgs.m_exportedPkgs.get(usedPkgName);
+                Blame currentImportedBlame = currentPkgs.m_importedPkgs.get(usedPkgName);
+// TODO: PROTO3 RESOLVER - What do we do with required packages?
+                List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(usedPkgName);
+
+                Packages candSourcePkgs = modulePkgMap.get(candSourceCap.getModule());
+//System.out.println("+++ candSourceCap " + candSourceCap);
+//System.out.println("+++ candSourceCap.getModule() " + candSourceCap.getModule() + " (" + candSourceCap.getModule().isResolved() + ")");
+//System.out.println("+++ candSourcePkgs " + candSourcePkgs);
+//System.out.println("+++ candSourcePkgs.m_exportedPkgs " + candSourcePkgs.m_exportedPkgs);
+                Blame candSourceBlame = candSourcePkgs.m_exportedPkgs.get(usedPkgName);
+                candSourceBlame = (candSourceBlame != null)
+                    ? candSourceBlame
+                    : candSourcePkgs.m_importedPkgs.get(usedPkgName);
+//                sourceCap = (sourceCap != null)
+//                    ? sourceCap
+//                    : sourcePkgs.m_requiredPkgs.get(usedPkgName);
+
+                // If the candidate doesn't actually have a constraint for
+                // the used package, then just ignore it since this is likely
+                // an error in its metadata.
+                if (candSourceBlame == null)
+                {
+                    return;
+                }
+
+                // If there is no current mapping for this package, then
+                // we can just return.
+                if ((currentExportedBlame == null)
+                    && (currentImportedBlame == null)
+                    && (currentRequiredBlames == null))
+                {
+                    List<Blame> usedCaps = currentPkgs.m_usedPkgs.get(usedPkgName);
+                    if (usedCaps == null)
+                    {
+                        usedCaps = new ArrayList<Blame>();
+                        currentPkgs.m_usedPkgs.put(usedPkgName, usedCaps);
+                    }
+//System.out.println("+++ MERGING CB " + candBlame + " SB " + candSourceBlame);
+//                    usedCaps.add(new Blame(candBlame.m_reqs, sourceBlame.m_cap));
+                    usedCaps.add(candSourceBlame);
+//                    return;
+                }
+                else if (!current.isResolved())
+                {
+                    if ((currentExportedBlame != null)
+                        && !isCompatible(currentExportedBlame.m_cap, candSourceBlame.m_cap, modulePkgMap))
+                    {
+                        throw new ResolveException(
+                            "Constraint violation for package '" + usedPkgName
+                            + "' when resolving module " + current
+                            + " between existing constraint "
+                            + currentExportedBlame
+                            + " and candidate constraint "
+                            + candSourceBlame, null, null);
+                    }
+                    else if ((currentImportedBlame != null)
+                        && !isCompatible(currentImportedBlame.m_cap, candSourceBlame.m_cap, modulePkgMap))
+                    {
+//System.out.println("+++ CIB " + currentImportedBlame + " SB " + sourceBlame);
+                        // Try to remove the previously selected candidate associated
+                        // with the requirement blamed for adding the constraint. This
+                        // Permutate the candidate map.
+                        if (currentImportedBlame.m_reqs.size() != 0)
+                        {
+                            // Permutate the candidate map.
+                            for (int reqIdx = 0; reqIdx < currentImportedBlame.m_reqs.size(); reqIdx++)
+                            {
+                                Map<Requirement, Set<Capability>> copy = copyCandidateMap(candidateMap);
+                                Set<Capability> candidates =
+                                    copy.get(currentImportedBlame.m_reqs.get(reqIdx));
+                                Iterator it = candidates.iterator();
+                                it.next();
+                                it.remove();
+// TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy.
+                                if (candidates.size() > 0)
+                                {
+                                    m_candidatePermutations.add(copy);
+                                }
+                            }
+                        }
+
+                        throw new ResolveException(
+                            "Constraint violation for package '" + usedPkgName
+                            + "' when resolving module " + current
+                            + " between existing constraint "
+                            + currentImportedBlame
+                            + " and candidate constraint "
+                            + candSourceBlame, null, null);
+                    }
+                }
+
+                verifyAndMergeUses(current, currentPkgs, candSourceBlame,
+                    modulePkgMap, candidateMap, cycleMap);
+            }
+        }
+    }
+
+    private void permutateCandidates(
+        Module current, String pkgName, Blame currentBlame, Blame candBlame,
+        Map<Requirement, Set<Capability>> candidateMap)
+        throws ResolveException
+    {
+        // Try to remove the previously selected candidate associated
+        // with the requirement blamed for adding the constraint. This
+        // blamed requirement may be null if the bundle itself is
+        // exports the package imposing the uses constraint.
+        if ((currentBlame.m_reqs != null) && (currentBlame.m_reqs.size() != 0))
+        {
+            // Permutate the candidate map.
+            for (int reqIdx = 0; reqIdx < currentBlame.m_reqs.size(); reqIdx++)
+            {
+                Map<Requirement, Set<Capability>> copy = copyCandidateMap(candidateMap);
+                Set<Capability> candidates = copy.get(currentBlame.m_reqs.get(reqIdx));
+                Iterator it = candidates.iterator();
+                it.next();
+                it.remove();
+                // TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy.
+                if (candidates.size() > 0)
+                {
+                    m_candidatePermutations.add(copy);
+                }
+            }
+        }
+        throw new ResolveException(
+            "Constraint violation for package '"
+            + pkgName + "' when resolving module "
+            + current + " between existing constraint "
+            + currentBlame + " and candidate constraint "
+            + candBlame, null, null);
+    }
+
+    private static boolean isCompatible(
+        Capability currentCap, Capability candCap, Map<Module, Packages> modulePkgMap)
+    {
+        if ((currentCap != null) && (candCap != null))
+        {
+            List<Capability> currentSources =
+                getPackageSources(
+                    currentCap,
+                    modulePkgMap,
+                    new ArrayList<Capability>(),
+                    new HashSet<Capability>());
+            List<Capability> candSources =
+                getPackageSources(
+                    candCap,
+                    modulePkgMap,
+                    new ArrayList<Capability>(),
+                    new HashSet<Capability>());
+//System.out.println("+++ currentSources " + currentSources + " - candSources " + candSources);
+            return currentSources.containsAll(candSources) || candSources.containsAll(currentSources);
+        }
+        return true;
+    }
+
+    private static List<Capability> getPackageSources(
+        Capability cap, Map<Module, Packages> modulePkgMap, List<Capability> sources,
+        Set<Capability> cycleMap)
+    {
+        if (cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+        {
+            if (cycleMap.contains(cap))
+            {
+                return sources;
+            }
+            cycleMap.add(cap);
+
+            Packages pkgs = modulePkgMap.get(cap.getModule());
+            sources.add(cap);
+            String pkgName = cap.getAttribute(Capability.PACKAGE_ATTR).getValue().toString();
+            List<Blame> required = pkgs.m_requiredPkgs.get(pkgName);
+            if (required != null)
+            {
+                for (Blame blame : required)
+                {
+                    getPackageSources(blame.m_cap, modulePkgMap, sources, cycleMap);
+                }
+            }
+        }
+
+        return sources;
+    }
+
+    private static Map<Requirement, Set<Capability>> copyCandidateMap(
+        Map<Requirement, Set<Capability>> candidateMap)
+    {
+        Map<Requirement, Set<Capability>> copy =
+            new HashMap<Requirement, Set<Capability>>();
+        for (Entry<Requirement, Set<Capability>> entry : candidateMap.entrySet())
+        {
+            Set<Capability> candidates = new TreeSet(new CandidateComparator());
+            candidates.addAll(entry.getValue());
+            copy.put(entry.getKey(), candidates);
+        }
+        return copy;
+    }
+
+    private static Map<Module, List<Wire>> populateWireMap(
+        Module module, Map<Module, Packages> modulePkgMap,
+        Map<Module, List<Wire>> wireMap, Map<Requirement, Set<Capability>> candidateMap)
+    {
+        if (m_isInvokeCount)
+        {
+            String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+            Long count = m_invokeCounts.get(methodName);
+            count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+            m_invokeCounts.put(methodName, count);
+        }
+
+        if (!module.isResolved() && !wireMap.containsKey(module))
+        {
+            wireMap.put(module, m_emptyWires);
+
+            List<Wire> packageWires = new ArrayList<Wire>();
+            List<Wire> moduleWires = new ArrayList<Wire>();
+
+            for (Requirement req : module.getRequirements())
+            {
+                Set<Capability> cands = candidateMap.get(req);
+                if ((cands != null) && (cands.size() > 0))
+                {
+                    Capability cand = cands.iterator().next();
+                    if (!cand.getModule().isResolved())
+                    {
+                        populateWireMap(cand.getModule(),
+                            modulePkgMap, wireMap, candidateMap);
+                    }
+                    // Ignore modules that import themselves.
+                    if (req.getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+                        && !module.equals(cand.getModule()))
+                    {
+                        packageWires.add(
+                            new WireImpl(module,
+                                req,
+                                cand.getModule(),
+                                cand));
+                    }
+                    else if (req.getNamespace().equals(Capability.MODULE_NAMESPACE))
+                    {
+                        Packages candPkgs = modulePkgMap.get(cand.getModule());
+                        moduleWires.add(
+                            new WireModuleImpl(module,
+                                req,
+                                cand.getModule(),
+                                cand,
+                                candPkgs.getExportedAndReexportedPackages()));
+                    }
+                }
+            }
+
+            // Combine wires with module wires last.
+            packageWires.addAll(moduleWires);
+            wireMap.put(module, packageWires);
+        }
+
+        return wireMap;
+    }
+
+    private static Map<Module, List<Wire>> populateDynamicWireMap(
+        Module module, String pkgName, Map<Module, Packages> modulePkgMap,
+        Map<Module, List<Wire>> wireMap, 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);
+        }
+
+        wireMap.put(module, m_emptyWires);
+
+        List<Wire> packageWires = new ArrayList<Wire>();
+
+        Packages pkgs = modulePkgMap.get(module);
+        for (Entry<String, Blame> entry : pkgs.m_importedPkgs.entrySet())
+        {
+            if (!entry.getValue().m_cap.getModule().isResolved())
+            {
+                populateWireMap(entry.getValue().m_cap.getModule(), modulePkgMap, wireMap,
+                    candidateMap);
+            }
+
+            // Ignore modules that import themselves.
+            if (!module.equals(entry.getValue().m_cap.getModule())
+                && entry.getValue().m_cap.getAttribute(
+                    Capability.PACKAGE_ATTR).getValue().equals(pkgName))
+            {
+                List<Attribute> attrs = new ArrayList();
+                attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
+                packageWires.add(
+                    new WireImpl(
+                        module,
+                        // We need an unique requirement here or else subsequent
+                        // dynamic imports for the same dynamic requirement will
+                        // conflict with previous ones.
+                        new RequirementImpl(Capability.PACKAGE_NAMESPACE, new ArrayList(0), attrs),
+                        entry.getValue().m_cap.getModule(),
+                        entry.getValue().m_cap));
+            }
+        }
+
+        wireMap.put(module, packageWires);
+
+        return wireMap;
+    }
+
+// TODO: FELIX3 - This check should be moved to ResolverState.
+    private static void verifyNativeLibraries(Module module)
+    {
+        // Next, try to resolve any native code, since the module is
+        // not resolvable if its native code cannot be loaded.
+        List<R4Library> libs = module.getNativeLibraries();
+        if (libs != null)
+        {
+            String msg = null;
+            // Verify that all native libraries exist in advance; this will
+            // throw an exception if the native library does not exist.
+            for (int libIdx = 0; (msg == null) && (libIdx < libs.size()); libIdx++)
+            {
+                String entryName = libs.get(libIdx).getEntryName();
+                if (entryName != null)
+                {
+                    if (!module.getContent().hasEntry(entryName))
+                    {
+                        msg = "Native library does not exist: " + entryName;
+                    }
+                }
+            }
+            // If we have a zero-length native library array, then
+            // this means no native library class could be selected
+            // so we should fail to resolve.
+            if (libs.size() == 0)
+            {
+                msg = "No matching native libraries found.";
+            }
+            if (msg != null)
+            {
+                throw new ResolveException(msg, module, null);
+            }
+        }
+    }
+
+    /**
+     * Checks to see if the passed in module's required execution environment
+     * is provided by the framework.
+     * @param fwkExecEvnStr The original property value of the framework's
+     *        supported execution environments.
+     * @param fwkExecEnvSet Parsed set of framework's supported execution environments.
+     * @param module The module whose required execution environment is to be to verified.
+     * @throws ResolveException if the module's required execution environment does
+     *         not match the framework's supported execution environment.
+    **/
+    private static void verifyExecutionEnvironment(
+        String fwkExecEnvStr, Set fwkExecEnvSet, Module module)
+        throws ResolveException
+    {
+        String bundleExecEnvStr = (String)
+            module.getHeaders().get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
+        if (bundleExecEnvStr != null)
+        {
+            bundleExecEnvStr = bundleExecEnvStr.trim();
+
+            // If the bundle has specified an execution environment and the
+            // framework has an execution environment specified, then we must
+            // check for a match.
+            if (!bundleExecEnvStr.equals("")
+                && (fwkExecEnvStr != null)
+                && (fwkExecEnvStr.length() > 0))
+            {
+                StringTokenizer tokens = new StringTokenizer(bundleExecEnvStr, ",");
+                boolean found = false;
+                while (tokens.hasMoreTokens() && !found)
+                {
+                    if (fwkExecEnvSet.contains(tokens.nextToken().trim()))
+                    {
+                        found = true;
+                    }
+                }
+                if (!found)
+                {
+                    throw new ResolveException(
+                        "Execution environment not supported: "
+                        + bundleExecEnvStr, module, null);
+                }
+            }
+        }
+    }
+
+    /**
+     * Updates the framework wide execution environment string and a cached Set of
+     * execution environment tokens from the comma delimited list specified by the
+     * system variable 'org.osgi.framework.executionenvironment'.
+     * @param frameworkEnvironment Comma delimited string of provided execution environments
+    **/
+    private static Set parseExecutionEnvironments(String fwkExecEnvStr)
+    {
+        Set newSet = new HashSet();
+        if (fwkExecEnvStr != null)
+        {
+            StringTokenizer tokens = new StringTokenizer(fwkExecEnvStr, ",");
+            while (tokens.hasMoreTokens())
+            {
+                newSet.add(tokens.nextToken().trim());
+            }
+        }
+        return newSet;
+    }
+
+    private static class Packages
+    {
+        public final Map<String, Blame> m_exportedPkgs
+            = new HashMap<String, Blame>();
+        public final Map<String, Blame> m_importedPkgs
+            = new HashMap<String, Blame>();
+        public final Map<String, List<Blame>> m_requiredPkgs
+            = new HashMap<String, List<Blame>>();
+        public final Map<String, List<Blame>> m_usedPkgs
+            = new HashMap<String, List<Blame>>();
+
+        public 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 List<String> getExportedAndReexportedPackages()
+        {
+            List<String> pkgs = new ArrayList();
+            for (Entry<String, Blame> entry : m_exportedPkgs.entrySet())
+            {
+                pkgs.add((String)
+                    entry.getValue().m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue());
+            }
+            for (Entry<String, List<Blame>> entry : m_requiredPkgs.entrySet())
+            {
+                for (Blame blame : entry.getValue())
+                {
+                    Directive dir = blame.m_reqs.get(
+                        blame.m_reqs.size() - 1).getDirective(Constants.VISIBILITY_DIRECTIVE);
+                    if ((dir != null)
+                        && dir.getValue().equals(Constants.VISIBILITY_REEXPORT))
+                    {
+                        pkgs.add((String)
+                            blame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue());
+                        break;
+                    }
+                }
+            }
+            return pkgs;
+        }
+    }
+
+    private static class Blame
+    {
+        public final List<Requirement> m_reqs;
+        public final Capability m_cap;
+
+        public Blame(List<Requirement> reqs, Capability cap)
+        {
+            m_reqs = reqs;
+            m_cap = cap;
+        }
+
+        public String toString()
+        {
+            return m_cap.getModule() + "." + m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue()
+                + " BLAMED ON " + m_reqs;
+        }
+
+        public boolean equals(Object o)
+        {
+            return (o instanceof Blame) && m_reqs.equals(((Blame) o).m_reqs)
+                && m_cap.equals(((Blame) o).m_cap);
+        }
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResourceNotFoundException.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResourceNotFoundException.java
new file mode 100644
index 0000000..3cb5107
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResourceNotFoundException.java
@@ -0,0 +1,27 @@
+/* 
+ * 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.resolver;
+
+public class ResourceNotFoundException extends Exception
+{
+    public ResourceNotFoundException(String msg)
+    {
+        super(msg);
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/moduleloader/IWire.java b/framework/src/main/java/org/apache/felix/framework/resolver/Wire.java
similarity index 72%
rename from framework/src/main/java/org/apache/felix/moduleloader/IWire.java
rename to framework/src/main/java/org/apache/felix/framework/resolver/Wire.java
index 65bd320..ba85f50 100644
--- a/framework/src/main/java/org/apache/felix/moduleloader/IWire.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Wire.java
@@ -1,57 +1,53 @@
-/* 
- * 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.moduleloader;
+package org.apache.felix.framework.resolver;
 
+import org.apache.felix.framework.resolver.Module;
 import java.net.URL;
 import java.util.Enumeration;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Requirement;
 
-/**
- * This interface represents a directed class/resource loading dependency
- * between two modules, which result when the framework resolves
- * <tt>Import-Package</tt> or <tt>Require-Bundle</tt> declarations. A wire is
- * the means by which a dependent module makes a class/resource request on
- * the providing module.
-**/
-public interface IWire
+public interface Wire
 {
     /**
      * Returns the importing module.
      * @return The importing module.
     **/
-    public IModule getImporter();
+    public Module getImporter();
     /**
      * Returns the associated requirement from the importing module that
      * resulted in the creation of this wire.
      * @return
     **/
-    public IRequirement getRequirement();
+    public Requirement getRequirement();
     /**
      * Returns the exporting module.
      * @return The exporting module.
     **/
-    public IModule getExporter();
+    public Module getExporter();
     /**
      * Returns the associated capability from the exporting module that
      * satisfies the requirement of the importing module.
      * @return
     **/
-    public ICapability getCapability();
+    public Capability getCapability();
     /**
      * Returns whether or not the wire has a given package name. For some
      * wires, such as ones for Require-Bundle, there may be many packages.
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/WireImpl.java b/framework/src/main/java/org/apache/felix/framework/resolver/WireImpl.java
new file mode 100755
index 0000000..8e36f3b
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WireImpl.java
@@ -0,0 +1,175 @@
+/*
+ *  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.resolver;
+
+import java.net.URL;
+import java.util.Enumeration;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Requirement;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.CapabilityImpl;
+
+public class WireImpl implements Wire
+{
+    private final Module m_importer;
+    private final Requirement m_req;
+    private final Module m_exporter;
+    private final Capability m_cap;
+
+    public WireImpl(Module importer, Requirement ip, Module exporter, Capability ep)
+    {
+        m_importer = importer;
+        m_req = ip;
+        m_exporter = exporter;
+        m_cap = ep;
+    }
+
+    public Module getImporter()
+    {
+        return m_importer;
+    }
+
+    public Requirement getRequirement()
+    {
+        return m_req;
+    }
+
+    public Module getExporter()
+    {
+        return m_exporter;
+    }
+
+    public Capability getCapability()
+    {
+        return m_cap;
+    }
+
+    public String toString()
+    {
+        return m_req + " (" + m_importer + ") -> " + m_cap + " (" + m_exporter + ")";
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
+     */
+    public boolean hasPackage(String pkgName)
+    {
+        return (m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE) &&
+            m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName));
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
+     */
+    public Class getClass(String name) throws ClassNotFoundException
+    {
+        Class clazz = null;
+
+        // Get the package of the target class.
+        String pkgName = Util.getClassPackage(name);
+
+        // Only check when the package of the target class is
+        // the same as the package for the wire.
+        if (m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE) &&
+            m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
+        {
+            // Check the include/exclude filters from the target package
+            // to make sure that the class is actually visible. We delegate
+            // to the exporting module, rather than its content, so it can
+            // it can follow any internal wires it may have (e.g., if the
+            // package has multiple sources).
+// TODO: FELIX3 - Should isIncluded() be part of Capability?
+            if (((CapabilityImpl) m_cap).isIncluded(name))
+            {
+                clazz = m_exporter.getClassByDelegation(name);
+            }
+
+            // If no class was found, then we must throw an exception
+            // since the exporter for this package did not contain the
+            // requested class.
+            if (clazz == null)
+            {
+                throw new ClassNotFoundException(name);
+            }
+        }
+
+        return clazz;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.framework.searchpolicy.IWire#getResource(java.lang.String)
+     */
+    public URL getResource(String name) throws ResourceNotFoundException
+    {
+        URL url = null;
+
+        // Get the package of the target class.
+        String pkgName = Util.getResourcePackage(name);
+
+        // Only check when the package of the target resource is
+        // the same as the package for the wire.
+        if (m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE) &&
+            m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
+        {
+            // Delegate to the exporting module, rather than its
+            // content, so that it can follow any internal wires it may have
+            // (e.g., if the package has multiple sources).
+            url = m_exporter.getResourceByDelegation(name);
+
+            // If no resource was found, then we must throw an exception
+            // since the exporter for this package did not contain the
+            // requested class.
+            if (url == null)
+            {
+                throw new ResourceNotFoundException(name);
+            }
+        }
+
+        return url;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.framework.searchpolicy.IWire#getResources(java.lang.String)
+     */
+    public Enumeration getResources(String name) throws ResourceNotFoundException
+    {
+        Enumeration urls = null;
+
+        // Get the package of the target class.
+        String pkgName = Util.getResourcePackage(name);
+
+        // Only check when the package of the target resource is
+        // the same as the package for the wire.
+        if (m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE) &&
+            m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
+        {
+            urls = m_exporter.getResourcesByDelegation(name);
+
+            // If no resource was found, then we must throw an exception
+            // since the exporter for this package did not contain the
+            // requested class.
+            if (urls == null)
+            {
+                throw new ResourceNotFoundException(name);
+            }
+        }
+
+        return urls;
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java b/framework/src/main/java/org/apache/felix/framework/resolver/WireModuleImpl.java
similarity index 78%
rename from framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
rename to framework/src/main/java/org/apache/felix/framework/resolver/WireModuleImpl.java
index 28671c6..42df1cd 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WireModuleImpl.java
@@ -16,36 +16,37 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.framework.searchpolicy;
+package org.apache.felix.framework.resolver;
 
 import java.net.URL;
-import java.util.*;
-
+import java.util.Enumeration;
+import java.util.List;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Requirement;
 import org.apache.felix.framework.util.Util;
-import org.apache.felix.moduleloader.*;
 
-public class R4WireModule implements IWire
+public class WireModuleImpl implements Wire
 {
-    private final IModule m_importer;
-    private final IRequirement m_requirement;
-    private final IModule m_exporter;
-    private final ICapability m_capability;
-    private final Map m_pkgMap;
+    private final Module m_importer;
+    private final Requirement m_requirement;
+    private final Module m_exporter;
+    private final Capability m_capability;
+    private final List<String> m_packages;
 
-    public R4WireModule(IModule importer, IRequirement requirement,
-        IModule exporter, ICapability capability, Map pkgMap)
+    public WireModuleImpl(Module importer, Requirement requirement,
+        Module exporter, Capability capability, List<String> packages)
     {
         m_importer = importer;
         m_requirement = requirement;
         m_exporter = exporter;
         m_capability = capability;
-        m_pkgMap = pkgMap;
+        m_packages = packages;
     }
 
     /* (non-Javadoc)
      * @see org.apache.felix.framework.searchpolicy.IWire#getImporter()
      */
-    public IModule getImporter()
+    public Module getImporter()
     {
         return m_importer;
     }
@@ -53,7 +54,7 @@
     /* (non-Javadoc)
      * @see org.apache.felix.framework.searchpolicy.IWire#getRequirement()
      */
-    public IRequirement getRequirement()
+    public Requirement getRequirement()
     {
         return m_requirement;
     }
@@ -61,7 +62,7 @@
     /* (non-Javadoc)
      * @see org.apache.felix.framework.searchpolicy.IWire#getExporter()
      */
-    public IModule getExporter()
+    public Module getExporter()
     {
         return m_exporter;
     }
@@ -69,7 +70,7 @@
     /* (non-Javadoc)
      * @see org.apache.felix.framework.searchpolicy.IWire#getCapability()
      */
-    public ICapability getCapability()
+    public Capability getCapability()
     {
         return m_capability;
     }
@@ -79,7 +80,7 @@
      */
     public boolean hasPackage(String pkgName)
     {
-        return (m_pkgMap.get(pkgName) != null);
+        return m_packages.contains(pkgName);
     }
 
     /* (non-Javadoc)
@@ -89,9 +90,7 @@
     {
         // Get the package of the target class.
         String pkgName = Util.getClassPackage(name);
-
-        ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
-        if (rp != null)
+        if (m_packages.contains(pkgName))
         {
             try
             {
@@ -119,9 +118,7 @@
     {
         // Get the package of the target class.
         String pkgName = Util.getResourcePackage(name);
-
-        ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
-        if (rp != null)
+        if (m_packages.contains(pkgName))
         {
             URL url = m_exporter.getResourceByDelegation(name);
             if (url != null)
@@ -145,10 +142,7 @@
         String pkgName = Util.getResourcePackage(name);
 
         // See if we have a resolved package for the resource's package.
-        // If so, loop through all package sources and aggregate any
-        // matching resource enumerations.
-        ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
-        if (rp != null)
+        if (m_packages.contains(pkgName))
         {
             Enumeration urls = m_exporter.getResourcesByDelegation(name);
             if (urls != null)
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/CandidateSet.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/CandidateSet.java
deleted file mode 100644
index f16165c..0000000
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/CandidateSet.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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;
-
-import java.util.List;
-import org.apache.felix.moduleloader.IModule;
-import org.apache.felix.moduleloader.IRequirement;
-
-class CandidateSet
-{
-    public static final int NORMAL = 0;
-    public final IModule m_module;
-    public final IRequirement m_requirement;
-    public final List m_candidates;
-    public int m_idx = 0;
-    public int m_rotated = 0;
-
-    public CandidateSet(IModule module, IRequirement requirement, List candidates)
-    {
-        super();
-        m_module = module;
-        m_requirement = requirement;
-        m_candidates = candidates;
-    }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java
deleted file mode 100755
index 0eb232b..0000000
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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;
-
-import java.net.URL;
-import java.util.Enumeration;
-
-import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.Capability;
-import org.apache.felix.moduleloader.*;
-
-public class R4Wire implements IWire
-{
-    private final IModule m_importer;
-    private final IRequirement m_requirement;
-    private final IModule m_exporter;
-    private final ICapability m_capability;
-
-    public R4Wire(IModule importer, IRequirement requirement,
-        IModule exporter, ICapability capability)
-    {
-        m_importer = importer;
-        m_requirement = requirement;
-        m_exporter = exporter;
-        m_capability = capability;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getImporter()
-     */
-    public IModule getImporter()
-    {
-        return m_importer;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getRequirement()
-     */
-    public IRequirement getRequirement()
-    {
-        return m_requirement;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getExporter()
-     */
-    public IModule getExporter()
-    {
-        return m_exporter;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getCapability()
-     */
-    public ICapability getCapability()
-    {
-        return m_capability;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
-     */
-    public boolean hasPackage(String pkgName)
-    {
-        return (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-            m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName));
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
-     */
-    public Class getClass(String name) throws ClassNotFoundException
-    {
-        Class clazz = null;
-
-        // Get the package of the target class.
-        String pkgName = Util.getClassPackage(name);
-
-        // Only check when the package of the target class is
-        // the same as the package for the wire.
-        if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-            m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
-        {
-            // Check the include/exclude filters from the target package
-            // to make sure that the class is actually visible. We delegate
-            // to the exporting module, rather than its content, so it can
-            // it can follow any internal wires it may have (e.g., if the
-            // package has multiple sources).
-            if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                && ((Capability) m_capability).isIncluded(name))
-            {
-                clazz = m_exporter.getClassByDelegation(name);
-            }
-
-            // If no class was found, then we must throw an exception
-            // since the exporter for this package did not contain the
-            // requested class.
-            if (clazz == null)
-            {
-                throw new ClassNotFoundException(name);
-            }
-        }
-
-        return clazz;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getResource(java.lang.String)
-     */
-    public URL getResource(String name) throws ResourceNotFoundException
-    {
-        URL url = null;
-
-        // Get the package of the target class.
-        String pkgName = Util.getResourcePackage(name);
-
-        // Only check when the package of the target resource is
-        // the same as the package for the wire.
-        if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-            m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
-        {
-            // Delegate to the exporting module, rather than its
-            // content, so that it can follow any internal wires it may have
-            // (e.g., if the package has multiple sources).
-            url = m_exporter.getResourceByDelegation(name);
-
-            // If no resource was found, then we must throw an exception
-            // since the exporter for this package did not contain the
-            // requested class.
-            if (url == null)
-            {
-                throw new ResourceNotFoundException(name);
-            }
-        }
-
-        return url;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getResources(java.lang.String)
-     */
-    public Enumeration getResources(String name) throws ResourceNotFoundException
-    {
-        Enumeration urls = null;
-
-        // Get the package of the target class.
-        String pkgName = Util.getResourcePackage(name);
-
-        // Only check when the package of the target resource is
-        // the same as the package for the wire.
-        if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-            m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
-        {
-            urls = m_exporter.getResourcesByDelegation(name);
-
-            // If no resource was found, then we must throw an exception
-            // since the exporter for this package did not contain the
-            // requested class.
-            if (urls == null)
-            {
-                throw new ResourceNotFoundException(name);
-            }
-        }
-
-        return urls;
-    }
-
-    public String toString()
-    {
-        if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-        {
-            return m_importer + " -> "
-                + m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY)
-                + " -> " + m_exporter;
-        }
-        return m_importer + " -> " + m_capability + " -> " + m_exporter;
-    }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java
deleted file mode 100755
index e3658e5..0000000
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/* 
- * 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;
-
-import org.apache.felix.moduleloader.IModule;
-import org.apache.felix.moduleloader.IRequirement;
-
-/**
- * <p>
- * This exception is thrown if a module cannot be resolved. The module
- * that failed to be resolved is recorded, along with the failed import target
- * identifier and version number. If the error was a result of a propagation
- * conflict, then the propagation error flag is set.
- * </p>
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy#validate(org.apache.felix.moduleloader.Module)
-**/
-public class ResolveException extends Exception
-{
-    private IModule m_module = null;
-    private IRequirement m_req = null;
-
-    /**
-     * Constructs an exception with the specified message, module,
-     * import identifier, import version number, and propagation flag.
-    **/
-    public ResolveException(String msg, IModule module, IRequirement req)
-    {
-        super(msg);
-        m_module = module;
-        m_req = req;
-    }
-
-    /**
-     * Returns the module that was being resolved.
-     * @return the module that was being resolved.
-    **/
-    public IModule getModule()
-    {
-        return m_module;
-    }
-
-    public IRequirement getRequirement()
-    {
-        return m_req;
-    }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolvedPackage.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolvedPackage.java
deleted file mode 100644
index b75ebfa..0000000
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolvedPackage.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.felix.moduleloader.ICapability;
-
-/**
- * This utility class is a resolved package, which is comprised of a
- * set of <tt>ICapability</tt>s that is calculated by the resolver
- * algorithm. A given resolved package may have a single capability,
- * as is the case with imported packages, or it may have multiple
- * capabilities, as is the case with required bundles.
- */
-class ResolvedPackage
-{
-    public final String m_name;
-    public final CandidateSet m_cs;
-    public final List m_capList = new ArrayList();
-
-    public ResolvedPackage(String name, CandidateSet cs)
-    {
-        super();
-        m_name = name;
-        m_cs = cs;
-    }
-
-    public boolean isSubset(ResolvedPackage rp)
-    {
-        if (m_capList.size() > rp.m_capList.size())
-        {
-            return false;
-        }
-        else if (!m_name.equals(rp.m_name))
-        {
-            return false;
-        }
-        // Determine if the target set of source modules is a subset.
-        return rp.m_capList.containsAll(m_capList);
-    }
-
-    public Object clone()
-    {
-        ResolvedPackage rp = new ResolvedPackage(m_name, m_cs);
-        rp.m_capList.addAll(m_capList);
-        return rp;
-    }
-
-    public void merge(ResolvedPackage rp)
-    {
-        // Merge required packages, avoiding duplicate
-        // package sources and maintaining ordering.
-        for (int capIdx = 0; capIdx < rp.m_capList.size(); capIdx++)
-        {
-            if (!m_capList.contains(rp.m_capList.get(capIdx)))
-            {
-                m_capList.add(rp.m_capList.get(capIdx));
-            }
-        }
-    }
-
-    public String toString()
-    {
-        return toString("", new StringBuffer()).toString();
-    }
-
-    public StringBuffer toString(String padding, StringBuffer sb)
-    {
-        sb.append(padding);
-        sb.append(m_name);
-        sb.append(" from [");
-        for (int i = 0; i < m_capList.size(); i++)
-        {
-            ICapability cap = (ICapability) m_capList.get(i);
-            sb.append(cap.getModule());
-            if ((i + 1) < m_capList.size())
-            {
-                sb.append(", ");
-            }
-        }
-        sb.append("]");
-        return sb;
-    }
-}
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
deleted file mode 100644
index eb42f0c..0000000
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
+++ /dev/null
@@ -1,1737 +0,0 @@
-/*
- * 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;
-
-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.Set;
-import java.util.StringTokenizer;
-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.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.osgi.framework.Constants;
-
-public class Resolver
-{
-    private final Logger m_logger;
-
-    // Execution environment.
-    private final String m_fwkExecEnvStr;
-    private final Set m_fwkExecEnvSet;
-
-    // Reusable empty array.
-    private static final IWire[] m_emptyWires = new IWire[0];
-
-    public Resolver(Logger logger, String fwkExecEnvStr)
-    {
-        m_logger = logger;
-        m_fwkExecEnvStr = (fwkExecEnvStr != null) ? fwkExecEnvStr.trim() : null;
-        m_fwkExecEnvSet = parseExecutionEnvironments(fwkExecEnvStr);
-    }
-
-    // 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
-    {
-        ICapability candidate = null;
-        Map resolvedModuleWireMap = 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.
-        // The following call checks all of these conditions and returns
-        // a matching dynamic requirement if possible.
-        IRequirement dynReq = findAllowedDynamicImport(importer, pkgName);
-        if (dynReq != null)
-        {
-            // 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++)
-            {
-                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);
-
-            // 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++)
-                {
-                    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.
-                    }
-                }
-
-                if (candidate != null)
-                {
-                    // 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;
-                }
-            }
-            catch (Exception ex)
-            {
-                m_logger.log(Logger.LOG_ERROR, "Unable to dynamically import package.", ex);
-            }
-        }
-
-        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)
-        {
-            return null;
-        }
-
-        // 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++)
-        {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                && caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
-            {
-                return null;
-            }
-        }
-        // 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++)
-        {
-            if (wires[i].hasPackage(pkgName))
-            {
-                return null;
-            }
-        }
-
-        // 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();
-        for (int dynIdx = 0;
-            (dynamics != null) && (dynIdx < dynamics.length);
-            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)))
-            {
-                return dynamics[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;
-                    }
-                }
-            }
-        }
-
-        return populateWireMap(state, candidatesMap, provider, new HashMap());
-    }
-
-    private void populateCandidatesMap(
-        ResolverState state, Map candidatesMap, IModule targetModule)
-        throws ResolveException
-    {
-        // Detect cycles.
-        if (candidatesMap.containsKey(targetModule))
-        {
-            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)
-            {
-                for (Iterator it = candidates.iterator(); it.hasNext(); )
-                {
-                    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;
-                    }
-                }
-            }
-
-            // 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
-                {
-                    throw new ResolveException(
-                        "Unable to resolve.", targetModule, reqs[reqIdx]);
-                }
-            }
-            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);
-    }
-
-    private static void removeInvalidCandidate(
-        IModule invalidModule, Map candidatesMap, List invalidList)
-    {
-// 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.
-
-        // 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);
-
-        // 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(); )
-        {
-            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();
-
-                            // 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();
-
-                                // 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;
-                        }
-                    }
-                }
-            }
-        }
-
-        if (!invalidList.isEmpty())
-        {
-            while (!invalidList.isEmpty())
-            {
-                IModule m = (IModule) invalidList.remove(0);
-                removeInvalidCandidate(m, candidatesMap, invalidList);
-            }
-        }
-    }
-
-    // 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;
-
-    private void findConsistentClassSpace(
-        ResolverState state, Map candidatesMap, IModule rootModule)
-        throws ResolveException
-    {
-        List candidatesList = null;
-
-        // 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)
-                    {
-                        int w1 = calculateWeight((List) o1);
-                        int w2 = calculateWeight((List) o2);
-                        if (w1 < w2)
-                        {
-                            return -1;
-                        }
-                        else if (w1 > w2)
-                        {
-                            return 1;
-                        }
-                        return 0;
-                    }
-
-                    private int calculateWeight(List candSetList)
-                    {
-                        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;
-                    }
-                });
-            }
-
-            // 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)
-            {
-                incrementCandidateConfiguration(candidatesList);
-            }
-            else
-            {
-                m_candidatesRotated = false;
-            }
-
-            // 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 (modules[i].isResolved() && isSingleton(modules[i]))
-            {
-                String symName = modules[i].getSymbolicName();
-                singletonMap.put(symName, symName);
-            }
-        }
-
-        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)
-    {
-        // If we are in a cycle, then assume true for now.
-        if (cycleMap.get(targetModule) != null)
-        {
-            return true;
-        }
-
-        // 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))
-        {
-            return false;
-        }
-        else if (isSingleton)
-        {
-            singletonMap.put(symName, symName);
-        }
-
-        // Get the package space of the target module.
-        Map pkgMap = null;
-        try
-        {
-            pkgMap = getModulePackages(moduleMap, targetModule, candidatesMap);
-        }
-        catch (ResolveException ex)
-        {
-            m_logger.log(
-                Logger.LOG_DEBUG,
-                "Constraint violation for " + targetModule + " detected.",
-                ex);
-            return false;
-        }
-
-        // 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);
-                }
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * 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)
-        {
-            // this should never happen?
-            return false;
-        }
-        final R4Directive[] dirs = ((Capability) modCaps[0]).getDirectives();
-        for (int dirIdx = 0; (dirs != null) && (dirIdx < dirs.length); dirIdx++)
-        {
-            if (dirs[dirIdx].getName().equalsIgnoreCase(Constants.SINGLETON_DIRECTIVE)
-                && Boolean.valueOf(dirs[dirIdx].getValue()).booleanValue())
-            {
-                return true;
-            }
-        }
-        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)
-        {
-            return true;
-        }
-
-        // Record the target module in the cycle map.
-        cycleMap.put(targetModule, targetModule);
-
-        // 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
-        {
-            pkgMap = getModulePackages(moduleMap, targetModule, candidatesMap);
-        }
-        catch (ResolveException ex)
-        {
-            m_logger.log(
-                Logger.LOG_DEBUG,
-                "Constraint violation for " + targetModule + " detected.",
-                ex);
-            return false;
-        }
-
-        // 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++)
-            {
-                ICapability cap = (ICapability) rp.m_capList.get(capIdx);
-                if (!isClassSpaceConsistent(cap.getModule(), moduleMap, cycleMap, candidatesMap))
-                {
-                    return false;
-                }
-            }
-        }
-
-        // 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;
-        }
-
-        // 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))
-                    {
-                        // 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 " + 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()))
-                        {
-                            // 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;
-                        }
-
-                        return false;
-                    }
-                }
-            }
-        }
-
-        return 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
-    {
-//System.out.println("calculateUsesConstraints2("+psTarget.m_module+")");
-        // If we are in a cycle, then return for now.
-        if (cycleMap.get(capTarget) != null)
-        {
-            return usesMap;
-        }
-
-        // Record the target capability in the cycle map.
-        cycleMap.put(capTarget, capTarget);
-
-        // 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++)
-        {
-            // 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]);
-
-            // In general, the resolved package should not be null,
-            // but check for safety.
-            if (rp != null)
-            {
-                // 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++)
-                {
-                    usesMap = calculateUsesConstraints(
-                        (ICapability) rp.m_capList.get(srcIdx),
-                        moduleMap, usesMap, cycleMap, candidatesMap);
-                }
-
-                // 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)
-                {
-                    constraintList = new ArrayList();
-                }
-                constraintList.add(rp);
-                usesMap.put(cap.getUses()[i], constraintList);
-            }
-        }
-
-        return usesMap;
-    }
-
-    private static Map getModulePackages(Map moduleMap, IModule module, Map candidatesMap)
-        throws ResolveException
-    {
-        Map map = (Map) moduleMap.get(module);
-
-        if (map == null)
-        {
-            map = calculateModulePackages(module, candidatesMap);
-            moduleMap.put(module, map);
-        }
-        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;
-    }
-
-    private static Map calculateImportedPackages(IModule targetModule, Map candidatesMap)
-        throws ResolveException
-    {
-        return (candidatesMap.get(targetModule) == null)
-            ? calculateImportedPackagesResolved(targetModule)
-            : calculateImportedPackagesUnresolved(targetModule, candidatesMap);
-    }
-
-    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++)
-        {
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-            ICapability candCap = (ICapability) cs.m_candidates.get(cs.m_idx);
-
-            if (candCap.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                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);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private static Map calculateImportedPackagesResolved(IModule targetModule)
-        throws ResolveException
-    {
-//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 (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);
-            }
-        }
-
-        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++)
-        {
-            if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                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 pkgMap;
-    }
-
-    private static Map calculateRequiredPackages(IModule targetModule, Map candidatesMap)
-    {
-        return (candidatesMap.get(targetModule) == null)
-            ? calculateRequiredPackagesResolved(targetModule)
-            : calculateRequiredPackagesUnresolved(targetModule, candidatesMap);
-    }
-
-    private static Map calculateRequiredPackagesUnresolved(IModule targetModule, Map candidatesMap)
-    {
-//System.out.println("calculateRequiredPackagesUnresolved("+targetModule+")");
-        Map pkgMap = new HashMap();
-
-        // 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++)
-        {
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-            ICapability candCap = (ICapability) cs.m_candidates.get(cs.m_idx);
-
-            // If the capabaility is a module dependency, then flatten it to packages.
-            if (candCap.getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                // 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(); )
-                {
-                    Map.Entry entry = (Map.Entry) reqIter.next();
-                    ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
-                    if (rp != null)
-                    {
-                        // Merge required packages, avoiding duplicate
-                        // packages and maintaining ordering.
-                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
-                        rp.merge(rpReq);
-                    }
-                    else
-                    {
-                        pkgMap.put(entry.getKey(), entry.getValue());
-                    }
-                }
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private static Map calculateRequiredPackagesResolved(IModule targetModule)
-    {
-//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))
-            {
-                // Calculate transitively required packages.
-                // We can call calculateExportedAndReexportedPackagesResolved()
-                // directly, since we know all dependencies have to be resolved
-                // because this module itself is resolved.
-                Map cycleMap = new HashMap();
-                cycleMap.put(targetModule, targetModule);
-                Map requireMap =
-                    calculateExportedAndReexportedPackagesResolved(
-                        wires[i].getExporter(), 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(); )
-                {
-                    Map.Entry entry = (Map.Entry) reqIter.next();
-                    ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
-                    if (rp != null)
-                    {
-                        // Merge required packages, avoiding duplicate
-                        // packages and maintaining ordering.
-                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
-                        rp.merge(rpReq);
-                    }
-                    else
-                    {
-                        pkgMap.put(entry.getKey(), entry.getValue());
-                    }
-                }
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private static Map calculateExportedAndReexportedPackages(
-        ICapability capTarget, Map candidatesMap, Map cycleMap)
-    {
-        return (candidatesMap.get(capTarget.getModule()) == null)
-            ? calculateExportedAndReexportedPackagesResolved(capTarget.getModule(), cycleMap)
-            : calculateExportedAndReexportedPackagesUnresolved(capTarget, candidatesMap, cycleMap);
-    }
-
-    private static Map calculateExportedAndReexportedPackagesUnresolved(
-        ICapability capTarget, Map candidatesMap, Map cycleMap)
-    {
-//System.out.println("calculateExportedAndReexportedPackagesUnresolved("+psTarget.m_module+")");
-        Map pkgMap = new HashMap();
-
-        if (cycleMap.get(capTarget.getModule()) != null)
-        {
-            return pkgMap;
-        }
-
-        cycleMap.put(capTarget.getModule(), capTarget.getModule());
-
-        // Loop through all current candidates for target module's dependencies
-        // and calculate the module's complete set of required packages (and
-        // their associated packages) and the complete set of required
-        // packages to be re-exported.
-        Map allRequiredMap = new HashMap();
-        Map reexportedPkgMap = new HashMap();
-        List candSetList = (List) candidatesMap.get(capTarget.getModule());
-        for (int candSetIdx = 0; candSetIdx < candSetList.size(); candSetIdx++)
-        {
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-            ICapability candCap = (ICapability) cs.m_candidates.get(cs.m_idx);
-
-            // If the candidate is resolving a module dependency, then
-            // flatten the required packages if they are re-exported.
-            if (candCap.getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                // Determine if required packages are re-exported.
-                boolean reexport = false;
-                R4Directive[] dirs =  ((Requirement) cs.m_requirement).getDirectives();
-                for (int dirIdx = 0;
-                    !reexport && (dirs != null) && (dirIdx < dirs.length); dirIdx++)
-                {
-                    if (dirs[dirIdx].getName().equals(Constants.VISIBILITY_DIRECTIVE)
-                        && dirs[dirIdx].getValue().equals(Constants.VISIBILITY_REEXPORT))
-                    {
-                        reexport = true;
-                    }
-                }
-
-                // Recursively calculate the required packages for the
-                // current candidate.
-                Map requiredMap =
-                    calculateExportedAndReexportedPackages(candCap, candidatesMap, cycleMap);
-
-                // Merge the candidate's exported and required packages
-                // into the complete set of required packages.
-                for (Iterator reqIter = requiredMap.entrySet().iterator(); reqIter.hasNext(); )
-                {
-                    Map.Entry entry = (Map.Entry) reqIter.next();
-                    String pkgName = (String) entry.getKey();
-
-                    // Merge the current set of required packages into
-                    // the overall complete set of required packages.
-                    // We calculate all the required packages, because
-                    // despite the fact that some packages will be required
-                    // "privately" and some will be required "reexport", any
-                    // re-exported packages will ultimately need to
-                    // be combined with privately required packages,
-                    // if the required packages overlap. This is one of the
-                    // bad things about require-bundle behavior, it does not
-                    // necessarily obey the visibility rules declared in the
-                    // dependency.
-                    ResolvedPackage rp = (ResolvedPackage) allRequiredMap.get(pkgName);
-                    if (rp != null)
-                    {
-                        // Create the union of all packages.
-                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
-                        rp.merge(rpReq);
-                    }
-                    else
-                    {
-                        // Add package to required map.
-                        allRequiredMap.put(pkgName, entry.getValue());
-                    }
-
-                    // Keep track of all required packages to be re-exported.
-                    // All re-exported packages will need to be merged into the
-                    // target module's package map and become part of its overall
-                    // export signature.
-                    if (reexport)
-                    {
-                        reexportedPkgMap.put(pkgName, pkgName);
-                    }
-                }
-            }
-        }
-
-        // For the target module we have now calculated its entire set
-        // of required packages and their associated packages in
-        // allRequiredMap and have calculated all packages to be re-exported
-        // in reexportedPkgMap. Add all re-exported required packages to the
-        // target module's package map since they will be part of its export
-        // signature.
-        for (Iterator iter = reexportedPkgMap.entrySet().iterator(); iter.hasNext(); )
-        {
-            String pkgName = (String) ((Map.Entry) iter.next()).getKey();
-            pkgMap.put(pkgName, allRequiredMap.get(pkgName));
-        }
-
-        // Now loop through the target module's export package capabilities and add
-        // the target module's export capability as a source for any exported packages.
-        ICapability[] candCaps = capTarget.getModule().getCapabilities();
-        for (int capIdx = 0; (candCaps != null) && (capIdx < candCaps.length); capIdx++)
-        {
-            if (candCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                String pkgName = (String)
-                    candCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
-                rp = (rp == null) ? new ResolvedPackage(pkgName, null) : rp;
-                rp.m_capList.add(candCaps[capIdx]);
-                pkgMap.put(rp.m_name, rp);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private static Map calculateExportedAndReexportedPackagesResolved(
-        IModule targetModule, Map cycleMap)
-    {
-//System.out.println("calculateExportedAndRequiredPackagesResolved("+targetModule+")");
-        Map pkgMap = new HashMap();
-
-        if (cycleMap.get(targetModule) != null)
-        {
-            return pkgMap;
-        }
-
-        cycleMap.put(targetModule, targetModule);
-
-        // Loop through all wires for the target module's module dependencies
-        // and calculate the module's complete set of required packages (and
-        // their associated sources) and the complete set of required
-        // packages to be re-exported.
-        Map allRequiredMap = new HashMap();
-        Map reexportedPkgMap = new HashMap();
-        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))
-            {
-                // Determine if required packages are re-exported.
-                boolean reexport = false;
-                R4Directive[] dirs =  ((Requirement) wires[i].getRequirement()).getDirectives();
-                for (int dirIdx = 0;
-                    !reexport && (dirs != null) && (dirIdx < dirs.length); dirIdx++)
-                {
-                    if (dirs[dirIdx].getName().equals(Constants.VISIBILITY_DIRECTIVE)
-                        && dirs[dirIdx].getValue().equals(Constants.VISIBILITY_REEXPORT))
-                    {
-                        reexport = true;
-                    }
-                }
-
-                // Recursively calculate the required packages for the
-                // wire's exporting module.
-                Map requiredMap = calculateExportedAndReexportedPackagesResolved(
-                    wires[i].getExporter(), cycleMap);
-
-                // Merge the wires exported and re-exported packages
-                // into the complete set of required packages.
-                for (Iterator reqIter = requiredMap.entrySet().iterator(); reqIter.hasNext(); )
-                {
-                    Map.Entry entry = (Map.Entry) reqIter.next();
-                    String pkgName = (String) entry.getKey();
-
-                    // Merge the current set of required packages into
-                    // the overall complete set of required packages.
-                    // We calculate all the required packages, because
-                    // despite the fact that some packages will be required
-                    // "privately" and some will be required "reexport", any
-                    // re-exported packages will ultimately need to
-                    // be combined with privately required packages,
-                    // if the required packages overlap. This is one of the
-                    // bad things about require-bundle behavior, it does not
-                    // necessarily obey the visibility rules declared in the
-                    // dependency.
-                    ResolvedPackage rp = (ResolvedPackage) allRequiredMap.get(pkgName);
-                    if (rp != null)
-                    {
-                        // Create the union of all packages.
-                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
-                        rp.merge(rpReq);
-                    }
-                    else
-                    {
-                        // Add package to required map.
-                        allRequiredMap.put(pkgName, entry.getValue());
-                    }
-
-                    // Keep track of all required packages to be re-exported.
-                    // All re-exported packages will need to be merged into the
-                    // target module's package map and become part of its overall
-                    // export signature.
-                    if (reexport)
-                    {
-                        reexportedPkgMap.put(pkgName, pkgName);
-                    }
-                }
-            }
-        }
-
-        // For the target module we have now calculated its entire set
-        // of required packages and their associated source capabilities in
-        // allRequiredMap and have calculated all packages to be re-exported
-        // in reexportedPkgMap. Add all re-exported required packages to the
-        // target module's package map since they will be part of its export
-        // signature.
-        for (Iterator iter = reexportedPkgMap.entrySet().iterator(); iter.hasNext(); )
-        {
-            String pkgName = (String) ((Map.Entry) iter.next()).getKey();
-            pkgMap.put(pkgName, allRequiredMap.get(pkgName));
-        }
-
-        // Now loop through the target module's export package capabilities and
-        // add the target module as a source for any exported packages.
-        ICapability[] caps = targetModule.getCapabilities();
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
-        {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                String pkgName = (String)
-                    caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
-                rp = (rp == null) ? new ResolvedPackage(pkgName, null) : rp;
-                rp.m_capList.add(caps[i]);
-                pkgMap.put(rp.m_name, rp);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private static Map calculateCandidateRequiredPackages(
-        IModule module, ICapability capTarget, Map candidatesMap)
-    {
-//System.out.println("calculateCandidateRequiredPackages("+module+")");
-        Map cycleMap = new HashMap();
-        cycleMap.put(module, module);
-        return calculateExportedAndReexportedPackages(capTarget, candidatesMap, cycleMap);
-    }
-
-    private static void incrementCandidateConfiguration(List resolverList)
-        throws ResolveException
-    {
-        for (int i = 0; i < resolverList.size(); i++)
-        {
-            List candSetList = (List) resolverList.get(i);
-            for (int j = 0; j < candSetList.size(); j++)
-            {
-                CandidateSet cs = (CandidateSet) candSetList.get(j);
-                // See if we can increment the candidate set, without overflowing
-                // the candidate array bounds.
-                if ((cs.m_idx + 1) < cs.m_candidates.size())
-                {
-                    cs.m_idx++;
-                    return;
-                }
-                // If the index will overflow the candidate array bounds,
-                // then set the index back to zero and try to increment
-                // the next candidate.
-                else
-                {
-                    cs.m_idx = 0;
-                }
-            }
-        }
-        throw new ResolveException(
-            "Unable to resolve due to constraint violation.", null, null);
-    }
-
-    private static Map populateWireMap(
-        ResolverState state, Map candidatesMap, IModule importer, Map wireMap)
-    {
-        // If the module is already resolved or it is part of
-        // a cycle, then just return the wire map.
-        if (importer.isResolved() || (wireMap.get(importer) != null))
-        {
-            return wireMap;
-        }
-
-        // Get the candidate set list for the importer.
-        List candSetList = (List) candidatesMap.get(importer);
-
-        List moduleWires = new ArrayList();
-        List packageWires = new ArrayList();
-
-        // Put the module in the wireMap with an empty wire array;
-        // we do this early so we can use it to detect cycles.
-        wireMap.put(importer, m_emptyWires);
-
-        // Loop through each candidate Set and create a wire
-        // for the selected candidate for the associated import.
-        for (int candSetIdx = 0; candSetIdx < candSetList.size(); candSetIdx++)
-        {
-            // Get the current candidate set.
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-
-            // Create a module wire for module dependencies.
-            if (cs.m_requirement.getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                moduleWires.add(new R4WireModule(
-                    importer,
-                    cs.m_requirement,
-                    ((ICapability) cs.m_candidates.get(cs.m_idx)).getModule(),
-                    ((ICapability) cs.m_candidates.get(cs.m_idx)),
-                    calculateCandidateRequiredPackages(
-                        importer, (ICapability) cs.m_candidates.get(cs.m_idx), candidatesMap)));
-            }
-            // Create a package wire for package dependencies.
-            // Filter out the case where a module imports from
-            // itself, since the module should simply load from
-            // its internal class path in this case.
-            else if (importer != ((ICapability) cs.m_candidates.get(cs.m_idx)).getModule())
-            {
-                // Add wire for imported package.
-                packageWires.add(new R4Wire(
-                    importer,
-                    cs.m_requirement,
-                    ((ICapability) cs.m_candidates.get(cs.m_idx)).getModule(),
-                    ((ICapability) cs.m_candidates.get(cs.m_idx))));
-            }
-
-            // Create any necessary wires for the selected candidate module.
-            wireMap = populateWireMap(
-                state, candidatesMap,
-                ((ICapability) cs.m_candidates.get(cs.m_idx)).getModule(),
-                wireMap);
-        }
-
-        packageWires.addAll(moduleWires);
-        wireMap.put(importer, packageWires.toArray(new IWire[packageWires.size()]));
-
-        return wireMap;
-    }
-
-    //
-    // Utility methods.
-    //
-
-    private static void verifyNativeLibraries(IModule module)
-        throws ResolveException
-    {
-        // Next, try to resolve any native code, since the module is
-        // not resolvable if its native code cannot be loaded.
-        R4Library[] libs = module.getNativeLibraries();
-        if (libs != null)
-        {
-            String msg = null;
-            // Verify that all native libraries exist in advance; this will
-            // throw an exception if the native library does not exist.
-            for (int libIdx = 0; (msg == null) && (libIdx < libs.length); libIdx++)
-            {
-                String entryName = libs[libIdx].getEntryName();
-                if (entryName != null)
-                {
-                    if (!module.getContent().hasEntry(entryName))
-                    {
-                        msg = "Native library does not exist: " + entryName;
-                    }
-                }
-            }
-            // If we have a zero-length native library array, then
-            // this means no native library class could be selected
-            // so we should fail to resolve.
-            if (libs.length == 0)
-            {
-                msg = "No matching native libraries found.";
-            }
-            if (msg != null)
-            {
-                throw new ResolveException(msg, module, null);
-            }
-        }
-    }
-
-    /**
-     * Checks to see if the passed in module's required execution environment
-     * is provided by the framework.
-     * @param fwkExecEvnStr The original property value of the framework's
-     *        supported execution environments.
-     * @param fwkExecEnvSet Parsed set of framework's supported execution environments.
-     * @param module The module whose required execution environment is to be to verified.
-     * @throws ResolveException if the module's required execution environment does
-     *         not match the framework's supported execution environment.
-    **/
-    private static void verifyExecutionEnvironment(
-        String fwkExecEnvStr, Set fwkExecEnvSet, IModule module)
-        throws ResolveException
-    {
-        String bundleExecEnvStr = (String)
-            module.getHeaders().get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
-        if (bundleExecEnvStr != null)
-        {
-            bundleExecEnvStr = bundleExecEnvStr.trim();
-
-            // If the bundle has specified an execution environment and the
-            // framework has an execution environment specified, then we must
-            // check for a match.
-            if (!bundleExecEnvStr.equals("")
-                && (fwkExecEnvStr != null)
-                && (fwkExecEnvStr.length() > 0))
-            {
-                StringTokenizer tokens = new StringTokenizer(bundleExecEnvStr, ",");
-                boolean found = false;
-                while (tokens.hasMoreTokens() && !found)
-                {
-                    if (fwkExecEnvSet.contains(tokens.nextToken().trim()))
-                    {
-                        found = true;
-                    }
-                }
-                if (!found)
-                {
-                    throw new ResolveException(
-                        "Execution environment not supported: "
-                        + bundleExecEnvStr, module, null);
-                }
-            }
-        }
-    }
-
-    /**
-     * Updates the framework wide execution environment string and a cached Set of
-     * execution environment tokens from the comma delimited list specified by the
-     * system variable 'org.osgi.framework.executionenvironment'.
-     * @param frameworkEnvironment Comma delimited string of provided execution environments
-    **/
-    private static Set parseExecutionEnvironments(String fwkExecEnvStr)
-    {
-        Set newSet = new HashSet();
-        if (fwkExecEnvStr != null)
-        {
-            StringTokenizer tokens = new StringTokenizer(fwkExecEnvStr, ",");
-            while (tokens.hasMoreTokens())
-            {
-                newSet.add(tokens.nextToken().trim());
-            }
-        }
-        return newSet;
-    }
-
-    //
-    // Inner classes.
-    //
-
-    public static interface ResolverState
-    {
-        IModule[] getModules();
-        List getResolvedCandidates(IRequirement req, IModule reqModule);
-        List getUnresolvedCandidates(IRequirement req, IModule reqModule);
-    }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/moduleloader/IModule.java b/framework/src/main/java/org/apache/felix/moduleloader/IModule.java
deleted file mode 100644
index 57a9018..0000000
--- a/framework/src/main/java/org/apache/felix/moduleloader/IModule.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.moduleloader;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.Map;
-import org.apache.felix.framework.util.manifestparser.R4Library;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Version;
-
-public interface IModule
-{
-    final static int EAGER_ACTIVATION = 0;
-    final static int LAZY_ACTIVATION = 1;
-
-    void setSecurityContext(Object securityContext);
-    Object getSecurityContext();
-
-    // Metadata access methods.
-    Map getHeaders();
-    boolean isExtension();
-    String getSymbolicName();
-    Version getVersion();
-    ICapability[] getCapabilities();
-    IRequirement[] getRequirements();
-    IRequirement[] getDynamicRequirements();
-    R4Library[] getNativeLibraries();
-    int getDeclaredActivationPolicy();
-
-    // Run-time data access methods.
-    Bundle getBundle();
-    String getId();
-    IWire[] getWires();
-    boolean isResolved();
-
-    // Content access methods.
-    IContent getContent();
-    Class getClassByDelegation(String name) throws ClassNotFoundException;
-    URL getResourceByDelegation(String name);
-    Enumeration getResourcesByDelegation(String name);
-    URL getEntry(String name);
-
-    // TODO: ML - For expediency, the index argument was added to these methods
-    // but it is not clear that this makes sense in the long run. This needs to
-    // be readdressed in the future, perhaps by the spec to clearly indicate
-    // how resources on the bundle class path are searched, which is why we
-    // need the index number in the first place -- to differentiate among
-    // resources with the same name on the bundle class path. This was previously
-    // handled as part of the resource path, but that approach is not spec
-    // compliant.
-    boolean hasInputStream(int index, String urlPath)
-        throws IOException;
-    InputStream getInputStream(int index, String urlPath)
-        throws IOException;
-}
\ No newline at end of file