Started refactoring of resolver code, breaking R4SearchPolicyCore into
the class loader delegation portion and the resolver portion. (FELIX-851)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@729083 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index a5f52ed..1d17403 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -27,6 +27,8 @@
 import org.apache.felix.framework.cache.*;
 import org.apache.felix.framework.ext.SecurityProvider;
 import org.apache.felix.framework.searchpolicy.*;
+import org.apache.felix.framework.searchpolicy.PackageSource;
+import org.apache.felix.framework.searchpolicy.Resolver.ResolverState;
 import org.apache.felix.framework.util.*;
 import org.apache.felix.framework.util.manifestparser.*;
 import org.apache.felix.moduleloader.*;
@@ -52,6 +54,9 @@
 
     // MODULE FACTORY.
     private IModuleFactory m_factory = null;
+    private final Resolver m_resolver;
+    private final FelixResolverState m_resolverState;
+    private final FelixResolver m_felixResolver;
     private R4SearchPolicyCore m_policyCore = null;
 
     // Lock object used to determine if an individual bundle
@@ -283,74 +288,16 @@
         // Create default bundle stream handler.
         m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
 
+        // Create a resolver and its state.
+        m_resolver = new Resolver(m_logger);
+        m_resolverState = new FelixResolverState(m_logger);
+        m_felixResolver = new FelixResolver(m_resolver, m_resolverState);
+
         // Create search policy for module loader.
-        m_policyCore = new R4SearchPolicyCore(m_logger, m_configMap);
-
-        // Add a resolver listener to the search policy
-        // so that we will be notified when modules are resolved
-        // in order to update the bundle state.
-        m_policyCore.addResolverListener(new ResolveListener() {
-            public void moduleResolved(ModuleEvent event)
-            {
-                FelixBundle bundle = null;
-                try
-                {
-                    long id = Util.getBundleIdFromModuleId(
-                        event.getModule().getId());
-                    if (id > 0)
-                    {
-                        // Update the bundle's state to resolved when the
-                        // current module is resolved; just ignore resolve
-                        // events for older revisions since this only occurs
-                        // when an update is done on an unresolved bundle
-                        // and there was no refresh performed.
-                        bundle = (FelixBundle) getBundle(id);
-
-                        // Lock the bundle first.
-                        try
-                        {
-                            acquireBundleLock(bundle);
-                            if (bundle.getInfo().getCurrentModule() == event.getModule())
-                            {
-                                if (bundle.getInfo().getState() != Bundle.INSTALLED)
-                                {
-                                    m_logger.log(
-                                        Logger.LOG_WARNING,
-                                        "Received a resolve event for a bundle that has already been resolved.");
-                                }
-                                else
-                                {
-                                    bundle.getInfo().setState(Bundle.RESOLVED);
-                                    fireBundleEvent(BundleEvent.RESOLVED, bundle);
-                                }
-                            }
-                        }
-                        finally
-                        {
-                            releaseBundleLock(bundle);
-                        }
-                    }
-                }
-                catch (NumberFormatException ex)
-                {
-                    // Ignore.
-                }
-            }
-
-            public void moduleUnresolved(ModuleEvent event)
-            {
-                // We can ignore this, because the only time it
-                // should happen is when a refresh occurs. The
-                // refresh operation resets the bundle's state
-                // by calling BundleInfo.reset(), thus it is not
-                // necessary for us to reset the bundle's state
-                // here.
-            }
-        });
+        m_policyCore = new R4SearchPolicyCore(m_logger, m_configMap, m_felixResolver);
 
         // Create the module factory and attach it to the search policy.
         m_factory = new ModuleFactoryImpl(m_logger);
-        m_policyCore.setModuleFactory(m_factory);
 
         // Create the system bundle info object, which will hold state info.
         m_sbi = new SystemBundleInfo(m_logger, null);
@@ -358,6 +305,7 @@
         // definition for creating the system bundle module.
         m_extensionManager = new ExtensionManager(m_logger, m_configMap, m_sbi);
         m_sbi.addModule(m_factory.createModule("0", m_extensionManager));
+        m_resolverState.addModule(m_sbi.getCurrentModule());
         // Set the extension manager as the content loader for the system
         // bundle module.
         m_extensionManager.setSearchPolicy(
@@ -749,7 +697,7 @@
             // state to be set to RESOLVED.
             try
             {
-                m_policyCore.resolve(m_sbi.getCurrentModule());
+                m_felixResolver.resolve(m_sbi.getCurrentModule());
             }
             catch (ResolveException ex)
             {
@@ -1783,7 +1731,7 @@
         IModule module = bundle.getInfo().getCurrentModule();
         try
         {
-            m_policyCore.resolve(module);
+            m_felixResolver.resolve(module);
         }
         catch (ResolveException ex)
         {
@@ -2989,8 +2937,8 @@
     protected ExportedPackage[] getExportedPackages(String pkgName)
     {
         // First, get all exporters of the package.
-        R4SearchPolicyCore.PackageSource[] exporters =
-            m_policyCore.getResolvedCandidates(
+        PackageSource[] exporters =
+            m_resolverState.getResolvedCandidates(
                 new Requirement(
                     ICapability.PACKAGE_NAMESPACE,
                     null,
@@ -3120,7 +3068,7 @@
                     // "in use" exporters of the package.
                     if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
                     {
-                        R4SearchPolicyCore.PackageSource[] inUseModules = m_policyCore.getResolvedCandidates(
+                        PackageSource[] inUseModules = m_resolverState.getResolvedCandidates(
                             new Requirement(
                                 ICapability.PACKAGE_NAMESPACE,
                                 null,
@@ -3478,6 +3426,7 @@
         // Create the module using the module definition.
         IModule module = m_factory.createModule(
             Long.toString(targetId) + "." + Integer.toString(revision), md);
+        m_resolverState.addModule(module);
 
         // Create the content loader from the module archive.
         IContentLoader contentLoader = new ContentLoaderImpl(
@@ -3513,6 +3462,11 @@
                     // has not yet been added to the bundle to be removed later.
                     m_factory.removeModule(module);
                     throw new BundleException("Native library does not exist: " + entryName);
+// TODO: REFACTOR - We have a memory leak here since we added a module above
+//                  and then don't remove it in case of an error; this may also
+//                  be a general issue for installing/updating bundles, so check.
+//                  This will likely go away when we refactor out the module
+//                  factory, but we will track it under FELIX-835 until then.
                 }
             }
         }
@@ -3575,6 +3529,7 @@
             for (int i = 0; i < modules.length; i++)
             {
                 m_factory.removeModule(modules[i]);
+                m_resolverState.removeModule(modules[i]);
             }
 
             // Purge all bundle revisions, but the current one.
@@ -3599,6 +3554,7 @@
         for (int i = 0; i < modules.length; i++)
         {
             m_factory.removeModule(modules[i]);
+            m_resolverState.removeModule(modules[i]);
         }
 
         // Remove the bundle from the cache.
@@ -3818,6 +3774,191 @@
     // Miscellaneous inner classes.
     //
 
+    public class FelixResolver
+    {
+        private final Resolver m_resolver;
+        private final FelixResolverState m_resolverState;
+
+        public FelixResolver(Resolver resolver, FelixResolverState resolverState)
+        {
+            m_resolver = resolver;
+            m_resolverState = resolverState;
+        }
+
+        public void resolve(IModule rootModule) throws ResolveException
+        {
+            if (!m_resolverState.isResolved(rootModule))
+            {
+                Resolver.Result result = m_resolver.resolve(m_resolverState, rootModule);
+
+                // Mark all modules as resolved.
+                markResolvedModules(result.m_resolvedModuleWireMap);
+
+                // Attach and mark all fragments as resolved.
+                attachFragments(result.m_host, result.m_fragmentMap);
+            }
+        }
+
+        public IWire resolveDynamicImport(IModule importer, String pkgName) throws ResolveException
+        {
+            IWire candidateWire = null;
+
+            if (m_resolverState.isResolved(importer))
+            {
+                Object[] result = m_resolver.resolveDynamicImport(m_resolverState, importer, pkgName);
+                if (result != null)
+                {
+                    candidateWire = (IWire) result[0];
+                    Map resolvedModuleWireMap = (Map) result[1];
+
+                    // Mark all modules as resolved.
+                    markResolvedModules(resolvedModuleWireMap);
+
+                    // Dynamically add new wire to importing module.
+                    if (candidateWire != null)
+                    {
+                        IWire[] wires = importer.getWires();
+                        IWire[] newWires = null;
+                        if (wires == null)
+                        {
+                            newWires = new IWire[1];
+                        }
+                        else
+                        {
+                            newWires = new IWire[wires.length + 1];
+                            System.arraycopy(wires, 0, newWires, 0, wires.length);
+                        }
+
+                        newWires[newWires.length - 1] = candidateWire;
+                        ((ModuleImpl) importer).setWires(newWires);
+m_logger.log(Logger.LOG_DEBUG, "DYNAMIC WIRE: " + newWires[newWires.length - 1]);
+                    }
+                }
+            }
+
+            return candidateWire;
+        }
+
+        public synchronized PackageSource[] getResolvedCandidates(IRequirement req)
+        {
+            return m_resolverState.getResolvedCandidates(req);
+        }
+
+        public synchronized PackageSource[] getUnresolvedCandidates(IRequirement req)
+        {
+            return m_resolverState.getUnresolvedCandidates(req);
+        }
+
+        private void markResolvedModules(Map resolvedModuleWireMap)
+        {
+            Iterator iter = resolvedModuleWireMap.entrySet().iterator();
+            // Iterate over the map to mark the modules as resolved and
+            // update our resolver data structures.
+            while (iter.hasNext())
+            {
+                Map.Entry entry = (Map.Entry) iter.next();
+                IModule module = (IModule) entry.getKey();
+                IWire[] wires = (IWire[]) entry.getValue();
+
+                // Only add wires attribute if some exist; export
+                // only modules may not have wires.
+                if (wires.length > 0)
+                {
+                    ((ModuleImpl) module).setWires(wires);
+for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
+{
+    m_logger.log(Logger.LOG_DEBUG, "WIRE: " + wires[wireIdx]);
+}
+                }
+
+                // Update the resolver state to show the module as resolved.
+                m_resolverState.setResolved(module, true);
+                // Update the state of the module's bundle to resolved as well.
+                markBundleResolved(module);
+            }
+        }
+
+        private void attachFragments(IModule host, Map fragmentMap)
+        {
+            // Attach fragments to host module.
+            if ((fragmentMap != null) && (fragmentMap.size() > 0))
+            {
+                List list = new ArrayList();
+                for (Iterator iter = fragmentMap.entrySet().iterator(); iter.hasNext(); )
+                {
+                    Map.Entry entry = (Map.Entry) iter.next();
+                    String symName = (String) entry.getKey();
+                    IModule[] fragments = (IModule[]) entry.getValue();
+// TODO: FRAGMENT - For now, just attach first candidate.
+                    list.add(fragments[0]);
+m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: "
+    + host + " -> " + symName + " -> " + fragments[0]);
+
+                    // Update the resolver state to show the module as resolved.
+                    m_resolverState.setResolved(fragments[0], true);
+                    // Update the state of the module's bundle to resolved as well.
+                    markBundleResolved(fragments[0]);
+                }
+                try
+                {
+                    ((ModuleImpl) host).attachFragments(
+                        (IModule[]) list.toArray(new IModule[list.size()]));
+                }
+                catch (Exception ex)
+                {
+                    m_logger.log(Logger.LOG_ERROR, "Unable to attach fragments", ex);
+                }
+            }
+        }
+
+        private void markBundleResolved(IModule module)
+        {
+            // Mark associated bundle as resolved.
+            try
+            {
+                long id = Util.getBundleIdFromModuleId(module.getId());
+                if (id > 0)
+                {
+                    // Update the bundle's state to resolved when the
+                    // current module is resolved; just ignore resolve
+                    // events for older revisions since this only occurs
+                    // when an update is done on an unresolved bundle
+                    // and there was no refresh performed.
+                    FelixBundle bundle = (FelixBundle) getBundle(id);
+
+                    // Lock the bundle first.
+                    try
+                    {
+// TODO: RESOLVER - Seems like we should release the lock before we fire the event.
+                        acquireBundleLock(bundle);
+                        if (bundle.getInfo().getCurrentModule() == module)
+                        {
+                            if (bundle.getInfo().getState() != Bundle.INSTALLED)
+                            {
+                                m_logger.log(
+                                    Logger.LOG_WARNING,
+                                    "Received a resolve event for a bundle that has already been resolved.");
+                            }
+                            else
+                            {
+                                bundle.getInfo().setState(Bundle.RESOLVED);
+                                fireBundleEvent(BundleEvent.RESOLVED, bundle);
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        releaseBundleLock(bundle);
+                    }
+                }
+            }
+            catch (NumberFormatException ex)
+            {
+                // Ignore.
+            }
+        }
+    }
+
     class SystemBundleActivator implements BundleActivator, Runnable
     {
         public void start(BundleContext context) throws Exception
@@ -3895,6 +4036,7 @@
                     try
                     {
                         m_factory.removeModule(modules[j]);
+                        m_resolverState.removeModule(modules[j]);
                     }
                     catch (Exception ex)
                     {
diff --git a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
new file mode 100644
index 0000000..c334276
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -0,0 +1,735 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.felix.framework.searchpolicy.Resolver;
+import org.apache.felix.framework.searchpolicy.PackageSource;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.Requirement;
+import org.apache.felix.moduleloader.ICapability;
+import org.apache.felix.moduleloader.IModule;
+import org.apache.felix.moduleloader.IRequirement;
+import org.apache.felix.moduleloader.IWire;
+import org.apache.felix.moduleloader.ModuleImpl;
+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();
+    // Maps a package name to an array of modules.
+    private final Map m_unresolvedPkgIndexMap = new HashMap();
+    // Maps a package name to an array of modules.
+    private final Map m_resolvedPkgIndexMap = new HashMap();
+    // Maps a module to an array of capabilities.
+    private final Map m_resolvedCapMap = new HashMap();
+
+    private final Map m_moduleDataMap = new HashMap();
+
+    // Reusable empty array.
+    private static final IModule[] m_emptyModules = new IModule[0];
+    private static final PackageSource[] m_emptySources = new PackageSource[0];
+
+    public FelixResolverState(Logger logger)
+    {
+        m_logger = logger;
+    }
+
+    public synchronized void addModule(IModule module)
+    {
+        // When a module is added, create an aggregated list of unresolved
+        // exports to simplify later processing when resolving bundles.
+        m_moduleList.add(module);
+
+        ICapability[] caps = module.getDefinition().getCapabilities();
+
+        // Add exports to unresolved package map.
+        for (int i = 0; (caps != null) && (i < caps.length); i++)
+        {
+            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            {
+                indexPackageCapability(m_unresolvedPkgIndexMap, module, caps[i]);
+            }
+        }
+
+System.out.println("UNRESOLVED PACKAGES:");
+dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+System.out.println("RESOLVED PACKAGES:");
+dumpPackageIndexMap(m_resolvedPkgIndexMap);
+    }
+
+    public synchronized void removeModule(IModule module)
+    {
+        // When a module is removed from the system, we need remove
+        // its exports from the "resolved" and "unresolved" package maps,
+        // remove the module's dependencies on fragments and exporters,
+        // and remove the module from the module data map.
+
+        m_moduleList.remove(module);
+
+        // Remove exports from package maps.
+        ICapability[] caps = module.getDefinition().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.
+                IModule[] modules = (IModule[]) m_unresolvedPkgIndexMap.get(pkgName);
+                if (modules != null)
+                {
+                    modules = removeModuleFromArray(modules, module);
+                    m_unresolvedPkgIndexMap.put(pkgName, modules);
+                }
+
+                // Remove from "resolved" package map.
+                modules = (IModule[]) m_resolvedPkgIndexMap.get(pkgName);
+                if (modules != null)
+                {
+                    modules = removeModuleFromArray(modules, module);
+                    m_resolvedPkgIndexMap.put(pkgName, modules);
+                }
+            }
+        }
+
+        // Set fragments to null, which will remove the module from all
+        // of its dependent fragment modules.
+        try
+        {
+            ((ModuleImpl) module).attachFragments(null);
+        }
+        catch (Exception ex)
+        {
+            m_logger.log(Logger.LOG_ERROR, "Error detaching fragments.", ex);
+        }
+        // Set wires to null, which will remove the module from all
+        // of its dependent modules.
+        ((ModuleImpl) module).setWires(null);
+        // Remove the module from the "resolved" map.
+// TODO: RB - Maybe this can be merged with ModuleData.
+        m_resolvedCapMap.remove(module);
+        // Finally, remove module data.
+        m_moduleDataMap.remove(module);
+    }
+
+    private void dumpPackageIndexMap(Map pkgIndexMap)
+    {
+        for (Iterator i = pkgIndexMap.entrySet().iterator(); i.hasNext(); )
+        {
+            Map.Entry entry = (Map.Entry) i.next();
+            IModule[] modules = (IModule[]) entry.getValue();
+            if ((modules != null) && (modules.length > 0))
+            {
+                if (!((modules.length == 1) && modules[0].getId().equals("0")))
+                {
+                    System.out.println("  " + entry.getKey());
+                    for (int j = 0; j < modules.length; j++)
+                    {
+                        System.out.println("    " + modules[j]);
+                    }
+                }
+            }
+        }
+    }
+
+    public synchronized IModule[] getModules()
+    {
+        return (IModule[]) m_moduleList.toArray(new IModule[m_moduleList.size()]);
+    }
+
+    public String getBundleSymbolicName(IModule module)
+    {
+        ICapability[] caps = module.getDefinition().getCapabilities();
+        for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+        {
+            if (caps[capIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            {
+                return (String)
+                    caps[capIdx].getProperties().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
+            }
+        }
+        return null;
+    }
+
+// TODO: FRAGMENT - Not very efficient.
+    private static Version getBundleVersion(IModule module)
+    {
+        ICapability[] caps = module.getDefinition().getCapabilities();
+        for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+        {
+            if (caps[capIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            {
+                return (Version)
+                    caps[capIdx].getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            }
+        }
+        return Version.emptyVersion;
+    }
+
+    public synchronized boolean isResolved(IModule module)
+    {
+        ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+        if (data != null)
+        {
+            return data.m_resolved;
+        }
+        return false;
+    }
+
+    public synchronized void setResolved(IModule module, boolean b)
+    {
+        ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+        if (data == null)
+        {
+            data = new ModuleData(module);
+            m_moduleDataMap.put(module, data);
+        }
+        data.m_resolved = b;
+
+        if (data.m_resolved)
+        {
+            // At this point, we need to remove all of the resolved module's
+            // capabilities from the "unresolved" package map and put them in
+            // in the "resolved" package map, with the exception of any
+            // package exports that are also imported. In that case we need
+            // to make sure that the import actually points to the resolved
+            // 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.getDefinition().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.
+                    m_unresolvedPkgIndexMap.put(
+                        pkgName,
+                        removeModuleFromArray(
+                            (IModule[]) m_unresolvedPkgIndexMap.get(pkgName),
+                            module));
+                }
+            }
+
+            // Next 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);
+            }
+            // 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++)
+            {
+                // 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++)
+                {
+                    // If the wire requirement is satisfied by the current capability,
+                    // then check to see if the wire is to the module itself. If it
+                    // is to another module, then null the current capability since
+                    // it was both providing and requiring the same capability and
+                    // the resolve process chose to import rather than provide that
+                    // capability, therefore we should ignore it.
+                    if (wires[wireIdx].getRequirement().isSatisfied(capsCopy[capIdx]))
+                    {
+                        if (!wires[wireIdx].getExporter().equals(module))
+                        {
+                            capsCopy[capIdx] = null;
+                        }
+                        break;
+                    }
+                }
+            }
+
+            // 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++)
+            {
+                if (capsCopy[capIdx] != null)
+                {
+                    ICapability[] resolvedCaps = (ICapability[]) m_resolvedCapMap.get(module);
+                    resolvedCaps = addCapabilityToArray(resolvedCaps, capsCopy[capIdx]);
+                    m_resolvedCapMap.put(module, resolvedCaps);
+
+                    // 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_resolvedPkgIndexMap,
+                            module,
+                            capsCopy[capIdx]);
+                    }
+                }
+            }
+        }
+
+System.out.println("UNRESOLVED PACKAGES:");
+dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+System.out.println("RESOLVED PACKAGES:");
+dumpPackageIndexMap(m_resolvedPkgIndexMap);
+    }
+
+    // TODO: FRAGMENT - Not very efficient.
+    public synchronized List getPotentialHosts(IModule fragment)
+    {
+        List hostList = new ArrayList();
+
+        IRequirement[] reqs = fragment.getDefinition().getRequirements();
+        IRequirement hostReq = null;
+        for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
+        {
+            if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+            {
+                hostReq = reqs[reqIdx];
+                break;
+            }
+        }
+
+        IModule[] modules = getModules();
+        for (int modIdx = 0; (hostReq != null) && (modIdx < modules.length); modIdx++)
+        {
+            if (!fragment.equals(modules[modIdx]) && !isResolved(modules[modIdx]))
+            {
+                ICapability[] caps = modules[modIdx].getDefinition().getCapabilities();
+                for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+                {
+                    if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
+                        && hostReq.isSatisfied(caps[capIdx])
+                        && !modules[modIdx].isStale())
+                    {
+                        hostList.add(modules[modIdx]);
+                        break;
+                    }
+                }
+            }
+        }
+
+        return hostList;
+    }
+
+// TODO: FRAGMENT - Not very efficient.
+    public synchronized Map getPotentialFragments(IModule host)
+    {
+// TODO: FRAGMENT - This should check to make sure that the host allows fragments.
+        Map fragmentMap = new HashMap();
+
+        ICapability[] caps = host.getDefinition().getCapabilities();
+        ICapability bundleCap = null;
+        for (int capIdx = 0; capIdx < caps.length; capIdx++)
+        {
+            if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+            {
+                bundleCap = caps[capIdx];
+                break;
+            }
+        }
+
+        IModule[] modules = getModules();
+        for (int modIdx = 0; (bundleCap != null) && (modIdx < modules.length); modIdx++)
+        {
+            if (!host.equals(modules[modIdx]))
+            {
+                IRequirement[] reqs = modules[modIdx].getDefinition().getRequirements();
+                for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
+                {
+                    if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
+                        && reqs[reqIdx].isSatisfied(bundleCap)
+                        && !modules[modIdx].isStale())
+                    {
+                        indexFragment(fragmentMap, modules[modIdx]);
+                        break;
+                    }
+                }
+            }
+        }
+
+        return fragmentMap;
+    }
+
+    public synchronized PackageSource[] getResolvedCandidates(IRequirement req)
+    {
+        // Synchronized on the module manager to make sure that no
+        // modules are added, removed, or resolved.
+        PackageSource[] candidates = m_emptySources;
+        if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
+            && (((Requirement) req).getPackageName() != null))
+        {
+            String pkgName = ((Requirement) req).getPackageName();
+            IModule[] modules = (IModule[]) m_resolvedPkgIndexMap.get(pkgName);
+
+            for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
+            {
+                ICapability resolvedCap = Util.getSatisfyingCapability(modules[modIdx], req);
+                if (resolvedCap != null)
+                {
+// TODO: RB - Is this permission check correct.
+                    if ((System.getSecurityManager() != null) &&
+                        !((BundleProtectionDomain) modules[modIdx].getContentLoader().getSecurityContext()).impliesDirect(
+                            new PackagePermission(pkgName,
+                                PackagePermission.EXPORT)))
+                    {
+                        m_logger.log(Logger.LOG_DEBUG,
+                            "PackagePermission.EXPORT denied for "
+                            + pkgName
+                            + "from " + modules[modIdx].getId());
+                    }
+                    else
+                    {
+                        PackageSource[] tmp = new PackageSource[candidates.length + 1];
+                        System.arraycopy(candidates, 0, tmp, 0, candidates.length);
+                        tmp[candidates.length] =
+                            new PackageSource(modules[modIdx], resolvedCap);
+                        candidates = tmp;
+                    }
+                }
+            }
+        }
+        else
+        {
+            Iterator i = m_resolvedCapMap.entrySet().iterator();
+            while (i.hasNext())
+            {
+                Map.Entry entry = (Map.Entry) i.next();
+                IModule module = (IModule) entry.getKey();
+                ICapability[] resolvedCaps = (ICapability[]) entry.getValue();
+                for (int capIdx = 0; capIdx < resolvedCaps.length; capIdx++)
+                {
+                    if (req.isSatisfied(resolvedCaps[capIdx]))
+                    {
+// TODO: RB - Is this permission check correct.
+                        if (resolvedCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+                            (System.getSecurityManager() != null) &&
+                            !((BundleProtectionDomain) module.getContentLoader().getSecurityContext()).impliesDirect(
+                                new PackagePermission(
+                                    (String) resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY),
+                                    PackagePermission.EXPORT)))
+                        {
+                            m_logger.log(Logger.LOG_DEBUG,
+                                "PackagePermission.EXPORT denied for "
+                                + resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY)
+                                + "from " + module.getId());
+                        }
+                        else
+                        {
+                            PackageSource[] tmp = new PackageSource[candidates.length + 1];
+                            System.arraycopy(candidates, 0, tmp, 0, candidates.length);
+                            tmp[candidates.length] = new PackageSource(module, resolvedCaps[capIdx]);
+                            candidates = tmp;
+                        }
+                    }
+                }
+            }
+        }
+        Arrays.sort(candidates);
+        return candidates;
+    }
+
+    public synchronized PackageSource[] getUnresolvedCandidates(IRequirement req)
+    {
+        // Get all modules.
+        IModule[] modules = null;
+        if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+            (((Requirement) req).getPackageName() != null))
+        {
+            modules = (IModule[]) m_unresolvedPkgIndexMap.get(((Requirement) req).getPackageName());
+        }
+        else
+        {
+            modules = getModules();
+        }
+
+        // Create list of compatible providers.
+        PackageSource[] candidates = m_emptySources;
+        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) && !isResolved(modules[modIdx]))
+            {
+                PackageSource[] tmp = new PackageSource[candidates.length + 1];
+                System.arraycopy(candidates, 0, tmp, 0, candidates.length);
+                tmp[candidates.length] = new PackageSource(modules[modIdx], cap);
+                candidates = tmp;
+            }
+        }
+        Arrays.sort(candidates);
+        return candidates;
+    }
+
+    //
+    // Utility methods.
+    //
+
+    private void indexPackageCapability(Map map, IModule module, ICapability capability)
+    {
+        if (capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+        {
+            String pkgName = (String)
+                capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
+            IModule[] modules = (IModule[]) map.get(pkgName);
+
+            // We want to add the module into the list of exporters
+            // in sorted order (descending version and ascending bundle
+            // identifier). Insert using a simple binary search algorithm.
+            if (modules == null)
+            {
+                modules = new IModule[] { module };
+            }
+            else
+            {
+                Version version = (Version)
+                    capability.getProperties().get(ICapability.VERSION_PROPERTY);
+                Version middleVersion = null;
+                int top = 0, bottom = modules.length - 1, middle = 0;
+                while (top <= bottom)
+                {
+                    middle = (bottom - top) / 2 + top;
+                    middleVersion = (Version)
+                        getExportPackageCapability(
+                            modules[middle], pkgName)
+                                .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 = Util.getBundleIdFromModuleId(modules[middle].getId());
+                        long exportId = Util.getBundleIdFromModuleId(module.getId());
+                        if (middleId < exportId)
+                        {
+                            top = middle + 1;
+                        }
+                        else
+                        {
+                            bottom = middle - 1;
+                        }
+                    }
+                    else
+                    {
+                        top = middle + 1;
+                    }
+                }
+
+                // Ignore duplicates.
+                if ((top >= modules.length) || (modules[top] != module))
+                {
+                    IModule[] newMods = new IModule[modules.length + 1];
+                    System.arraycopy(modules, 0, newMods, 0, top);
+                    System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
+                    newMods[top] = module;
+                    modules = newMods;
+                }
+            }
+
+            map.put(pkgName, modules);
+        }
+    }
+
+    private void indexFragment(Map map, IModule module)
+    {
+        String symName = getBundleSymbolicName(module);
+        IModule[] modules = (IModule[]) map.get(symName);
+
+        // We want to add the fragment into the list of matching
+        // fragments in sorted order (descending version and
+        // ascending bundle identifier). Insert using a simple
+        // binary search algorithm.
+        if (modules == null)
+        {
+            modules = new IModule[] { module };
+        }
+        else
+        {
+            Version version = getBundleVersion(module);
+            Version middleVersion = null;
+            int top = 0, bottom = modules.length - 1, middle = 0;
+            while (top <= bottom)
+            {
+                middle = (bottom - top) / 2 + top;
+                middleVersion = getBundleVersion(modules[middle]);
+                // 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 = Util.getBundleIdFromModuleId(modules[middle].getId());
+                    long exportId = Util.getBundleIdFromModuleId(module.getId());
+                    if (middleId < exportId)
+                    {
+                        top = middle + 1;
+                    }
+                    else
+                    {
+                        bottom = middle - 1;
+                    }
+                }
+                else
+                {
+                    top = middle + 1;
+                }
+            }
+
+            // Ignore duplicates.
+            if ((top >= modules.length) || (modules[top] != module))
+            {
+                IModule[] newMods = new IModule[modules.length + 1];
+                System.arraycopy(modules, 0, newMods, 0, top);
+                System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
+                newMods[top] = module;
+                modules = newMods;
+            }
+        }
+
+        map.put(symName, modules);
+    }
+
+    private static IModule[] removeModuleFromArray(IModule[] modules, IModule m)
+    {
+        if (modules == null)
+        {
+            return m_emptyModules;
+        }
+
+        int idx = -1;
+        do
+        {
+            idx = -1;
+            for (int i = 0; i < modules.length; i++)
+            {
+                if (modules[i] == m)
+                {
+                    idx = i;
+                    break;
+                }
+            }
+
+            if (idx >= 0)
+            {
+                // If this is the module, then point to empty list.
+                if ((modules.length - 1) == 0)
+                {
+                    modules = m_emptyModules;
+                }
+                // Otherwise, we need to do some array copying.
+                else
+                {
+                    IModule[] newModules = new IModule[modules.length - 1];
+                    System.arraycopy(modules, 0, newModules, 0, idx);
+                    if (idx < newModules.length)
+                    {
+                        System.arraycopy(
+                            modules, idx + 1, newModules, idx, newModules.length - idx);
+                    }
+                    modules = newModules;
+                }
+            }
+        }
+        while (idx >= 0);
+
+        return modules;
+    }
+
+    public static ICapability getExportPackageCapability(IModule m, String pkgName)
+    {
+        ICapability[] caps = m.getDefinition().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 caps[i];
+            }
+        }
+        return null;
+    }
+
+    private static ICapability[] addCapabilityToArray(ICapability[] caps, ICapability cap)
+    {
+        // Verify that the capability is not already in the array.
+        for (int i = 0; (caps != null) && (i < caps.length); i++)
+        {
+            if (caps[i].equals(cap))
+            {
+                return caps;
+            }
+        }
+
+        if (caps != null)
+        {
+            ICapability[] newCaps = new ICapability[caps.length + 1];
+            System.arraycopy(caps, 0, newCaps, 0, caps.length);
+            newCaps[caps.length] = cap;
+            caps = newCaps;
+        }
+        else
+        {
+            caps = new ICapability[] { cap };
+        }
+
+        return caps;
+    }
+    //
+    // Simple utility classes.
+    //
+
+    private static class ModuleData
+    {
+        public IModule m_module = null;
+        public boolean m_resolved = false;
+        public ModuleData(IModule module)
+        {
+            m_module = module;
+        }
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java
new file mode 100644
index 0000000..e2367db
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java
@@ -0,0 +1,120 @@
+/*
+ * 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.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.Capability;
+import org.apache.felix.moduleloader.ICapability;
+import org.apache.felix.moduleloader.IModule;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * This utility class represents a source for a given package, where
+ * the package is indicated by a particular module and the module's
+ * capability associated with that package. This class also implements
+ * <tt>Comparable</tt> so that two package sources can be compared based
+ * on version and bundle identifiers.
+ */
+public class PackageSource implements Comparable
+{
+    public IModule m_module = null;
+    public ICapability m_capability = null;
+
+    public PackageSource(IModule module, ICapability capability)
+    {
+        super();
+        m_module = module;
+        m_capability = capability;
+    }
+
+    public int compareTo(Object o)
+    {
+        PackageSource ps = (PackageSource) o;
+        Version thisVersion = null;
+        Version version = null;
+        if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+        {
+            thisVersion = ((Capability) m_capability).getPackageVersion();
+            version = ((Capability) ps.m_capability).getPackageVersion();
+        }
+        else if (m_capability.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+        {
+            thisVersion = (Version) m_capability.getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            version = (Version) ps.m_capability.getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+        }
+        if ((thisVersion != null) && (version != null))
+        {
+            int cmp = thisVersion.compareTo(version);
+            if (cmp < 0)
+            {
+                return 1;
+            }
+            else if (cmp > 0)
+            {
+                return -1;
+            }
+            else
+            {
+                long thisId = Util.getBundleIdFromModuleId(m_module.getId());
+                long id = Util.getBundleIdFromModuleId(ps.m_module.getId());
+                if (thisId < id)
+                {
+                    return -1;
+                }
+                else if (thisId > id)
+                {
+                    return 1;
+                }
+                return 0;
+            }
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    public int hashCode()
+    {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((m_capability == null) ? 0 : m_capability.hashCode());
+        result = PRIME * result + ((m_module == null) ? 0 : m_module.hashCode());
+        return result;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+        if (o == null)
+        {
+            return false;
+        }
+        if (getClass() != o.getClass())
+        {
+            return false;
+        }
+        PackageSource ps = (PackageSource) o;
+        return m_module.equals(ps.m_module) && (m_capability == ps.m_capability);
+    }
+}
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
index 1fdf121..e7299e0 100755
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
@@ -22,72 +22,49 @@
 import java.lang.reflect.Proxy;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
 
-import org.apache.felix.framework.BundleProtectionDomain;
+import org.apache.felix.framework.Felix.FelixResolver;
 import org.apache.felix.framework.Logger;
 import org.apache.felix.framework.util.CompoundEnumeration;
 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.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.IModuleFactory;
 import org.apache.felix.moduleloader.IRequirement;
 import org.apache.felix.moduleloader.IWire;
-import org.apache.felix.moduleloader.ModuleEvent;
-import org.apache.felix.moduleloader.ModuleImpl;
-import org.apache.felix.moduleloader.ModuleListener;
 import org.apache.felix.moduleloader.ResourceNotFoundException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.PackagePermission;
-import org.osgi.framework.Version;
 import org.osgi.framework.Bundle;
 
-public class R4SearchPolicyCore implements ModuleListener
+public class R4SearchPolicyCore
 {
-    private Logger m_logger = null;
-    private Map m_configMap = null;
-    private IModuleFactory m_factory = null;
-    // Maps a package name to an array of modules.
-    private Map m_unresolvedPkgIndexMap = new HashMap();
-    // Maps a package name to an array of modules.
-    private Map m_resolvedPkgIndexMap = new HashMap();
-    // Maps a module to an array of capabilities.
-    private Map m_resolvedCapMap = new HashMap();
-    private Map m_moduleDataMap = new HashMap();
+    private final Logger m_logger;
+    private final Map m_configMap;
+    private final FelixResolver m_resolver;
 
     // Boot delegation packages.
     private String[] m_bootPkgs = null;
     private boolean[] m_bootPkgWildcards = null;
 
-    // Listener-related instance variables.
-    private static final ResolveListener[] m_emptyListeners = new ResolveListener[0];
-    private ResolveListener[] m_listeners = m_emptyListeners;
-
     // Reusable empty array.
-    public static final IModule[] m_emptyModules = new IModule[0];
     public static final ICapability[] m_emptyCapabilities = new ICapability[0];
-    public static final PackageSource[] m_emptySources = new PackageSource[0];
 
     // Re-usable security manager for accessing class context.
     private static SecurityManagerEx m_sm = new SecurityManagerEx();
 
-    public R4SearchPolicyCore(Logger logger, Map configMap)
+    public R4SearchPolicyCore(
+        Logger logger, Map configMap, FelixResolver resolver)
     {
         m_logger = logger;
         m_configMap = configMap;
+        m_resolver = resolver;
 
         // Read the boot delegation property and parse it.
         String s = (String) m_configMap.get(Constants.FRAMEWORK_BOOTDELEGATION);
@@ -107,53 +84,6 @@
         }
     }
 
-    public IModuleFactory getModuleFactory()
-    {
-        return m_factory;
-    }
-
-    public void setModuleFactory(IModuleFactory factory)
-        throws IllegalStateException
-    {
-        if (m_factory == null)
-        {
-            m_factory = factory;
-            m_factory.addModuleListener(this);
-        }
-        else
-        {
-            throw new IllegalStateException(
-                "Module manager is already initialized");
-        }
-    }
-
-    /**
-     * Private utility method to check module resolved state.
-     * CONCURRENCY NOTE: This method must be called while holding
-     * a lock on m_factory.
-    **/
-    private boolean isResolved(IModule module)
-    {
-        ModuleData data = (ModuleData) m_moduleDataMap.get(module);
-        return (data == null) ? false : data.m_resolved;
-    }
-
-    /**
-     * Private utility method to set module resolved state.
-     * CONCURRENCY NOTE: This method must be called while holding
-     * a lock on m_factory.
-    **/
-    private void setResolved(IModule module, boolean resolved)
-    {
-        ModuleData data = (ModuleData) m_moduleDataMap.get(module);
-        if (data == null)
-        {
-            data = new ModuleData(module);
-            m_moduleDataMap.put(module, data);
-        }
-        data.m_resolved = resolved;
-    }
-
     public Object[] definePackage(IModule module, String pkgName)
     {
         Map headerMap = ((ModuleDefinition) module.getDefinition()).getHeaders();
@@ -233,7 +163,7 @@
 // for each class load.
         try
         {
-            resolve(module);
+            m_resolver.resolve(module);
         }
         catch (ResolveException ex)
         {
@@ -350,7 +280,15 @@
             // 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 = attemptDynamicImport(module, pkgName);
+            IWire wire = null;
+            try
+            {
+                wire = m_resolver.resolveDynamicImport(module, pkgName);
+            }
+            catch (ResolveException ex)
+            {
+                // Ignore this since it is likely normal.
+            }
             if (wire != null)
             {
                 urls = wire.getResources(name);
@@ -374,7 +312,7 @@
 // for each class load.
         try
         {
-            resolve(module);
+            m_resolver.resolve(module);
         }
         catch (ResolveException ex)
         {
@@ -521,7 +459,15 @@
         // 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 = attemptDynamicImport(module, pkgName);
+        IWire wire = null;
+        try
+        {
+            wire = m_resolver.resolveDynamicImport(module, pkgName);
+        }
+        catch (ResolveException ex)
+        {
+            // Ignore this since it is likely normal.
+        }
 
         // If the dynamic import was successful, then this initial
         // time we must directly return the result from dynamically
@@ -622,259 +568,6 @@
         return null;
     }
 
-    private IWire attemptDynamicImport(IModule importer, String pkgName)
-    {
-        R4Wire wire = null;
-        PackageSource candidate = null;
-
-        // We can only search dynamic imports if the bundle
-        // doesn't import, export, nor require the package in
-        // question. Check these conditions first.
-        if (isDynamicImportAllowed(importer, pkgName))
-        {
-            // 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.getDefinition().getDynamicRequirements();
-            for (int dynIdx = 0; (dynamics != null) && (dynIdx < dynamics.length); dynIdx++)
-            {
-                IRequirement target =
-                    createDynamicRequirement(dynamics[dynIdx], pkgName);
-                if (target != null)
-                {
-                    // See if there is a candidate exporter that satisfies the
-                    // constrained dynamic requirement.
-                    try
-                    {
-                        // Lock module manager instance to ensure that nothing changes.
-                        synchronized (m_factory)
-                        {
-                            // Get "resolved" and "unresolved" candidates and put
-                            // the "resolved" candidates first.
-                            PackageSource[] resolved = getResolvedCandidates(target);
-                            PackageSource[] unresolved = getUnresolvedCandidates(target);
-                            PackageSource[] candidates = new PackageSource[resolved.length + unresolved.length];
-                            System.arraycopy(resolved, 0, candidates, 0, resolved.length);
-                            System.arraycopy(unresolved, 0, candidates, resolved.length, unresolved.length);
-
-                            // Take the first candidate that can resolve.
-                            for (int candIdx = 0;
-                                (candidate == null) && (candIdx < candidates.length);
-                                candIdx++)
-                            {
-                                try
-                                {
-                                    if (resolveDynamicImportCandidate(
-                                        candidates[candIdx].m_module, importer))
-                                    {
-                                        candidate = candidates[candIdx];
-                                    }
-                                }
-                                catch (ResolveException ex)
-                                {
-                                    // Ignore candidates that cannot resolve.
-                                }
-                            }
-
-                            if (candidate != null)
-                            {
-                                IWire[] wires = importer.getWires();
-                                IWire[] newWires = null;
-                                if (wires == null)
-                                {
-                                    newWires = new IWire[1];
-                                }
-                                else
-                                {
-                                    newWires = new IWire[wires.length + 1];
-                                    System.arraycopy(wires, 0, newWires, 0, wires.length);
-                                }
-
-                                // Create the wire and add it to the module.
-                                wire = new R4Wire(
-                                    importer, dynamics[dynIdx], candidate.m_module, candidate.m_capability);
-                                newWires[newWires.length - 1] = wire;
-                                ((ModuleImpl) importer).setWires(newWires);
-m_logger.log(Logger.LOG_DEBUG, "WIRE: " + newWires[newWires.length - 1]);
-                                return wire;
-                            }
-                        }
-                    }
-                    catch (Exception ex)
-                    {
-                        m_logger.log(Logger.LOG_ERROR, "Unable to dynamically import package.", ex);
-                    }
-                }
-            }
-        }
-
-        return null;
-    }
-
-    private boolean isDynamicImportAllowed(IModule importer, String pkgName)
-    {
-        // If any of the module exports this package, then we cannot
-        // attempt to dynamically import it.
-        ICapability[] caps = importer.getDefinition().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 false;
-            }
-        }
-        // If any of our wires have this package, then we cannot
-        // attempt to dynamically import it.
-        IWire[] wires = importer.getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
-        {
-            if (wires[i].hasPackage(pkgName))
-            {
-                return false;
-            }
-        }
-        // Ok to attempt to dynamically import the package.
-        return true;
-    }
-
-    private IRequirement createDynamicRequirement(IRequirement dynReq, String pkgName)
-    {
-        IRequirement req = null;
-
-        // First check to see if the dynamic requirement matches the
-        // package name; this means we have to do wildcard matching.
-        String dynPkgName = ((Requirement) dynReq).getPackageName();
-        boolean wildcard = (dynPkgName.lastIndexOf(".*") >= 0);
-        dynPkgName = (wildcard)
-            ? dynPkgName.substring(0, dynPkgName.length() - 2) : 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 + ".")))
-        {
-            // 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;
-                }
-            }
-            req = new Requirement(ICapability.PACKAGE_NAMESPACE, dirs, newAttrs);
-        }
-
-        return req;
-    }
-
-    private boolean resolveDynamicImportCandidate(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 (!isResolved(provider))
-        {
-            populateCandidatesMap(candidatesMap, provider);
-            findConsistentClassSpace(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 package sources are
-                // compatible with the package source 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 package sources 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_sourceList.clear();
-                        rp.m_sourceList.addAll(rpUses.m_sourceList);
-                    }
-                    else
-                    {
-                        m_logger.log(
-                            Logger.LOG_DEBUG,
-                            "Constraint violation for " + importer
-                            + " detected; module can see "
-                            + rp + " and " + rpUses);
-                        return false;
-                    }
-                }
-            }
-        }
-
-        Map resolvedModuleWireMap = createWires(candidatesMap, provider);
-
-        // Fire resolved events for all resolved modules;
-        // the resolved modules array will only be set if the resolve
-        // was successful.
-        if (resolvedModuleWireMap != null)
-        {
-            Iterator iter = resolvedModuleWireMap.entrySet().iterator();
-            while (iter.hasNext())
-            {
-                fireModuleResolved((IModule) ((Map.Entry) iter.next()).getKey());
-            }
-        }
-
-        return true;
-    }
-
     public String findLibrary(IModule module, String name)
     {
         // Remove leading slash, if present.
@@ -896,1914 +589,6 @@
         return null;
     }
 
-    public PackageSource[] getResolvedCandidates(IRequirement req)
-    {
-        // Synchronized on the module manager to make sure that no
-        // modules are added, removed, or resolved.
-        synchronized (m_factory)
-        {
-            PackageSource[] candidates = m_emptySources;
-            if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
-                && (((Requirement) req).getPackageName() != null))
-            {
-                String pkgName = ((Requirement) req).getPackageName();
-                IModule[] modules = (IModule[]) m_resolvedPkgIndexMap.get(pkgName);
-
-                for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
-                {
-                    ICapability resolvedCap = Util.getSatisfyingCapability(modules[modIdx], req);
-                    if (resolvedCap != null)
-                    {
-// TODO: RB - Is this permission check correct.
-                        if ((System.getSecurityManager() != null) &&
-                            !((BundleProtectionDomain) modules[modIdx].getContentLoader().getSecurityContext()).impliesDirect(
-                                new PackagePermission(pkgName,
-                                    PackagePermission.EXPORT)))
-                        {
-                            m_logger.log(Logger.LOG_DEBUG,
-                                "PackagePermission.EXPORT denied for "
-                                + pkgName
-                                + "from " + modules[modIdx].getId());
-                        }
-                        else
-                        {
-                            PackageSource[] tmp = new PackageSource[candidates.length + 1];
-                            System.arraycopy(candidates, 0, tmp, 0, candidates.length);
-                            tmp[candidates.length] =
-                                new PackageSource(modules[modIdx], resolvedCap);
-                            candidates = tmp;
-                        }
-                    }
-                }
-            }
-            else
-            {
-                Iterator i = m_resolvedCapMap.entrySet().iterator();
-                while (i.hasNext())
-                {
-                    Map.Entry entry = (Map.Entry) i.next();
-                    IModule module = (IModule) entry.getKey();
-                    ICapability[] resolvedCaps = (ICapability[]) entry.getValue();
-                    for (int capIdx = 0; capIdx < resolvedCaps.length; capIdx++)
-                    {
-                        if (req.isSatisfied(resolvedCaps[capIdx]))
-                        {
-// TODO: RB - Is this permission check correct.
-                            if (resolvedCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-                                (System.getSecurityManager() != null) &&
-                                !((BundleProtectionDomain) module.getContentLoader().getSecurityContext()).impliesDirect(
-                                    new PackagePermission(
-                                        (String) resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY),
-                                        PackagePermission.EXPORT)))
-                            {
-                                m_logger.log(Logger.LOG_DEBUG,
-                                    "PackagePermission.EXPORT denied for "
-                                    + resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY)
-                                    + "from " + module.getId());
-                            }
-                            else
-                            {
-                                PackageSource[] tmp = new PackageSource[candidates.length + 1];
-                                System.arraycopy(candidates, 0, tmp, 0, candidates.length);
-                                tmp[candidates.length] = new PackageSource(module, resolvedCaps[capIdx]);
-                                candidates = tmp;
-                            }
-                        }
-                    }
-                }
-            }
-            Arrays.sort(candidates);
-            return candidates;
-        }
-    }
-
-    public PackageSource[] getUnresolvedCandidates(IRequirement req)
-    {
-        // Synchronized on the module manager to make sure that no
-        // modules are added, removed, or resolved.
-        synchronized (m_factory)
-        {
-            // Get all modules.
-            IModule[] modules = null;
-            if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-                (((Requirement) req).getPackageName() != null))
-            {
-                modules = (IModule[]) m_unresolvedPkgIndexMap.get(((Requirement) req).getPackageName());
-            }
-            else
-            {
-                modules = m_factory.getModules();
-            }
-
-            // Create list of compatible providers.
-            PackageSource[] candidates = m_emptySources;
-            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) && !isResolved(modules[modIdx]))
-                {
-                    PackageSource[] tmp = new PackageSource[candidates.length + 1];
-                    System.arraycopy(candidates, 0, tmp, 0, candidates.length);
-                    tmp[candidates.length] = new PackageSource(modules[modIdx], cap);
-                    candidates = tmp;
-                }
-            }
-            Arrays.sort(candidates);
-            return candidates;
-        }
-    }
-
-    public void resolve(IModule rootModule)
-        throws ResolveException
-    {
-        // This map will be used to hold the final wires for all
-        // resolved modules, which can then be used to fire resolved
-        // events outside of the synchronized block.
-        Map resolvedModuleWireMap = null;
-        Map fragmentMap = null;
-
-        // Synchronize on the module manager, because we don't want
-        // any modules being added or removed while we are in the
-        // middle of this operation.
-        synchronized (m_factory)
-        {
-            // If the module is already resolved, then we can just return.
-            if (isResolved(rootModule))
-            {
-                return;
-            }
-
-            // The root module is either a host or a fragment. If it is a host,
-            // then we want to go ahead and resolve it. If it is a fragment, then
-            // we want to select a host and resolve the host instead.
-            IModule targetFragment = null;
-// TODO: FRAGMENT - Currently we just make a single selection of the available
-//       fragments or hosts and try to resolve. In case of failure, we do not
-//       backtrack. We will likely want to add backtracking.
-            if (Util.isFragment(rootModule))
-            {
-                targetFragment = rootModule;
-                List hostList = getPotentialHosts(targetFragment);
-                rootModule = (IModule) hostList.get(0);
-            }
-
-            // Get the available fragments for the host.
-            fragmentMap = getPotentialFragments(rootModule);
-
-            // If the resolve was for a specific fragment, then
-            // eliminate all other potential candidate fragments
-            // of the same symbolic name.
-            if (targetFragment != null)
-            {
-                fragmentMap.put(
-                    getBundleSymbolicName(targetFragment),
-                    new IModule[] { targetFragment });
-            }
-
-            // 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(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(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.
-            resolvedModuleWireMap = createWires(candidatesMap, rootModule);
-
-            // Attach fragments to root module.
-            if ((fragmentMap != null) && (fragmentMap.size() > 0))
-            {
-                List list = new ArrayList();
-                for (Iterator iter = fragmentMap.entrySet().iterator(); iter.hasNext(); )
-                {
-                    Map.Entry entry = (Map.Entry) iter.next();
-                    String symName = (String) entry.getKey();
-                    IModule[] fragments = (IModule[]) entry.getValue();
-// TODO: FRAGMENT - For now, just attach first candidate.
-                    list.add(fragments[0]);
-                    setResolved(fragments[0], true);
-m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: "
-    + rootModule + " -> " + symName + " -> " + fragments[0]);
-                }
-                try
-                {
-                    ((ModuleImpl) rootModule).attachFragments(
-                        (IModule[]) list.toArray(new IModule[list.size()]));
-                }
-                catch (Exception ex)
-                {
-                    m_logger.log(Logger.LOG_ERROR, "Unable to attach fragments", ex);
-                }
-            }
-        } // End of synchronized block on module manager.
-
-        // Fire resolved events for all resolved modules;
-        // the resolved modules array will only be set if the resolve
-        // was successful after the root module was resolved.
-        if (resolvedModuleWireMap != null)
-        {
-            Iterator iter = resolvedModuleWireMap.entrySet().iterator();
-            while (iter.hasNext())
-            {
-                fireModuleResolved((IModule) ((Map.Entry) iter.next()).getKey());
-            }
-            iter = fragmentMap.entrySet().iterator();
-            while (iter.hasNext())
-            {
-                fireModuleResolved(((IModule[]) ((Map.Entry) iter.next()).getValue())[0]);
-            }
-        }
-    }
-
-    // TODO: FRAGMENT - Not very efficient.
-    private List getPotentialHosts(IModule fragment)
-        throws ResolveException
-    {
-        List hostList = new ArrayList();
-
-        IRequirement[] reqs = fragment.getDefinition().getRequirements();
-        IRequirement hostReq = null;
-        for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
-        {
-            if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
-            {
-                hostReq = reqs[reqIdx];
-                break;
-            }
-        }
-
-        IModule[] modules = m_factory.getModules();
-        for (int modIdx = 0; (hostReq != null) && (modIdx < modules.length); modIdx++)
-        {
-            if (!fragment.equals(modules[modIdx]) && !isResolved(modules[modIdx]))
-            {
-                ICapability[] caps = modules[modIdx].getDefinition().getCapabilities();
-                for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
-                {
-                    if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
-                        && hostReq.isSatisfied(caps[capIdx])
-                        && !modules[modIdx].isStale())
-                    {
-                        hostList.add(modules[modIdx]);
-                        break;
-                    }
-                }
-            }
-        }
-
-        if (hostList.size() == 0)
-        {
-            throw new ResolveException("Unable to resolve.", fragment, hostReq);
-        }
-
-        return hostList;
-    }
-
-// TODO: FRAGMENT - Not very efficient.
-    private Map getPotentialFragments(IModule host)
-    {
-// TODO: FRAGMENT - This should check to make sure that the host allows fragments.
-        Map fragmentMap = new HashMap();
-
-        ICapability[] caps = host.getDefinition().getCapabilities();
-        ICapability bundleCap = null;
-        for (int capIdx = 0; capIdx < caps.length; capIdx++)
-        {
-            if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
-            {
-                bundleCap = caps[capIdx];
-                break;
-            }
-        }
-
-        IModule[] modules = m_factory.getModules();
-        for (int modIdx = 0; (bundleCap != null) && (modIdx < modules.length); modIdx++)
-        {
-            if (!host.equals(modules[modIdx]))
-            {
-                IRequirement[] reqs = modules[modIdx].getDefinition().getRequirements();
-                for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
-                {
-                    if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
-                        && reqs[reqIdx].isSatisfied(bundleCap)
-                        && !modules[modIdx].isStale())
-                    {
-                        indexFragment(fragmentMap, modules[modIdx]);
-                        break;
-                    }
-                }
-            }
-        }
-
-        return fragmentMap;
-    }
-
-// TODO: FRAGMENT - Not very efficient.
-    private static String getBundleSymbolicName(IModule module)
-    {
-        ICapability[] caps = module.getDefinition().getCapabilities();
-        for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
-        {
-            if (caps[capIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                return (String)
-                    caps[capIdx].getProperties().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
-            }
-        }
-        return null;
-    }
-
-// TODO: FRAGMENT - Not very efficient.
-    private static Version getBundleVersion(IModule module)
-    {
-        ICapability[] caps = module.getDefinition().getCapabilities();
-        for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
-        {
-            if (caps[capIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                return (Version)
-                    caps[capIdx].getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
-            }
-        }
-        return Version.emptyVersion;
-    }
-
-    private void indexFragment(Map map, IModule module)
-    {
-        String symName = getBundleSymbolicName(module);
-        IModule[] modules = (IModule[]) map.get(symName);
-
-        // We want to add the fragment into the list of matching
-        // fragments in sorted order (descending version and
-        // ascending bundle identifier). Insert using a simple
-        // binary search algorithm.
-        if (modules == null)
-        {
-            modules = new IModule[] { module };
-        }
-        else
-        {
-            Version version = getBundleVersion(module);
-            Version middleVersion = null;
-            int top = 0, bottom = modules.length - 1, middle = 0;
-            while (top <= bottom)
-            {
-                middle = (bottom - top) / 2 + top;
-                middleVersion = getBundleVersion(modules[middle]);
-                // 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 = Util.getBundleIdFromModuleId(modules[middle].getId());
-                    long exportId = Util.getBundleIdFromModuleId(module.getId());
-                    if (middleId < exportId)
-                    {
-                        top = middle + 1;
-                    }
-                    else
-                    {
-                        bottom = middle - 1;
-                    }
-                }
-                else
-                {
-                    top = middle + 1;
-                }
-            }
-
-            // Ignore duplicates.
-            if ((top >= modules.length) || (modules[top] != module))
-            {
-                IModule[] newMods = new IModule[modules.length + 1];
-                System.arraycopy(modules, 0, newMods, 0, top);
-                System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
-                newMods[top] = module;
-                modules = newMods;
-            }
-        }
-
-        map.put(symName, modules);
-    }
-
-    private void populateCandidatesMap(Map candidatesMap, IModule module)
-        throws ResolveException
-    {
-        // Detect cycles.
-        if (candidatesMap.get(module) != null)
-        {
-            return;
-        }
-
-        // List to hold the resolving candidate sets for the module's
-        // requirements.
-        List candSetList = new ArrayList();
-
-        // Even though the candidate set list is currently empty, we
-        // record it in the candidates map early so we can use it to
-        // detect cycles.
-        candidatesMap.put(module, candSetList);
-
-        // Loop through each requirement and calculate its resolving
-        // set of candidates.
-        IRequirement[] reqs = module.getDefinition().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.
-            PackageSource[] resolved = getResolvedCandidates(reqs[reqIdx]);
-            PackageSource[] unresolved = getUnresolvedCandidates(reqs[reqIdx]);
-            PackageSource[] candidates = new PackageSource[resolved.length + unresolved.length];
-            System.arraycopy(resolved, 0, candidates, 0, resolved.length);
-            System.arraycopy(unresolved, 0, candidates, resolved.length, unresolved.length);
-
-            // If we have candidates, then we need to recursively populate
-            // the resolver map with each of them.
-            ResolveException rethrow = null;
-            if (candidates.length > 0)
-            {
-                for (int candIdx = 0; candIdx < candidates.length; candIdx++)
-                {
-                    try
-                    {
-                        // Only populate the resolver map with modules that
-                        // are not already resolved.
-                        if (!isResolved(candidates[candIdx].m_module))
-                        {
-                            populateCandidatesMap(candidatesMap, candidates[candIdx].m_module);
-                        }
-                    }
-                    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.
-                        candidates[candIdx] = null;
-                        rethrow = ex;
-                    }
-                }
-
-                // Remove any nulled candidates to create the final list
-                // of available candidates.
-                candidates = shrinkCandidateArray(candidates);
-            }
-
-            // If no candidates exist at this point, then throw a
-            // resolve exception unless the import is optional.
-            if ((candidates.length == 0) && !reqs[reqIdx].isOptional())
-            {
-                // If we have received an exception while trying to populate
-                // the resolver 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.", module, reqs[reqIdx]);
-                }
-            }
-            else if (candidates.length > 0)
-            {
-                candSetList.add(
-                    new CandidateSet(module, reqs[reqIdx], candidates));
-            }
-        }
-    }
-
-    private void dumpPackageIndexMap(Map pkgIndexMap)
-    {
-        synchronized (this)
-        {
-            for (Iterator i = pkgIndexMap.entrySet().iterator(); i.hasNext(); )
-            {
-                Map.Entry entry = (Map.Entry) i.next();
-                IModule[] modules = (IModule[]) entry.getValue();
-                if ((modules != null) && (modules.length > 0))
-                {
-                    if (!((modules.length == 1) && modules[0].getId().equals("0")))
-                    {
-                        System.out.println("  " + entry.getKey());
-                        for (int j = 0; j < modules.length; j++)
-                        {
-                            System.out.println("    " + modules[j]);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private void dumpPackageSources(Map pkgMap)
-    {
-        for (Iterator i = pkgMap.entrySet().iterator(); i.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) i.next();
-            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
-            System.out.println(rp);
-        }
-    }
-
-    private void findConsistentClassSpace(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(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(); )
-                {
-                    candidatesList.add(((Map.Entry) iter.next()).getValue());
-                }
-            }
-
-            // Increment the candidate configuration so we can test again.
-            incrementCandidateConfiguration(candidatesList);
-
-            // 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(IModule targetModule, Map moduleMap, Map candidatesMap)
-    {
-        // Create a map of all resolved singleton modules.
-        Map singletonMap = new HashMap();
-        IModule[] modules = m_factory.getModules();
-        for (int i = 0; (modules != null) && (i < modules.length); i++)
-        {
-            if (isResolved(modules[i]) && isSingleton(modules[i]))
-            {
-                String symName = getBundleSymbolicName(modules[i]);
-                singletonMap.put(symName, symName);
-            }
-        }
-
-        return areCandidatesSingletonConsistent(
-            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(
-        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 = getBundleSymbolicName(targetModule);
-        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 package sources 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
-            // package sources for the given package.
-            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
-            // Loop through each package source and test if it is consistent.
-            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
-            {
-                // If the module for this package source is not resolved, then
-                // we have to see if resolving it would violate a singleton
-                // constraint.
-                PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
-                if (!isResolved(ps.m_module))
-                {
-                    return areCandidatesSingletonConsistent(ps.m_module, 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 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 package sources.
-        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 package sources 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
-            // package sources for the given package.
-            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
-            // Loop through each package source and test if it is consistent.
-            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
-            {
-                PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
-                if (!isClassSpaceConsistent(ps.m_module, 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 package sources are
-                // compatible with the package source 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 package sources 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_sourceList.clear();
-                        rp.m_sourceList.addAll(rpUses.m_sourceList);
-                    }
-                    else
-                    {
-                        m_logger.log(
-                            Logger.LOG_DEBUG,
-                            "Constraint violation for " + targetModule
-                            + " detected; module can see "
-                            + rp + " and " + rpUses);
-                        return false;
-                    }
-                }
-            }
-        }
-
-        return true;
-    }
-
-    private 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 modules, called package sources. The
-        // "uses" constraints implied by all package sources 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 srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
-            {
-                usesMap = calculateUsesConstraints(
-                    (PackageSource) rp.m_sourceList.get(srcIdx),
-                    moduleMap, usesMap, cycleMap, candidatesMap);
-            }
-        }
-        return usesMap;
-    }
-
-    private Map calculateUsesConstraints(
-        PackageSource psTarget, 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(psTarget) != null)
-        {
-            return usesMap;
-        }
-
-        // Record the target package source in the cycle map.
-        cycleMap.put(psTarget, psTarget);
-
-        // Get all packages accessible from the module of the
-        // target package source.
-        Map pkgMap = getModulePackages(moduleMap, psTarget.m_module, candidatesMap);
-
-        // Get capability (i.e., package) of the target package source.
-        Capability cap = (Capability) psTarget.m_capability;
-
-        // Loop through all "used" packages of the capability.
-        for (int i = 0; i < cap.getUses().length; i++)
-        {
-            // The target package source 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 package sources for the resolved
-                // package associated with the current "used" package and calculate
-                // and combine the "uses" constraints for each package source.
-                for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
-                {
-                    usesMap = calculateUsesConstraints(
-                        (PackageSource) rp.m_sourceList.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 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 sources. 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 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 source to the end of
-        // the require package sources; 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
-                // package sources 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 Map calculateImportedPackages(IModule targetModule, Map candidatesMap)
-        throws ResolveException
-    {
-        return (candidatesMap.get(targetModule) == null)
-            ? calculateImportedPackagesResolved(targetModule)
-            : calculateImportedPackagesUnresolved(targetModule, candidatesMap);
-    }
-
-    private 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 package source
-        // to the imported package map.
-        for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
-        {
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-            PackageSource ps = cs.m_candidates[cs.m_idx];
-
-            if (ps.m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                String pkgName = (String)
-                    ps.m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
-
-                ResolvedPackage rp = new ResolvedPackage(pkgName);
-                rp.m_sourceList.add(ps);
-                pkgMap.put(rp.m_name, rp);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private 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 package source 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) : rp;
-                rp.m_sourceList.add(new PackageSource(wires[wireIdx].getExporter(), wires[wireIdx].getCapability()));
-                pkgMap.put(rp.m_name, rp);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private 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.getDefinition().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) : rp;
-                rp.m_sourceList.add(new PackageSource(targetModule, caps[capIdx]));
-                pkgMap.put(rp.m_name, rp);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private Map calculateRequiredPackages(IModule targetModule, Map candidatesMap)
-    {
-        return (candidatesMap.get(targetModule) == null)
-            ? calculateRequiredPackagesResolved(targetModule)
-            : calculateRequiredPackagesUnresolved(targetModule, candidatesMap);
-    }
-
-    private 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);
-            PackageSource ps = cs.m_candidates[cs.m_idx];
-
-            // If the capabaility is a module dependency, then flatten it to packages.
-            if (ps.m_capability.getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                // Calculate transitively required packages.
-                Map cycleMap = new HashMap();
-                cycleMap.put(targetModule, targetModule);
-                Map requireMap =
-                    calculateExportedAndReexportedPackages(
-                        ps, 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
-                        // package sources and maintaining ordering.
-                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
-                        rp.merge(rpReq);
-                    }
-                    else
-                    {
-                        pkgMap.put(entry.getKey(), entry.getValue());
-                    }
-                }
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private 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
-                        // package sources and maintaining ordering.
-                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
-                        rp.merge(rpReq);
-                    }
-                    else
-                    {
-                        pkgMap.put(entry.getKey(), entry.getValue());
-                    }
-                }
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private Map calculateExportedAndReexportedPackages(
-        PackageSource psTarget, Map candidatesMap, Map cycleMap)
-    {
-        return (candidatesMap.get(psTarget.m_module) == null)
-            ? calculateExportedAndReexportedPackagesResolved(psTarget.m_module, cycleMap)
-            : calculateExportedAndReexportedPackagesUnresolved(psTarget, candidatesMap, cycleMap);
-    }
-
-    private Map calculateExportedAndReexportedPackagesUnresolved(
-        PackageSource psTarget, Map candidatesMap, Map cycleMap)
-    {
-//System.out.println("calculateExportedAndReexportedPackagesUnresolved("+psTarget.m_module+")");
-        Map pkgMap = new HashMap();
-
-        if (cycleMap.get(psTarget.m_module) != null)
-        {
-            return pkgMap;
-        }
-
-        cycleMap.put(psTarget.m_module, psTarget.m_module);
-
-        // Loop through all current candidates for target module's dependencies
-        // and calculate the module's complete set of required packages (and
-        // their associated package sources) and the complete set of required
-        // packages to be re-exported.
-        Map allRequiredMap = new HashMap();
-        Map reexportedPkgMap = new HashMap();
-        List candSetList = (List) candidatesMap.get(psTarget.m_module);
-        for (int candSetIdx = 0; candSetIdx < candSetList.size(); candSetIdx++)
-        {
-            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-            PackageSource ps = cs.m_candidates[cs.m_idx];
-
-            // If the candidate is resolving a module dependency, then
-            // flatten the required packages if they are re-exported.
-            if (ps.m_capability.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(ps, 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 package sources will ultimately need to
-                    // be combined with privately required package sources,
-                    // 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 package sources.
-                        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 package sources 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 package source for any exported packages.
-        ICapability[] candCaps = psTarget.m_module.getDefinition().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) : rp;
-                rp.m_sourceList.add(new PackageSource(psTarget.m_module, candCaps[capIdx]));
-                pkgMap.put(rp.m_name, rp);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private 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 package 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 package sources will ultimately need to
-                    // be combined with privately required package sources,
-                    // 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 package sources.
-                        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 package sources 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 package source for any exported packages.
-        ICapability[] caps = targetModule.getDefinition().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) : rp;
-                rp.m_sourceList.add(new PackageSource(targetModule, caps[i]));
-                pkgMap.put(rp.m_name, rp);
-            }
-        }
-
-        return pkgMap;
-    }
-
-    private Map calculateCandidateRequiredPackages(IModule module, PackageSource psTarget, Map candidatesMap)
-    {
-//System.out.println("calculateCandidateRequiredPackages("+module+")");
-        Map cycleMap = new HashMap();
-        cycleMap.put(module, module);
-        return calculateExportedAndReexportedPackages(psTarget, candidatesMap, cycleMap);
-    }
-
-    private 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.length)
-                {
-                    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 Map createWires(Map candidatesMap, IModule rootModule)
-    {
-        // Get a map of all modules and their resolved wires.
-        Map resolvedModuleWireMap =
-            populateWireMap(candidatesMap, rootModule, new HashMap());
-        Iterator iter = resolvedModuleWireMap.entrySet().iterator();
-        // Iterate over the map to mark the modules as resolved and
-        // update our resolver data structures.
-        while (iter.hasNext())
-        {
-            Map.Entry entry = (Map.Entry) iter.next();
-            IModule module = (IModule) entry.getKey();
-            IWire[] wires = (IWire[]) entry.getValue();
-
-            // Set the module's resolved and wiring attribute.
-            setResolved(module, true);
-            // Only add wires attribute if some exist; export
-            // only modules may not have wires.
-            if (wires.length > 0)
-            {
-                ((ModuleImpl) module).setWires(wires);
-for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
-{
-    m_logger.log(Logger.LOG_DEBUG, "WIRE: " + wires[wireIdx]);
-}
-            }
-
-            // At this point, we need to remove all of the resolved module's
-            // capabilities from the "unresolved" package map and put them in
-            // in the "resolved" package map, with the exception of any
-            // package exports that are also imported. In that case we need
-            // to make sure that the import actually points to the resolved
-            // 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.getDefinition().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.
-                    m_unresolvedPkgIndexMap.put(
-                        pkgName,
-                        removeModuleFromArray(
-                            (IModule[]) m_unresolvedPkgIndexMap.get(pkgName),
-                            module));
-                }
-            }
-
-            // Next 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);
-            }
-            // 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.
-            for (int capIdx = 0; (capsCopy != null) && (capIdx < capsCopy.length); 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++)
-                {
-                    // If the wire requirement is satisfied by the current capability,
-                    // then check to see if the wire is to the module itself. If it
-                    // is to another module, then null the current capability since
-                    // it was both providing and requiring the same capability and
-                    // the resolve process chose to import rather than provide that
-                    // capability, therefore we should ignore it.
-                    if (wires[wireIdx].getRequirement().isSatisfied(capsCopy[capIdx]))
-                    {
-                        if (!wires[wireIdx].getExporter().equals(module))
-                        {
-                            capsCopy[capIdx] = null;
-                        }
-                        break;
-                    }
-                }
-            }
-
-            // 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++)
-            {
-                if (capsCopy[capIdx] != null)
-                {
-                    ICapability[] resolvedCaps = (ICapability[]) m_resolvedCapMap.get(module);
-                    resolvedCaps = addCapabilityToArray(resolvedCaps, capsCopy[capIdx]);
-                    m_resolvedCapMap.put(module, resolvedCaps);
-
-                    // 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_resolvedPkgIndexMap,
-                            module,
-                            capsCopy[capIdx]);
-                    }
-                }
-            }
-        }
-
-//System.out.println("UNRESOLVED INDEX:");
-//dumpPackageIndexMap(m_unresolvedPkgIndexMap);
-//System.out.println("RESOLVED INDEX:");
-//dumpPackageIndexMap(m_resolvedPkgIndexMap);
-        return resolvedModuleWireMap;
-    }
-
-    private Map populateWireMap(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 (isResolved(importer) || (wireMap.get(importer) != null))
-        {
-            return wireMap;
-        }
-
-        List candSetList = (List) candidatesMap.get(importer);
-        List moduleWires = new ArrayList();
-        List packageWires = new ArrayList();
-        IWire[] wires = new IWire[candSetList.size()];
-
-        // 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, wires);
-
-        // 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 wire for the current candidate based on the type
-            // of requirement it resolves.
-            if (cs.m_requirement.getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                moduleWires.add(new R4WireModule(
-                    importer,
-                    cs.m_requirement,
-                    cs.m_candidates[cs.m_idx].m_module,
-                    cs.m_candidates[cs.m_idx].m_capability,
-                    calculateCandidateRequiredPackages(importer, cs.m_candidates[cs.m_idx], candidatesMap)));
-            }
-            else
-            {
-                // Add wire for imported package.
-                packageWires.add(new R4Wire(
-                    importer,
-                    cs.m_requirement,
-                    cs.m_candidates[cs.m_idx].m_module,
-                    cs.m_candidates[cs.m_idx].m_capability));
-            }
-
-            // Create any necessary wires for the selected candidate module.
-            wireMap = populateWireMap(
-                candidatesMap, cs.m_candidates[cs.m_idx].m_module, wireMap);
-        }
-
-        packageWires.addAll(moduleWires);
-        wireMap.put(importer, packageWires.toArray(wires));
-
-        return wireMap;
-    }
-
-    //
-    // Event handling methods for validation events.
-    //
-
-    /**
-     * Adds a resolver listener to the search policy. Resolver
-     * listeners are notified when a module is resolve and/or unresolved
-     * by the search policy.
-     * @param l the resolver listener to add.
-    **/
-    public void addResolverListener(ResolveListener l)
-    {
-        // Verify listener.
-        if (l == null)
-        {
-            throw new IllegalArgumentException("Listener is null");
-        }
-
-        // Use the m_noListeners object as a lock.
-        synchronized (m_emptyListeners)
-        {
-            // If we have no listeners, then just add the new listener.
-            if (m_listeners == m_emptyListeners)
-            {
-                m_listeners = new ResolveListener[] { l };
-            }
-            // Otherwise, we need to do some array copying.
-            // Notice, the old array is always valid, so if
-            // the dispatch thread is in the middle of a dispatch,
-            // then it has a reference to the old listener array
-            // and is not affected by the new value.
-            else
-            {
-                ResolveListener[] newList = new ResolveListener[m_listeners.length + 1];
-                System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
-                newList[m_listeners.length] = l;
-                m_listeners = newList;
-            }
-        }
-    }
-
-    /**
-     * Removes a resolver listener to this search policy.
-     * @param l the resolver listener to remove.
-    **/
-    public void removeResolverListener(ResolveListener l)
-    {
-        // Verify listener.
-        if (l == null)
-        {
-            throw new IllegalArgumentException("Listener is null");
-        }
-
-        // Use the m_emptyListeners object as a lock.
-        synchronized (m_emptyListeners)
-        {
-            // Try to find the instance in our list.
-            int idx = -1;
-            for (int i = 0; i < m_listeners.length; i++)
-            {
-                if (m_listeners[i].equals(l))
-                {
-                    idx = i;
-                    break;
-                }
-            }
-
-            // If we have the instance, then remove it.
-            if (idx >= 0)
-            {
-                // If this is the last listener, then point to empty list.
-                if (m_listeners.length == 1)
-                {
-                    m_listeners = m_emptyListeners;
-                }
-                // Otherwise, we need to do some array copying.
-                // Notice, the old array is always valid, so if
-                // the dispatch thread is in the middle of a dispatch,
-                // then it has a reference to the old listener array
-                // and is not affected by the new value.
-                else
-                {
-                    ResolveListener[] newList = new ResolveListener[m_listeners.length - 1];
-                    System.arraycopy(m_listeners, 0, newList, 0, idx);
-                    if (idx < newList.length)
-                    {
-                        System.arraycopy(m_listeners, idx + 1, newList, idx,
-                            newList.length - idx);
-                    }
-                    m_listeners = newList;
-                }
-            }
-        }
-    }
-
-    /**
-     * Fires a validation event for the specified module.
-     * @param module the module that was resolved.
-    **/
-    private void fireModuleResolved(IModule module)
-    {
-        // Event holder.
-        ModuleEvent event = null;
-
-        // Get a copy of the listener array, which is guaranteed
-        // to not be null.
-        ResolveListener[] listeners = m_listeners;
-
-        // Loop through listeners and fire events.
-        for (int i = 0; i < listeners.length; i++)
-        {
-            // Lazily create event.
-            if (event == null)
-            {
-                event = new ModuleEvent(m_factory, module);
-            }
-            listeners[i].moduleResolved(event);
-        }
-    }
-
-    /**
-     * Fires an unresolved event for the specified module.
-     * @param module the module that was unresolved.
-    **/
-    private void fireModuleUnresolved(IModule module)
-    {
-// TODO: FRAMEWORK - Call this method where appropriate.
-        // Event holder.
-        ModuleEvent event = null;
-
-        // Get a copy of the listener array, which is guaranteed
-        // to not be null.
-        ResolveListener[] listeners = m_listeners;
-
-        // Loop through listeners and fire events.
-        for (int i = 0; i < listeners.length; i++)
-        {
-            // Lazily create event.
-            if (event == null)
-            {
-                event = new ModuleEvent(m_factory, module);
-            }
-            listeners[i].moduleUnresolved(event);
-        }
-    }
-
-    //
-    // ModuleListener callback methods.
-    //
-
-    public void moduleAdded(ModuleEvent event)
-    {
-        synchronized (m_factory)
-        {
-            // When a module is added, create an aggregated list of unresolved
-            // exports to simplify later processing when resolving bundles.
-            IModule module = event.getModule();
-            ICapability[] caps = module.getDefinition().getCapabilities();
-
-            // Add exports to unresolved package map.
-            for (int i = 0; (caps != null) && (i < caps.length); i++)
-            {
-                if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                {
-                    indexPackageCapability(m_unresolvedPkgIndexMap, module, caps[i]);
-                }
-            }
-        }
-    }
-
-    public void moduleRemoved(ModuleEvent event)
-    {
-        // When a module is removed from the system, we need remove
-        // its exports from the "resolved" and "unresolved" package maps,
-        // remove the module's dependencies on fragments and exporters,
-        // and remove the module from the module data map.
-
-        // Synchronize on the module manager, since we don't want any
-        // bundles to be installed or removed.
-        synchronized (m_factory)
-        {
-            // Remove exports from package maps.
-            ICapability[] caps = event.getModule().getDefinition().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.
-                    IModule[] modules = (IModule[]) m_unresolvedPkgIndexMap.get(pkgName);
-                    if (modules != null)
-                    {
-                        modules = removeModuleFromArray(modules, event.getModule());
-                        m_unresolvedPkgIndexMap.put(pkgName, modules);
-                    }
-
-                    // Remove from "resolved" package map.
-                    modules = (IModule[]) m_resolvedPkgIndexMap.get(pkgName);
-                    if (modules != null)
-                    {
-                        modules = removeModuleFromArray(modules, event.getModule());
-                        m_resolvedPkgIndexMap.put(pkgName, modules);
-                    }
-                }
-            }
-
-            // Set fragments to null, which will remove the module from all
-            // of its dependent fragment modules.
-            try
-            {
-                ((ModuleImpl) event.getModule()).attachFragments(null);
-            }
-            catch (Exception ex)
-            {
-                m_logger.log(Logger.LOG_ERROR, "Error detaching fragments.", ex);
-            }
-            // Set wires to null, which will remove the module from all
-            // of its dependent modules.
-            ((ModuleImpl) event.getModule()).setWires(null);
-            // Remove the module from the "resolved" map.
-// TODO: RB - Maybe this can be merged with ModuleData.
-            m_resolvedCapMap.remove(event.getModule());
-            // Finally, remove module data.
-            m_moduleDataMap.remove(event.getModule());
-        }
-    }
-
     /**
      * This is an experimental method that is likely to change or go
      * away - so don't use it for now.
@@ -2818,6 +603,7 @@
      * For now we assume that capabilities have been added only. We might need to
      * enforce that at one point of time.
      */
+/* TODO: RESOLVER - We need to figure out what to do with this.
     public void moduleRefreshed(ModuleEvent event)
     {
         synchronized (m_factory)
@@ -2849,422 +635,7 @@
             }
         }
     }
-
-    private void indexPackageCapability(Map map, IModule module, ICapability capability)
-    {
-        if (capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-        {
-            String pkgName = (String)
-                capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
-            IModule[] modules = (IModule[]) map.get(pkgName);
-
-            // We want to add the module into the list of exporters
-            // in sorted order (descending version and ascending bundle
-            // identifier). Insert using a simple binary search algorithm.
-            if (modules == null)
-            {
-                modules = new IModule[] { module };
-            }
-            else
-            {
-                Version version = (Version)
-                    capability.getProperties().get(ICapability.VERSION_PROPERTY);
-                Version middleVersion = null;
-                int top = 0, bottom = modules.length - 1, middle = 0;
-                while (top <= bottom)
-                {
-                    middle = (bottom - top) / 2 + top;
-                    middleVersion = (Version)
-                        getExportPackageCapability(
-                            modules[middle], pkgName)
-                                .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 = Util.getBundleIdFromModuleId(modules[middle].getId());
-                        long exportId = Util.getBundleIdFromModuleId(module.getId());
-                        if (middleId < exportId)
-                        {
-                            top = middle + 1;
-                        }
-                        else
-                        {
-                            bottom = middle - 1;
-                        }
-                    }
-                    else
-                    {
-                        top = middle + 1;
-                    }
-                }
-
-                // Ignore duplicates.
-                if ((top >= modules.length) || (modules[top] != module))
-                {
-                    IModule[] newMods = new IModule[modules.length + 1];
-                    System.arraycopy(modules, 0, newMods, 0, top);
-                    System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
-                    newMods[top] = module;
-                    modules = newMods;
-                }
-            }
-
-            map.put(pkgName, modules);
-        }
-    }
-
-    public static ICapability getExportPackageCapability(IModule m, String pkgName)
-    {
-        ICapability[] caps = m.getDefinition().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 caps[i];
-            }
-        }
-        return null;
-    }
-
-    //
-    // Simple utility methods.
-    //
-/*
-    private static IModule[] addModuleToArray(IModule[] modules, IModule m)
-    {
-        // Verify that the module is not already in the array.
-        for (int i = 0; (modules != null) && (i < modules.length); i++)
-        {
-            if (modules[i] == m)
-            {
-                return modules;
-            }
-        }
-
-        if (modules != null)
-        {
-            IModule[] newModules = new IModule[modules.length + 1];
-            System.arraycopy(modules, 0, newModules, 0, modules.length);
-            newModules[modules.length] = m;
-            modules = newModules;
-        }
-        else
-        {
-            modules = new IModule[] { m };
-        }
-
-        return modules;
-    }
 */
-    private static IModule[] removeModuleFromArray(IModule[] modules, IModule m)
-    {
-        if (modules == null)
-        {
-            return m_emptyModules;
-        }
-
-        int idx = -1;
-        do
-        {
-            idx = -1;
-            for (int i = 0; i < modules.length; i++)
-            {
-                if (modules[i] == m)
-                {
-                    idx = i;
-                    break;
-                }
-            }
-
-            if (idx >= 0)
-            {
-                // If this is the module, then point to empty list.
-                if ((modules.length - 1) == 0)
-                {
-                    modules = m_emptyModules;
-                }
-                // Otherwise, we need to do some array copying.
-                else
-                {
-                    IModule[] newModules = new IModule[modules.length - 1];
-                    System.arraycopy(modules, 0, newModules, 0, idx);
-                    if (idx < newModules.length)
-                    {
-                        System.arraycopy(
-                            modules, idx + 1, newModules, idx, newModules.length - idx);
-                    }
-                    modules = newModules;
-                }
-            }
-        } while (idx >= 0);
-        return modules;
-    }
-
-    private static PackageSource[] shrinkCandidateArray(PackageSource[] candidates)
-    {
-        if (candidates == null)
-        {
-            return m_emptySources;
-        }
-
-        // Move all non-null values to one end of the array.
-        int lower = 0;
-        for (int i = 0; i < candidates.length; i++)
-        {
-            if (candidates[i] != null)
-            {
-                candidates[lower++] = candidates[i];
-            }
-        }
-
-        if (lower == 0)
-        {
-            return m_emptySources;
-        }
-
-        // Copy non-null values into a new array and return.
-        PackageSource[] newCandidates= new PackageSource[lower];
-        System.arraycopy(candidates, 0, newCandidates, 0, lower);
-        return newCandidates;
-    }
-
-    private static ICapability[] addCapabilityToArray(ICapability[] caps, ICapability cap)
-    {
-        // Verify that the capability is not already in the array.
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
-        {
-            if (caps[i].equals(cap))
-            {
-                return caps;
-            }
-        }
-
-        if (caps != null)
-        {
-            ICapability[] newCaps = new ICapability[caps.length + 1];
-            System.arraycopy(caps, 0, newCaps, 0, caps.length);
-            newCaps[caps.length] = cap;
-            caps = newCaps;
-        }
-        else
-        {
-            caps = new ICapability[] { cap };
-        }
-
-        return caps;
-    }
-
-    //
-    // Simple utility classes.
-    //
-
-    private static class ModuleData
-    {
-        public IModule m_module = null;
-        public boolean m_resolved = false;
-        public ModuleData(IModule module)
-        {
-            m_module = module;
-        }
-    }
-
-    private class CandidateSet
-    {
-        public IModule m_module = null;
-        public IRequirement m_requirement = null;
-        public PackageSource[] m_candidates = null;
-        public int m_idx = 0;
-        public CandidateSet(IModule module, IRequirement requirement, PackageSource[] candidates)
-        {
-            m_module = module;
-            m_requirement = requirement;
-            m_candidates = candidates;
-        }
-    }
-
-    /**
-     * This utility class represents a source for a given package, where
-     * the package is indicated by a particular module and the module's
-     * capability associated with that package. This class also implements
-     * <tt>Comparable</tt> so that two package sources can be compared based
-     * on version and bundle identifiers.
-    **/
-    public class PackageSource implements Comparable
-    {
-        public IModule m_module = null;
-        public ICapability m_capability = null;
-
-        public PackageSource(IModule module, ICapability capability)
-        {
-            m_module = module;
-            m_capability = capability;
-        }
-
-        public int compareTo(Object o)
-        {
-            PackageSource ps = (PackageSource) o;
-
-            Version thisVersion = null;
-            Version version = null;
-            if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-            {
-                thisVersion = ((Capability) m_capability).getPackageVersion();
-                version = ((Capability) ps.m_capability).getPackageVersion();
-            }
-            else if (m_capability.getNamespace().equals(ICapability.MODULE_NAMESPACE))
-            {
-                thisVersion = (Version)
-                    m_capability.getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
-                version = (Version)
-                    ps.m_capability.getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
-            }
-
-            if ((thisVersion != null) && (version != null))
-            {
-                // Sort in reverse version order.
-                int cmp = thisVersion.compareTo(version);
-                if (cmp < 0)
-                {
-                    return 1;
-                }
-                else if (cmp > 0)
-                {
-                    return -1;
-                }
-                else
-                {
-                    // Sort further by ascending bundle ID.
-                    long thisId = Util.getBundleIdFromModuleId(m_module.getId());
-                    long id = Util.getBundleIdFromModuleId(ps.m_module.getId());
-                    if (thisId < id)
-                    {
-                        return -1;
-                    }
-                    else if (thisId > id)
-                    {
-                        return 1;
-                    }
-                    return 0;
-                }
-            }
-            else
-            {
-                return -1;
-            }
-        }
-
-        public int hashCode()
-        {
-            final int PRIME = 31;
-            int result = 1;
-            result = PRIME * result + ((m_capability == null) ? 0 : m_capability.hashCode());
-            result = PRIME * result + ((m_module == null) ? 0 : m_module.hashCode());
-            return result;
-        }
-
-        public boolean equals(Object o)
-        {
-            if (this == o)
-            {
-                return true;
-            }
-            if (o == null)
-            {
-                return false;
-            }
-            if (getClass() != o.getClass())
-            {
-                return false;
-            }
-            PackageSource ps = (PackageSource) o;
-            return (m_module.equals(ps.m_module) && (m_capability == ps.m_capability));
-        }
-    }
-
-    /**
-     * This utility class is a resolved package, which is comprised of a
-     * set of <tt>PackageSource</tt>s that is calculated by the resolver
-     * algorithm. A given resolved package may have a single package source,
-     * as is the case with imported packages, or it may have multiple
-     * package sources, as is the case with required bundles.
-    **/
-    protected class ResolvedPackage
-    {
-        public String m_name = null;
-        public List m_sourceList = new ArrayList();
-
-        public ResolvedPackage(String name)
-        {
-            m_name = name;
-        }
-
-        public boolean isSubset(ResolvedPackage rp)
-        {
-            if (m_sourceList.size() > rp.m_sourceList.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_sourceList.containsAll(m_sourceList);
-        }
-
-        public Object clone()
-        {
-            ResolvedPackage rp = new ResolvedPackage(m_name);
-            rp.m_sourceList.addAll(m_sourceList);
-            return rp;
-        }
-
-        public void merge(ResolvedPackage rp)
-        {
-            // Merge required packages, avoiding duplicate
-            // package sources and maintaining ordering.
-            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
-            {
-                if (!m_sourceList.contains(rp.m_sourceList.get(srcIdx)))
-                {
-                    m_sourceList.add(rp.m_sourceList.get(srcIdx));
-                }
-            }
-        }
-
-        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_sourceList.size(); i++)
-            {
-                PackageSource ps = (PackageSource) m_sourceList.get(i);
-                sb.append(ps.m_module);
-                if ((i + 1) < m_sourceList.size())
-                {
-                    sb.append(", ");
-                }
-            }
-            sb.append("]");
-            return sb;
-        }
-    }
-
     //
     // Diagnostics.
     //
@@ -3372,6 +743,7 @@
         }
 */
         // Next, check to see if the package is dynamically imported by the module.
+/* TODO: RESOLVER: Need to fix this too.
         IRequirement[] dynamics = module.getDefinition().getDynamicRequirements();
         for (int dynIdx = 0; dynIdx < dynamics.length; dynIdx++)
         {
@@ -3436,6 +808,7 @@
                 return sb.toString();
             }
         }
+*/
         IRequirement pkgReq = null;
         try
         {
@@ -3445,8 +818,8 @@
         {
             // This should never happen.
         }
-        PackageSource[] exporters = getResolvedCandidates(pkgReq);
-        exporters = (exporters.length == 0) ? getUnresolvedCandidates(pkgReq) : exporters;
+        PackageSource[] exporters = m_resolver.getResolvedCandidates(pkgReq);
+        exporters = (exporters.length == 0) ? m_resolver.getUnresolvedCandidates(pkgReq) : exporters;
         if (exporters.length > 0)
         {
             boolean classpath = false;
@@ -3548,4 +921,4 @@
 
         return sb.toString();
     }
-}
+}
\ 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/searchpolicy/R4WireModule.java
index b60967f..31c606c 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
@@ -21,8 +21,8 @@
 import java.net.URL;
 import java.util.*;
 
-import org.apache.felix.framework.searchpolicy.R4SearchPolicyCore.ResolvedPackage;
-import org.apache.felix.framework.searchpolicy.R4SearchPolicyCore.PackageSource;
+import org.apache.felix.framework.searchpolicy.PackageSource;
+import org.apache.felix.framework.searchpolicy.ResolvedPackage;
 import org.apache.felix.framework.util.CompoundEnumeration;
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.framework.util.manifestparser.Capability;
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
new file mode 100644
index 0000000..3421198
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolvedPackage.java
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+/**
+ * This utility class is a resolved package, which is comprised of a
+ * set of <tt>PackageSource</tt>s that is calculated by the resolver
+ * algorithm. A given resolved package may have a single package source,
+ * as is the case with imported packages, or it may have multiple
+ * package sources, as is the case with required bundles.
+ */
+class ResolvedPackage
+{
+    public String m_name = null;
+    public List m_sourceList = new ArrayList();
+
+    public ResolvedPackage(String name)
+    {
+        super();
+        m_name = name;
+    }
+
+    public boolean isSubset(ResolvedPackage rp)
+    {
+        if (m_sourceList.size() > rp.m_sourceList.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_sourceList.containsAll(m_sourceList);
+    }
+
+    public Object clone()
+    {
+        ResolvedPackage rp = new ResolvedPackage(m_name);
+        rp.m_sourceList.addAll(m_sourceList);
+        return rp;
+    }
+
+    public void merge(ResolvedPackage rp)
+    {
+        // Merge required packages, avoiding duplicate
+        // package sources and maintaining ordering.
+        for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+        {
+            if (!m_sourceList.contains(rp.m_sourceList.get(srcIdx)))
+            {
+                m_sourceList.add(rp.m_sourceList.get(srcIdx));
+            }
+        }
+    }
+
+    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_sourceList.size(); i++)
+        {
+            PackageSource ps = (PackageSource) m_sourceList.get(i);
+            sb.append(ps.m_module);
+            if ((i + 1) < m_sourceList.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
new file mode 100644
index 0000000..c85efcb
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
@@ -0,0 +1,1552 @@
+/*
+ * 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.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+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.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;
+
+    // Reusable empty array.
+    private static final PackageSource[] m_emptySources = new PackageSource[0];
+
+    public Resolver(Logger logger)
+    {
+        m_logger = logger;
+    }
+
+    // Returns a map of resolved bundles where the key is the module
+    // and the value is an array of wires.
+    // TODO: RESOLVER - The caller must ensure this is not called currently;
+    //       this may not be important if no state is shared.
+    public Result resolve(ResolverState state, IModule rootModule) throws ResolveException
+    {
+        // This map will be used to hold the final wires for all
+        // resolved modules, which can then be used to fire resolved
+        // events outside of the synchronized block.
+        Map fragmentMap = null;
+
+        // If the module is already resolved, then we can just return.
+        if (state.isResolved(rootModule))
+        {
+            return null;
+        }
+
+        // The root module is either a host or a fragment. If it is a host,
+        // then we want to go ahead and resolve it. If it is a fragment, then
+        // we want to select a host and resolve the host instead.
+        IModule targetFragment = null;
+// TODO: FRAGMENT - Currently we just make a single selection of the available
+//       fragments or hosts and try to resolve. In case of failure, we do not
+//       backtrack. We will likely want to add backtracking.
+        if (Util.isFragment(rootModule))
+        {
+            targetFragment = rootModule;
+            List hostList = state.getPotentialHosts(targetFragment);
+            if (hostList.size() == 0)
+            {
+                throw new ResolveException("Unable to find host for fragment.", targetFragment, null);
+            }
+            rootModule = (IModule) hostList.get(0);
+        }
+
+        // Get the available fragments for the host.
+        fragmentMap = state.getPotentialFragments(rootModule);
+
+        // If the resolve was for a specific fragment, then
+        // eliminate all other potential candidate fragments
+        // of the same symbolic name.
+        if (targetFragment != null)
+        {
+            fragmentMap.put(
+                state.getBundleSymbolicName(targetFragment),
+                new IModule[] { targetFragment });
+        }
+
+        // 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.
+        // Get a map of all modules and their resolved wires.
+        Map resolvedModuleWireMap =
+            populateWireMap(state, candidatesMap, rootModule, new HashMap());
+        return new Result(rootModule, fragmentMap, resolvedModuleWireMap);
+    }
+
+    // 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
+    {
+        PackageSource candidate = null;
+        Map resolvedModuleWireMap = null;
+
+        // We can only search dynamic imports if the bundle
+        // doesn't import, export, nor require the package in
+        // question. Check these conditions first.
+        if (isDynamicImportAllowed(importer, pkgName))
+        {
+            // 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.getDefinition().getDynamicRequirements();
+            for (int dynIdx = 0; (dynamics != null) && (dynIdx < dynamics.length); dynIdx++)
+            {
+                IRequirement target =
+                    createDynamicRequirement(dynamics[dynIdx], pkgName);
+                if (target != null)
+                {
+                    // See if there is a candidate exporter that satisfies the
+                    // constrained dynamic requirement.
+                    try
+                    {
+                        // Get "resolved" and "unresolved" candidates and put
+                        // the "resolved" candidates first.
+                        PackageSource[] resolved = state.getResolvedCandidates(target);
+                        PackageSource[] unresolved = state.getUnresolvedCandidates(target);
+                        PackageSource[] candidates = new PackageSource[resolved.length + unresolved.length];
+                        System.arraycopy(resolved, 0, candidates, 0, resolved.length);
+                        System.arraycopy(unresolved, 0, candidates, resolved.length, unresolved.length);
+
+                        // Take the first candidate that can resolve.
+                        for (int candIdx = 0;
+                            (candidate == null) && (candIdx < candidates.length);
+                            candIdx++)
+                        {
+                            try
+                            {
+                                // If a map is returned, then the candidate resolved
+                                // consistently with the importer.
+                                resolvedModuleWireMap =
+                                    resolveDynamicImportCandidate(
+                                        state, candidates[candIdx].m_module, importer);
+                                if (resolvedModuleWireMap != null)
+                                {
+                                    candidate = candidates[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, dynamics[dynIdx], candidate.m_module, candidate.m_capability);
+                            result[1] = resolvedModuleWireMap;
+                            return result;
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        m_logger.log(Logger.LOG_ERROR, "Unable to dynamically import package.", ex);
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private static boolean isDynamicImportAllowed(IModule importer, String pkgName)
+    {
+        // If any of the module exports this package, then we cannot
+        // attempt to dynamically import it.
+        ICapability[] caps = importer.getDefinition().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 false;
+            }
+        }
+        // If any of our wires have this package, then we cannot
+        // attempt to dynamically import it.
+        IWire[] wires = importer.getWires();
+        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        {
+            if (wires[i].hasPackage(pkgName))
+            {
+                return false;
+            }
+        }
+        // Ok to attempt to dynamically import the package.
+        return true;
+    }
+
+    private static IRequirement createDynamicRequirement(IRequirement dynReq, String pkgName)
+    {
+        IRequirement req = null;
+
+        // First check to see if the dynamic requirement matches the
+        // package name; this means we have to do wildcard matching.
+        String dynPkgName = ((Requirement) dynReq).getPackageName();
+        boolean wildcard = (dynPkgName.lastIndexOf(".*") >= 0);
+        dynPkgName = (wildcard)
+            ? dynPkgName.substring(0, dynPkgName.length() - 2) : 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 + ".")))
+        {
+            // 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;
+                }
+            }
+            req = new Requirement(ICapability.PACKAGE_NAMESPACE, dirs, newAttrs);
+        }
+
+        return req;
+    }
+
+    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 (!state.isResolved(provider))
+        {
+            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 package sources are
+                // compatible with the package source 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 package sources 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_sourceList.clear();
+                        rp.m_sourceList.addAll(rpUses.m_sourceList);
+                    }
+                    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 static void populateCandidatesMap(
+        ResolverState state, Map candidatesMap, IModule module)
+        throws ResolveException
+    {
+        // Detect cycles.
+        if (candidatesMap.get(module) != null)
+        {
+            return;
+        }
+
+        // List to hold the resolving candidate sets for the module's
+        // requirements.
+        List candSetList = new ArrayList();
+
+        // Even though the candidate set list is currently empty, we
+        // record it in the candidates map early so we can use it to
+        // detect cycles.
+        candidatesMap.put(module, candSetList);
+
+        // Loop through each requirement and calculate its resolving
+        // set of candidates.
+        IRequirement[] reqs = module.getDefinition().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.
+            PackageSource[] resolved = state.getResolvedCandidates(reqs[reqIdx]);
+            PackageSource[] unresolved = state.getUnresolvedCandidates(reqs[reqIdx]);
+            PackageSource[] candidates = new PackageSource[resolved.length + unresolved.length];
+            System.arraycopy(resolved, 0, candidates, 0, resolved.length);
+            System.arraycopy(unresolved, 0, candidates, resolved.length, unresolved.length);
+
+            // If we have candidates, then we need to recursively populate
+            // the resolver map with each of them.
+            ResolveException rethrow = null;
+            if (candidates.length > 0)
+            {
+                for (int candIdx = 0; candIdx < candidates.length; candIdx++)
+                {
+                    try
+                    {
+                        // Only populate the resolver map with modules that
+                        // are not already resolved.
+                        if (!state.isResolved(candidates[candIdx].m_module))
+                        {
+                            populateCandidatesMap(state, candidatesMap, candidates[candIdx].m_module);
+                        }
+                    }
+                    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.
+                        candidates[candIdx] = null;
+                        rethrow = ex;
+                    }
+                }
+
+                // Remove any nulled candidates to create the final list
+                // of available candidates.
+                candidates = shrinkCandidateArray(candidates);
+            }
+
+            // If no candidates exist at this point, then throw a
+            // resolve exception unless the import is optional.
+            if ((candidates.length == 0) && !reqs[reqIdx].isOptional())
+            {
+                // If we have received an exception while trying to populate
+                // the resolver 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.", module, reqs[reqIdx]);
+                }
+            }
+            else if (candidates.length > 0)
+            {
+                candSetList.add(
+                    new CandidateSet(module, reqs[reqIdx], candidates));
+            }
+        }
+    }
+
+    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(); )
+                {
+                    candidatesList.add(((Map.Entry) iter.next()).getValue());
+                }
+            }
+
+            // Increment the candidate configuration so we can test again.
+            incrementCandidateConfiguration(candidatesList);
+
+            // 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 (state.isResolved(modules[i]) && isSingleton(modules[i]))
+            {
+                String symName = state.getBundleSymbolicName(modules[i]);
+                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 = state.getBundleSymbolicName(targetModule);
+        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 package sources 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
+            // package sources for the given package.
+            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
+            // Loop through each package source and test if it is consistent.
+            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+            {
+                // If the module for this package source is not resolved, then
+                // we have to see if resolving it would violate a singleton
+                // constraint.
+                PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
+                if (!state.isResolved(ps.m_module))
+                {
+                    return areCandidatesSingletonConsistent(state, ps.m_module, 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 package sources.
+        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 package sources 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
+            // package sources for the given package.
+            ResolvedPackage rp = (ResolvedPackage) entry.getValue();
+            // Loop through each package source and test if it is consistent.
+            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+            {
+                PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
+                if (!isClassSpaceConsistent(ps.m_module, 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 package sources are
+                // compatible with the package source 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 package sources 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_sourceList.clear();
+                        rp.m_sourceList.addAll(rpUses.m_sourceList);
+                    }
+                    else
+                    {
+                        m_logger.log(
+                            Logger.LOG_DEBUG,
+                            "Constraint violation for " + targetModule
+                            + " detected; module can see "
+                            + rp + " and " + rpUses);
+                        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 modules, called package sources. The
+        // "uses" constraints implied by all package sources 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 srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+            {
+                usesMap = calculateUsesConstraints(
+                    (PackageSource) rp.m_sourceList.get(srcIdx),
+                    moduleMap, usesMap, cycleMap, candidatesMap);
+            }
+        }
+        return usesMap;
+    }
+
+    private static Map calculateUsesConstraints(
+        PackageSource psTarget, 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(psTarget) != null)
+        {
+            return usesMap;
+        }
+
+        // Record the target package source in the cycle map.
+        cycleMap.put(psTarget, psTarget);
+
+        // Get all packages accessible from the module of the
+        // target package source.
+        Map pkgMap = getModulePackages(moduleMap, psTarget.m_module, candidatesMap);
+
+        // Get capability (i.e., package) of the target package source.
+        Capability cap = (Capability) psTarget.m_capability;
+
+        // Loop through all "used" packages of the capability.
+        for (int i = 0; i < cap.getUses().length; i++)
+        {
+            // The target package source 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 package sources for the resolved
+                // package associated with the current "used" package and calculate
+                // and combine the "uses" constraints for each package source.
+                for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+                {
+                    usesMap = calculateUsesConstraints(
+                        (PackageSource) rp.m_sourceList.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 sources. 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 source to the end of
+        // the require package sources; 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
+                // package sources 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 package source
+        // to the imported package map.
+        for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
+        {
+            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
+            PackageSource ps = cs.m_candidates[cs.m_idx];
+
+            if (ps.m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            {
+                String pkgName = (String)
+                    ps.m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
+
+                ResolvedPackage rp = new ResolvedPackage(pkgName);
+                rp.m_sourceList.add(ps);
+                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 package source 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) : rp;
+                rp.m_sourceList.add(new PackageSource(wires[wireIdx].getExporter(), 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.getDefinition().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) : rp;
+                rp.m_sourceList.add(new PackageSource(targetModule, 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);
+            PackageSource ps = cs.m_candidates[cs.m_idx];
+
+            // If the capabaility is a module dependency, then flatten it to packages.
+            if (ps.m_capability.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            {
+                // Calculate transitively required packages.
+                Map cycleMap = new HashMap();
+                cycleMap.put(targetModule, targetModule);
+                Map requireMap =
+                    calculateExportedAndReexportedPackages(
+                        ps, 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
+                        // package sources 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
+                        // package sources and maintaining ordering.
+                        ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
+                        rp.merge(rpReq);
+                    }
+                    else
+                    {
+                        pkgMap.put(entry.getKey(), entry.getValue());
+                    }
+                }
+            }
+        }
+
+        return pkgMap;
+    }
+
+    private static Map calculateExportedAndReexportedPackages(
+        PackageSource psTarget, Map candidatesMap, Map cycleMap)
+    {
+        return (candidatesMap.get(psTarget.m_module) == null)
+            ? calculateExportedAndReexportedPackagesResolved(psTarget.m_module, cycleMap)
+            : calculateExportedAndReexportedPackagesUnresolved(psTarget, candidatesMap, cycleMap);
+    }
+
+    private static Map calculateExportedAndReexportedPackagesUnresolved(
+        PackageSource psTarget, Map candidatesMap, Map cycleMap)
+    {
+//System.out.println("calculateExportedAndReexportedPackagesUnresolved("+psTarget.m_module+")");
+        Map pkgMap = new HashMap();
+
+        if (cycleMap.get(psTarget.m_module) != null)
+        {
+            return pkgMap;
+        }
+
+        cycleMap.put(psTarget.m_module, psTarget.m_module);
+
+        // Loop through all current candidates for target module's dependencies
+        // and calculate the module's complete set of required packages (and
+        // their associated package sources) and the complete set of required
+        // packages to be re-exported.
+        Map allRequiredMap = new HashMap();
+        Map reexportedPkgMap = new HashMap();
+        List candSetList = (List) candidatesMap.get(psTarget.m_module);
+        for (int candSetIdx = 0; candSetIdx < candSetList.size(); candSetIdx++)
+        {
+            CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
+            PackageSource ps = cs.m_candidates[cs.m_idx];
+
+            // If the candidate is resolving a module dependency, then
+            // flatten the required packages if they are re-exported.
+            if (ps.m_capability.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(ps, 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 package sources will ultimately need to
+                    // be combined with privately required package sources,
+                    // 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 package sources.
+                        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 package sources 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 package source for any exported packages.
+        ICapability[] candCaps = psTarget.m_module.getDefinition().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) : rp;
+                rp.m_sourceList.add(new PackageSource(psTarget.m_module, 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 package 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 package sources will ultimately need to
+                    // be combined with privately required package sources,
+                    // 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 package sources.
+                        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 package sources 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 package source for any exported packages.
+        ICapability[] caps = targetModule.getDefinition().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) : rp;
+                rp.m_sourceList.add(new PackageSource(targetModule, caps[i]));
+                pkgMap.put(rp.m_name, rp);
+            }
+        }
+
+        return pkgMap;
+    }
+
+    private static Map calculateCandidateRequiredPackages(IModule module, PackageSource psTarget, Map candidatesMap)
+    {
+//System.out.println("calculateCandidateRequiredPackages("+module+")");
+        Map cycleMap = new HashMap();
+        cycleMap.put(module, module);
+        return calculateExportedAndReexportedPackages(psTarget, 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.length)
+                {
+                    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 (state.isResolved(importer) || (wireMap.get(importer) != null))
+        {
+            return wireMap;
+        }
+
+        List candSetList = (List) candidatesMap.get(importer);
+        List moduleWires = new ArrayList();
+        List packageWires = new ArrayList();
+        IWire[] wires = new IWire[candSetList.size()];
+
+        // 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, wires);
+
+        // 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 wire for the current candidate based on the type
+            // of requirement it resolves.
+            if (cs.m_requirement.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            {
+                moduleWires.add(new R4WireModule(
+                    importer,
+                    cs.m_requirement,
+                    cs.m_candidates[cs.m_idx].m_module,
+                    cs.m_candidates[cs.m_idx].m_capability,
+                    calculateCandidateRequiredPackages(importer, cs.m_candidates[cs.m_idx], candidatesMap)));
+            }
+            else
+            {
+                // Add wire for imported package.
+                packageWires.add(new R4Wire(
+                    importer,
+                    cs.m_requirement,
+                    cs.m_candidates[cs.m_idx].m_module,
+                    cs.m_candidates[cs.m_idx].m_capability));
+            }
+
+            // Create any necessary wires for the selected candidate module.
+            wireMap = populateWireMap(
+                state, candidatesMap, cs.m_candidates[cs.m_idx].m_module, wireMap);
+        }
+
+        packageWires.addAll(moduleWires);
+        wireMap.put(importer, packageWires.toArray(wires));
+
+        return wireMap;
+    }
+
+    //
+    // Utility methods.
+    //
+
+    private static PackageSource[] shrinkCandidateArray(PackageSource[] candidates)
+    {
+        if (candidates == null)
+        {
+            return m_emptySources;
+        }
+
+        // Move all non-null values to one end of the array.
+        int lower = 0;
+        for (int i = 0; i < candidates.length; i++)
+        {
+            if (candidates[i] != null)
+            {
+                candidates[lower++] = candidates[i];
+            }
+        }
+
+        if (lower == 0)
+        {
+            return m_emptySources;
+        }
+
+        // Copy non-null values into a new array and return.
+        PackageSource[] newCandidates= new PackageSource[lower];
+        System.arraycopy(candidates, 0, newCandidates, 0, lower);
+        return newCandidates;
+    }
+
+    //
+    // Inner classes.
+    //
+
+    public static interface ResolverState
+    {
+        IModule[] getModules();
+        // TODO: RESOLVER - This should be on module.
+        String getBundleSymbolicName(IModule module);
+        // TODO: RESOLVER - This should be on module.
+        boolean isResolved(IModule module);
+        Map getPotentialFragments(IModule module);
+        List getPotentialHosts(IModule module);
+        PackageSource[] getResolvedCandidates(IRequirement req);
+        PackageSource[] getUnresolvedCandidates(IRequirement req);
+    }
+
+    private static class CandidateSet
+    {
+        public IModule m_module = null;
+        public IRequirement m_requirement = null;
+        public PackageSource[] m_candidates = null;
+        public int m_idx = 0;
+        public CandidateSet(IModule module, IRequirement requirement, PackageSource[] candidates)
+        {
+            m_module = module;
+            m_requirement = requirement;
+            m_candidates = candidates;
+        }
+    }
+
+    // TODO: RESOLVER - This is a hack, we need to calcualte fragments differently.
+    public class Result
+    {
+        public final IModule m_host;
+        public final Map m_fragmentMap;
+        public final Map m_resolvedModuleWireMap;
+
+        public Result(IModule host, Map fragmentMap, Map resolvedModuleWireMap)
+        {
+            m_host = host;
+            m_fragmentMap = fragmentMap;
+            m_resolvedModuleWireMap = resolvedModuleWireMap;
+        }
+    }
+}
\ No newline at end of file