Initial pass at support for fragments exporting, importing, and requiring.
(FELIX-29)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@770791 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index 49291a9..5f17330 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -732,6 +732,11 @@
 
     public Class loadClass(String name) throws ClassNotFoundException
     {
+        if (isExtension())
+        {
+            throw new ClassNotFoundException("Extension bundles cannot load classes.");
+        }
+
         Object sm = System.getSecurityManager();
 
         if (sm != null)
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 ccd86de..10c98cf 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2176,7 +2176,14 @@
 
                 ex.printStackTrace();
 
-                throw new BundleException("Could not create bundle object.", ex);
+                if (ex instanceof BundleException)
+                {
+                    throw (BundleException) ex;
+                }
+                else
+                {
+                    throw new BundleException("Could not create bundle object.", ex);
+                }
             }
 
             // If the bundle is new, then set its start level; existing
@@ -3090,7 +3097,9 @@
                 throw new BundleException(
                     "Unresolved constraint in bundle "
                     + Util.getBundleIdFromModuleId(ex.getModule().getId())
-                    + ": " + ex.getRequirement());
+                    + ": "
+                    + ((ex.getRequirement() == null)
+                        ? ex.getMessage() : ex.getRequirement().toString()));
             }
             else
             {
@@ -3448,6 +3457,9 @@
         m_configMutableMap.put(
             FelixConstants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE,
             "true");
+        m_configMutableMap.put(
+            FelixConstants.SUPPORTS_BOOTCLASSPATH_EXTENSION,
+            "false");
 
         String s = null;
         s = R4LibraryClause.normalizeOSName(System.getProperty("os.name"));
@@ -3687,10 +3699,28 @@
 
                     verifyExecutionEnvironment(bundle);
 
-                    Map resolvedModuleWireMap = m_resolver.resolve(m_resolverState, rootModule);
+                    // Before trying to resolve, tell the resolver state to
+                    // merge all fragments into host, which may result in the
+                    // rootModule changing if the real root is a module.
+                    IModule newRootModule;
+                    try
+                    {
+                        newRootModule = m_resolverState.mergeFragments(rootModule);
+                    }
+                    catch (Exception ex)
+                    {
+                        ex.printStackTrace();
+                        throw new ResolveException("Unable to merge fragments", rootModule, null);
+                    }
 
-                    // Mark all modules as resolved.
-                    markResolvedModules(resolvedModuleWireMap);
+                    if (!Util.isFragment(newRootModule))
+                    {
+                        // Resolve the module.
+                        Map resolvedModuleWireMap = m_resolver.resolve(m_resolverState, newRootModule);
+
+                        // Mark all modules as resolved.
+                        markResolvedModules(resolvedModuleWireMap);
+                    }
                 }
                 finally
                 {
@@ -3786,11 +3816,9 @@
                 Iterator iter = resolvedModuleWireMap.entrySet().iterator();
                 // Iterate over the map to mark the modules as resolved and
                 // update our resolver data structures.
-                List fragmentList = new ArrayList();
                 List wireList = new ArrayList();
                 while (iter.hasNext())
                 {
-                    fragmentList.clear();
                     wireList.clear();
 
                     Map.Entry entry = (Map.Entry) iter.next();
@@ -3804,55 +3832,31 @@
                     {
                         for (int wireIdx = 0; wireIdx < wires.length; wireIdx++)
                         {
-                            if (wires[wireIdx] instanceof R4WireFragment)
-                            {
-                                fragmentList.add(wires[wireIdx].getExporter());
-                            }
-                            else
-                            {
-m_logger.log(Logger.LOG_DEBUG, "WIRE: " + wires[wireIdx]);
-                                wireList.add(wires[wireIdx]);
-                            }
+                            wireList.add(wires[wireIdx]);
+                            m_logger.log(
+                                Logger.LOG_DEBUG,
+                                "WIRE: " + wires[wireIdx]);
                         }
                         wires = (IWire[]) wireList.toArray(new IWire[wireList.size()]);
                         ((ModuleImpl) module).setWires(wires);
                     }
 
+                    // Resolve all attached fragments.
+                    IModule[] fragments = ((ModuleImpl) module).getFragments();
+                    for (int i = 0; (fragments != null) && (i < fragments.length); i++)
+                    {
+                        ((ModuleImpl) fragments[i]).setResolved();
+                        // Update the state of the module's bundle to resolved as well.
+                        markBundleResolved(fragments[i]);
+                        m_logger.log(
+                            Logger.LOG_DEBUG,
+                            "FRAGMENT WIRE: " + fragments[i] + " -> hosted by -> " + module);
+                    }
                     // Update the resolver state to show the module as resolved.
                     ((ModuleImpl) module).setResolved();
                     m_resolverState.moduleResolved(module);
                     // Update the state of the module's bundle to resolved as well.
                     markBundleResolved(module);
-
-                    // Attach and mark all fragments as resolved.
-                    attachFragments(module, fragmentList);
-                }
-            }
-        }
-
-        private void attachFragments(IModule host, List fragmentList)
-        {
-            // Attach fragments to host module.
-            if (fragmentList.size() > 0)
-            {
-                for (int i = 0; i < fragmentList.size(); i++)
-                {
-m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: " + host + " -> hosts -> " + fragmentList.get(i));
-
-                    // Update the resolver state to show the module as resolved.
-                    ((ModuleImpl) fragmentList.get(i)).setResolved();
-                    m_resolverState.moduleResolved((IModule) fragmentList.get(i));
-                    // Update the state of the module's bundle to resolved as well.
-                    markBundleResolved((IModule) fragmentList.get(i));
-                }
-                try
-                {
-                    ((ModuleImpl) host).attachFragments(
-                        (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]));
-                }
-                catch (Exception ex)
-                {
-                    m_logger.log(Logger.LOG_ERROR, "Unable to attach fragments", 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
index 46b691e..ffcd219 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -42,6 +42,8 @@
     private final Logger m_logger;
     // List of all modules.
     private final List m_moduleList = new ArrayList();
+    // Map of fragment symbolic names to array of modules sorted version.
+    private final Map m_fragmentMap = new HashMap();
     // 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.
@@ -58,20 +60,210 @@
         m_logger = logger;
     }
 
+    public synchronized IModule mergeFragments(IModule rootModule) throws Exception
+    {
+// TODO: FRAGMENT - This should check to make sure that the host allows fragments.
+        IModule newRootModule = rootModule;
+        for (int hostIdx = 0; hostIdx < m_moduleList.size(); hostIdx++)
+        {
+            IModule host = (IModule) m_moduleList.get(hostIdx);
+            if (!host.isResolved() && !Util.isFragment(host))
+            {
+                ICapability[] caps = host.getCapabilities();
+                ICapability bundleCap = null;
+                for (int capIdx = 0; capIdx < caps.length; capIdx++)
+                {
+                    if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+                    {
+                        bundleCap = caps[capIdx];
+                        break;
+                    }
+                }
+
+                // Need to remove any previously attached, but not resolved fragments.
+                // TODO: FRAGMENT - Would be better to have the previous resolves
+                //       not leave fragments attached.
+                ((ModuleImpl) host).attachFragments(null);
+
+                // Fragments are grouped by symbolic name and descending version.
+                // Attach the first matching fragment from each group if possible,
+                // since only one version of a given fragment may attach to a host.
+                List list = new ArrayList();
+                for (Iterator it = m_fragmentMap.entrySet().iterator(); it.hasNext(); )
+                {
+                    Map.Entry entry = (Map.Entry) it.next();
+                    IModule[] fragments = (IModule[]) entry.getValue();
+                    done: for (int fragIdx = 0; fragIdx < fragments.length; fragIdx++)
+                    {
+                        IRequirement[] reqs = fragments[fragIdx].getRequirements();
+                        for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
+                        {
+                            if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
+                                && reqs[reqIdx].isSatisfied(bundleCap)
+                                && !((BundleImpl) fragments[fragIdx].getBundle()).isStale()
+                                && !((BundleImpl) fragments[fragIdx].getBundle()).isRemovalPending())
+                            {
+                                // Fragments are attached in bundle ID order.
+                                int index = -1;
+                                for (int listIdx = 0;
+                                    (index < 0) && (listIdx < list.size());
+                                    listIdx++)
+                                {
+                                    if (fragments[fragIdx].getBundle().getBundleId()
+                                        < ((IModule) list.get(listIdx)).getBundle().getBundleId())
+                                    {
+                                        index = listIdx;
+                                    }
+                                }
+                                list.add((index < 0) ? list.size() : index, fragments[fragIdx]);
+                                break done;
+                            }
+                        }
+                    }
+                }
+
+                if (list.size() > 0)
+                {
+                    // Verify the fragments do not have conflicting imports.
+                    // For now, just check for duplicate imports, but in the
+                    // future we might want to make this more fine grained.
+                    // First get the host's imported packages.
+                    Map ipMerged = new HashMap();
+                    Map rbMerged = new HashMap();
+                    IRequirement[] reqs = host.getRequirements();
+                    for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
+                    {
+                        if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                        {
+                            ipMerged.put(((Requirement) reqs[reqIdx]).getTargetName(), host);
+                        }
+                        else if (reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+                        {
+                            rbMerged.put(((Requirement) reqs[reqIdx]).getTargetName(), host);
+                        }
+                    }
+                    // Loop through all fragments verifying they do no conflict,
+                    // adding those packages that do not conflict and removing
+                    // the fragment if it does conflict.
+                    for (Iterator it = list.iterator(); it.hasNext(); )
+                    {
+                        IModule fragment = (IModule) it.next();
+                        reqs = fragment.getRequirements();
+                        List ipFragment = new ArrayList();
+                        List rbFragment = new ArrayList();
+                        boolean conflicting = false;
+                        for (int reqIdx = 0;
+                            !conflicting && (reqs != null) && (reqIdx < reqs.length);
+                            reqIdx++)
+                        {
+                            if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
+                                || reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+                            {
+                                String targetName = ((Requirement) reqs[reqIdx]).getTargetName();
+                                Map mergedReqMap = (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                                    ? ipMerged : rbMerged;
+                                List fragmentReqList = (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                                    ? ipFragment : rbFragment;
+                                if (mergedReqMap.get(targetName) == null)
+                                {
+                                    fragmentReqList.add(targetName);
+                                }
+                                else
+                                {
+                                    conflicting = true;
+                                }
+                                if (conflicting)
+                                {
+                                    ipFragment.clear();
+                                    rbFragment.clear();
+                                    it.remove();
+                                    m_logger.log(
+                                        Logger.LOG_DEBUG,
+                                        "Excluding fragment " + fragment.getSymbolicName()
+                                        + " from " + host.getSymbolicName()
+                                        + " due to conflict with "
+                                        + (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
+                                            ? "imported package " : "required bundle ")
+                                        + targetName + " from "
+                                        + ((IModule) mergedReqMap.get(targetName)).getSymbolicName());
+                                }
+                            }
+                        }
+
+                        // Merge non-conflicting requirements into overall set
+                        // of requirements and continue checking for conflicts
+                        // with the next fragment.
+                        for (int pkgIdx = 0; pkgIdx < ipFragment.size(); pkgIdx++)
+                        {
+                            ipMerged.put(ipFragment.get(pkgIdx), fragment);
+                        }
+                        for (int pkgIdx = 0; pkgIdx < rbFragment.size(); pkgIdx++)
+                        {
+                            rbMerged.put(rbFragment.get(pkgIdx), fragment);
+                        }
+                    }
+
+                    // Attach the fragments to the host.
+                    IModule[] fragments = (IModule[]) list.toArray(new IModule[list.size()]);
+                    ((ModuleImpl) host).attachFragments(fragments);
+
+                    for (int fragIdx = 0; fragIdx < fragments.length; fragIdx++)
+                    {
+                        // Check to see if the root module is actually a fragment,
+                        // if so then we want to return the host for resolving.
+                        if (rootModule == fragments[fragIdx])
+                        {
+                            newRootModule = host;
+                        }
+
+                        // Add each fragment capabililty to the resolver state
+                        // data structures.
+                        ICapability[] fragCaps = fragments[fragIdx].getCapabilities();
+                        for (int capIdx = 0; (fragCaps != null) && (capIdx < fragCaps.length); capIdx++)
+                        {
+                            if (fragCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                            {
+                                indexPackageCapability(
+                                    m_unresolvedPkgIndexMap, host, fragCaps[capIdx]);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return newRootModule;
+    }
+
+    private void addFragment(IModule module)
+    {
+        indexFragment(m_fragmentMap, module);
+//        System.out.println("+++ BEGIN FRAGMENT DUMP");
+//        dumpModuleIndexMap(m_fragmentMap);
+//        System.out.println("+++ END FRAGMENT DUMP");
+    }
+
     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.getCapabilities();
-
-        // Add exports to unresolved package map.
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
+        if (Util.isFragment(module))
         {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            addFragment(module);
+        }
+        else
+        {
+            // 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.getCapabilities();
+
+            // Add exports to unresolved package map.
+            for (int i = 0; (caps != null) && (i < caps.length); i++)
             {
-                indexPackageCapability(m_unresolvedPkgIndexMap, module, caps[i]);
+                if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                {
+                    indexPackageCapability(m_unresolvedPkgIndexMap, module, caps[i]);
+                }
             }
         }
 
@@ -83,58 +275,77 @@
 
     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.
+        // Depending on whether the module is a fragment or not,
+        // we need to do different things.
 
-        m_moduleList.remove(module);
-
-        // Remove exports from package maps.
-        ICapability[] caps = module.getCapabilities();
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
+        // If module is a fragment, then remove from fragment map.
+        if (Util.isFragment(module))
         {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            IModule[] fragments = (IModule[]) m_fragmentMap.get(module.getSymbolicName());
+            fragments = removeModuleFromArray(fragments, module);
+            if (fragments.length == 0)
             {
-                // 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);
-                }
+                m_fragmentMap.remove(module.getSymbolicName());
+            }
+            else
+            {
+                m_fragmentMap.put(module.getSymbolicName(), fragments);
             }
         }
+        // If it is not a fragment, then 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 list.
+        else
+        {
+            m_moduleList.remove(module);
 
-        // Set fragments to null, which will remove the module from all
-        // of its dependent fragment modules.
-        try
-        {
-            ((ModuleImpl) module).attachFragments(null);
+            // Remove exports from package maps.
+            ICapability[] caps = module.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);
+                    }
+                }
+            }
+
+            // Remove the module from the "resolved" map.
+            m_resolvedCapMap.remove(module);
+            // 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);
         }
-        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);
+
         // Close the module's content.
         ((ModuleImpl) module).close();
-
-        // Remove the module from the "resolved" map.
-        m_resolvedCapMap.remove(module);
     }
 
     /**
@@ -168,6 +379,26 @@
         }
     }
 
+    private void dumpModuleIndexMap(Map moduleIndexMap)
+    {
+        for (Iterator i = moduleIndexMap.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 dumpPackageIndexMap(Map pkgIndexMap)
     {
         for (Iterator i = pkgIndexMap.entrySet().iterator(); i.hasNext(); )
@@ -303,93 +534,15 @@
 //dumpPackageIndexMap(m_resolvedPkgIndexMap);
     }
 
-    // TODO: FRAGMENT - Not very efficient.
-    public synchronized List getPotentialHosts(IModule fragment)
-    {
-        List hostList = new ArrayList();
-
-        IRequirement[] reqs = fragment.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]) && !modules[modIdx].isResolved())
-            {
-                ICapability[] caps = modules[modIdx].getCapabilities();
-                for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
-                {
-                    if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
-                        && hostReq.isSatisfied(caps[capIdx])
-                        && !((BundleImpl) modules[modIdx].getBundle()).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.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].getRequirements();
-                for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
-                {
-                    if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
-                        && reqs[reqIdx].isSatisfied(bundleCap)
-                        && !((BundleImpl) modules[modIdx].getBundle()).isStale()
-                        && !((BundleImpl) modules[modIdx].getBundle()).isRemovalPending())
-                    {
-                        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))
+            && (((Requirement) req).getTargetName() != null))
         {
-            String pkgName = ((Requirement) req).getPackageName();
+            String pkgName = ((Requirement) req).getTargetName();
             IModule[] modules = (IModule[]) m_resolvedPkgIndexMap.get(pkgName);
 
             for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
@@ -464,9 +617,9 @@
         // Get all modules.
         IModule[] modules = null;
         if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-            (((Requirement) req).getPackageName() != null))
+            (((Requirement) req).getTargetName() != null))
         {
-            modules = (IModule[]) m_unresolvedPkgIndexMap.get(((Requirement) req).getPackageName());
+            modules = (IModule[]) m_unresolvedPkgIndexMap.get(((Requirement) req).getTargetName());
         }
         else
         {
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java
index 2173dfc..5dee8b9 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java
@@ -30,6 +30,7 @@
 import java.security.ProtectionDomain;
 import java.security.SecureClassLoader;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Enumeration;
 
 import java.util.HashMap;
@@ -224,19 +225,71 @@
         return m_version;
     }
 
-    public ICapability[] getCapabilities()
+    public synchronized ICapability[] getCapabilities()
     {
-        return m_capabilities;
+        List capList = (m_capabilities == null)
+            ? new ArrayList() : new ArrayList(Arrays.asList(m_capabilities));
+        for (int fragIdx = 0;
+            (m_fragments != null) && (fragIdx < m_fragments.length);
+            fragIdx++)
+        {
+            ICapability[] caps = m_fragments[fragIdx].getCapabilities();
+            for (int capIdx = 0;
+                (caps != null) && (capIdx < caps.length);
+                capIdx++)
+            {
+                if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                {
+                    capList.add(caps[capIdx]);
+                }
+            }
+        }
+        return (ICapability[]) capList.toArray(new ICapability[capList.size()]);
     }
 
-    public IRequirement[] getRequirements()
+    public synchronized IRequirement[] getRequirements()
     {
-        return m_requirements;
+        List reqList = (m_requirements == null)
+            ? new ArrayList() : new ArrayList(Arrays.asList(m_requirements));
+        for (int fragIdx = 0;
+            (m_fragments != null) && (fragIdx < m_fragments.length);
+            fragIdx++)
+        {
+            IRequirement[] reqs = m_fragments[fragIdx].getRequirements();
+            for (int reqIdx = 0;
+                (reqs != null) && (reqIdx < reqs.length);
+                reqIdx++)
+            {
+                if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
+                    || reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+                {
+                    reqList.add(reqs[reqIdx]);
+                }
+            }
+        }
+        return (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
     }
 
-    public IRequirement[] getDynamicRequirements()
+    public synchronized IRequirement[] getDynamicRequirements()
     {
-        return m_dynamicRequirements;
+        List reqList = (m_dynamicRequirements == null)
+            ? new ArrayList() : new ArrayList(Arrays.asList(m_dynamicRequirements));
+        for (int fragIdx = 0;
+            (m_fragments != null) && (fragIdx < m_fragments.length);
+            fragIdx++)
+        {
+            IRequirement[] reqs = m_fragments[fragIdx].getDynamicRequirements();
+            for (int reqIdx = 0;
+                (reqs != null) && (reqIdx < reqs.length);
+                reqIdx++)
+            {
+                if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                {
+                    reqList.add(reqs[reqIdx]);
+                }
+            }
+        }
+        return (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
     }
 
     public R4Library[] getNativeLibraries()
@@ -334,15 +387,16 @@
     private IContent[] initializeContentPath() throws Exception
     {
         List contentList = new ArrayList();
-        calculateContentPath(m_content, contentList, true);
+        calculateContentPath(this, m_content, contentList, true);
         for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
         {
-            calculateContentPath(m_fragmentContents[i], contentList, false);
+            calculateContentPath(m_fragments[i], m_fragmentContents[i], contentList, false);
         }
         return (IContent[]) contentList.toArray(new IContent[contentList.size()]);
     }
 
-    private List calculateContentPath(IContent content, List contentList, boolean searchFragments)
+    private List calculateContentPath(
+        IModule module, IContent content, List contentList, boolean searchFragments)
         throws Exception
     {
         // Creating the content path entails examining the bundle's
@@ -354,7 +408,7 @@
         List localContentList = new ArrayList();
 
         // Find class path meta-data.
-        String classPath = (String) m_headerMap.get(FelixConstants.BUNDLE_CLASSPATH);
+        String classPath = (String) module.getHeaders().get(FelixConstants.BUNDLE_CLASSPATH);
         // Parse the class path into strings.
         String[] classPathStrings = ManifestParser.parseDelimitedString(
             classPath, FelixConstants.CLASS_PATH_SEPARATOR);
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireFragment.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireFragment.java
deleted file mode 100644
index 929e8af..0000000
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireFragment.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.framework.searchpolicy;
-
-import java.net.URL;
-import java.util.Enumeration;
-
-import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.Capability;
-import org.apache.felix.moduleloader.*;
-
-// TODO: RESOLVER - This is a hack and doesn't really fit with abstraction.
-public class R4WireFragment implements IWire
-{
-    private final IModule m_importer;
-    private final IRequirement m_requirement;
-    private final IModule m_exporter;
-    private final ICapability m_capability;
-
-    public R4WireFragment(IModule host, IModule fragment)
-    {
-        m_importer = host;
-        m_requirement = null;
-        m_exporter = fragment;
-        m_capability = null;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getImporter()
-     */
-    public IModule getImporter()
-    {
-        return m_importer;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getRequirement()
-     */
-    public IRequirement getRequirement()
-    {
-        return m_requirement;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getExporter()
-     */
-    public IModule getExporter()
-    {
-        return m_exporter;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getCapability()
-     */
-    public ICapability getCapability()
-    {
-        return m_capability;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
-     */
-    public boolean hasPackage(String pkgName)
-    {
-        return false;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
-     */
-    public Class getClass(String name) throws ClassNotFoundException
-    {
-        return null;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getResource(java.lang.String)
-     */
-    public URL getResource(String name) throws ResourceNotFoundException
-    {
-        return null;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.felix.framework.searchpolicy.IWire#getResources(java.lang.String)
-     */
-    public Enumeration getResources(String name) throws ResourceNotFoundException
-    {
-        return null;
-    }
-
-    public String toString()
-    {
-        return m_importer + " -> hosts -> " + m_exporter;
-    }
-}
\ No newline at end of file
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
index edd1464..d3a8bb7 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
@@ -216,7 +216,7 @@
 
         // 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();
+        String dynPkgName = ((Requirement) dynReq).getTargetName();
         boolean wildcard = (dynPkgName.lastIndexOf(".*") >= 0);
         // Remove the "*", but keep the "." if wildcarded.
         dynPkgName = (wildcard)
@@ -354,194 +354,82 @@
         // detect cycles.
         candidatesMap.put(targetModule, candSetList);
 
-        // Loop through potential fragments and add each set to the
-        // candidate set; if the targetModule is a fragment then there
-        // will be no potential fragments here.
-        Map fragmentMap = state.getPotentialFragments(targetModule);
-        for (Iterator it = fragmentMap.entrySet().iterator(); it.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) it.next();
-            IModule[] fragments = (IModule[]) entry.getValue();
-
-            // If we have fragment candidates, then we need to recursively populate
-            // the resolver map with each of them.
-            if (fragments.length > 0)
-            {
-                for (int fragIdx = 0; fragIdx < fragments.length; fragIdx++)
-                {
-                    try
-                    {
-                        // We still need to populate the candidates for the
-                        // fragment even if it is resolved, because fragments
-                        // can be attached to multiple hosts and each host
-                        // may end up with different wires for the fragments
-                        // dependencies.
-                        populateCandidatesMap(state, candidatesMap, fragments[fragIdx]);
-                    }
-                    catch (ResolveException ex)
-                    {
-                        // If we received a resolve exception, then the
-                        // current fragment is not resolvable for some
-                        // reason and should be removed from the list of
-                        // fragments. For now, just null it.
-                        fragments[fragIdx] = null;
-                    }
-                }
-
-                // Remove any nulled fragments to create the final list
-                // of potential fragment candidates.
-                fragments = shrinkModuleArray(fragments);
-            }
-
-            // All fragments, by definition, are optional so we if none of the
-            // candidates could be resolved, then just ignore them; otherwise,
-            // add the resolvable fragments to the host's candidate set.
-            if (fragments.length > 0)
-            {
-                candSetList.add(
-                    new CandidateSet(CandidateSet.FRAGMENT, targetModule, null, fragments));
-            }
-        }
-
         // Loop through each requirement and calculate its resolving
         // set of candidates.
         IRequirement[] reqs = targetModule.getRequirements();
         for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
         {
-            if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+            // 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)
             {
-                List hostList = state.getPotentialHosts(targetModule);
-                IModule[] hosts = (IModule[]) hostList.toArray(new IModule[hostList.size()]);
-                // If we have host candidates, then we need to recursively populate
-                // the resolver map with each of them.
-                ResolveException rethrow = null;
-                if (hosts.length > 0)
+                for (int candIdx = 0; candIdx < candidates.length; candIdx++)
                 {
-                    for (int hostIdx = 0; hostIdx < hosts.length; hostIdx++)
+                    try
                     {
-                        try
+                        // Only populate the resolver map with modules that
+                        // are not already resolved.
+                        if (!candidates[candIdx].m_module.isResolved())
                         {
-                            // Only populate the resolver map with hosts that
-                            // are not already resolved.
-                            if (!hosts[hostIdx].isResolved())
-                            {
-                                populateCandidatesMap(state, candidatesMap, hosts[hostIdx]);
-                            }
-                        }
-                        catch (ResolveException ex)
-                        {
-                            // If we received a resolve exception, then the
-                            // current host is not resolvable for some
-                            // reason and should be removed from the list of
-                            // hosts. For now, just null it.
-                            hosts[hostIdx] = null;
-                            rethrow = ex;
+                            populateCandidatesMap(state, candidatesMap, candidates[candIdx].m_module);
                         }
                     }
-
-                    // Remove any nulled hosts to create the final list
-                    // of potential host candidates.
-                    hosts = shrinkModuleArray(hosts);
-                }
-
-                // If no host candidates exist at this point, then throw a
-                // resolve exception since all fragments must have a host.
-                if (hosts.length == 0)
-                {
-                    // If we have received an exception while trying to populate
-                    // the candidates map, rethrow that exception since it might
-                    // be useful. NOTE: This is not necessarily the "only"
-                    // correct exception, since it is possible that multiple
-                    // candidates were not resolvable, but it is better than
-                    // nothing.
-                    if (rethrow != null)
+                    catch (ResolveException ex)
                     {
-                        throw rethrow;
-                    }
-                    else
-                    {
-                        throw new ResolveException(
-                            "Unable to find host for fragment.",
-                            targetModule, reqs[reqIdx]);
+                        // 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;
                     }
                 }
-                candSetList.add(
-                    new CandidateSet(CandidateSet.HOST, targetModule, reqs[reqIdx], hosts));
+
+                // Remove any nulled candidates to create the final list
+                // of available candidates.
+                candidates = shrinkCandidateArray(candidates);
             }
-            else
+
+            // If no candidates exist at this point, then throw a
+            // resolve exception unless the import is optional.
+            if ((candidates.length == 0) && !reqs[reqIdx].isOptional())
             {
-                // 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);
+                // Since the target module cannot resolve, remove its
+                // candidates set list from the candidates map, since
+                // it is invalid.
+                candidatesMap.remove(targetModule);
 
-                // If we have candidates, then we need to recursively populate
-                // the resolver map with each of them.
-                ResolveException rethrow = null;
-                if (candidates.length > 0)
+                // If we have received an exception while trying to populate
+                // the candidates map, rethrow that exception since it might
+                // be useful. NOTE: This is not necessarily the "only"
+                // correct exception, since it is possible that multiple
+                // candidates were not resolvable, but it is better than
+                // nothing.
+                if (rethrow != null)
                 {
-                    for (int candIdx = 0; candIdx < candidates.length; candIdx++)
-                    {
-                        try
-                        {
-                            // Only populate the resolver map with modules that
-                            // are not already resolved.
-                            if (!candidates[candIdx].m_module.isResolved())
-                            {
-                                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);
+                    throw rethrow;
                 }
-
-                // If no candidates exist at this point, then throw a
-                // resolve exception unless the import is optional.
-                if ((candidates.length == 0) && !reqs[reqIdx].isOptional())
+                else
                 {
-                    // Since the target module cannot resolve, remove its
-                    // candidates set list from the candidates map, since
-                    // it is invalid.
-                    candidatesMap.remove(targetModule);
-
-                    // If we have received an exception while trying to populate
-                    // the candidates map, rethrow that exception since it might
-                    // be useful. NOTE: This is not necessarily the "only"
-                    // correct exception, since it is possible that multiple
-                    // candidates were not resolvable, but it is better than
-                    // nothing.
-                    if (rethrow != null)
-                    {
-                        throw rethrow;
-                    }
-                    else
-                    {
-                        throw new ResolveException(
-                            "Unable to resolve.", targetModule, reqs[reqIdx]);
-                    }
+                    throw new ResolveException(
+                        "Unable to resolve.", targetModule, reqs[reqIdx]);
                 }
-                else if (candidates.length > 0)
-                {
-                    candSetList.add(
-                        new CandidateSet(CandidateSet.NORMAL, targetModule, reqs[reqIdx], candidates));
-                }
+            }
+            else if (candidates.length > 0)
+            {
+                candSetList.add(
+                    new CandidateSet(CandidateSet.NORMAL, targetModule, reqs[reqIdx], candidates));
             }
         }
     }
@@ -1121,18 +1009,6 @@
         for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
         {
             CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-// TODO: FRAGMENT - Eventually fragments will import, so the imports of a fragment
-//                  will need to be added to the imports of the host.
-            if (cs.m_type == CandidateSet.FRAGMENT)
-            {
-                continue;
-            }
-            else if (cs.m_type == CandidateSet.HOST)
-            {
-                // We can ignore the host candidates, since they will be
-                // taken care of when resolving the host module.
-                continue;
-            }
             PackageSource ps = cs.m_candidates[cs.m_idx];
 
             if (ps.m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
@@ -1217,18 +1093,6 @@
         for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
         {
             CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-// TODO: FRAGMENT - Eventually fragments will require bundles, so the required
-//                  packages of the fragment will need to be added to the host.
-            if (cs.m_type == CandidateSet.FRAGMENT)
-            {
-                continue;
-            }
-            else if (cs.m_type == CandidateSet.HOST)
-            {
-                // We can ignore the host candidates, since they will be
-                // taken care of when resolving the host module.
-                continue;
-            }
             PackageSource ps = cs.m_candidates[cs.m_idx];
 
             // If the capabaility is a module dependency, then flatten it to packages.
@@ -1345,18 +1209,6 @@
         for (int candSetIdx = 0; candSetIdx < candSetList.size(); candSetIdx++)
         {
             CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
-// TODO: FRAGMENT - Eventually fragments will export, so the exports of the
-//                  fragment will need to be added to the host.
-            if (cs.m_type == CandidateSet.FRAGMENT)
-            {
-                continue;
-            }
-            else if (cs.m_type == CandidateSet.HOST)
-            {
-                // We can ignore the host candidates, since they will be
-                // taken care of when resolving the host module.
-                continue;
-            }
             PackageSource ps = cs.m_candidates[cs.m_idx];
 
             // If the candidate is resolving a module dependency, then
@@ -1620,59 +1472,6 @@
         // Get the candidate set list for the importer.
         List candSetList = (List) candidatesMap.get(importer);
 
-        // Check if the importer is a fragment, if so we actually want
-        // to get the host and add all fragments candidates to it.
-        if (Util.isFragment(importer))
-        {
-            // Get host candidate for the fragment.
-            IModule host = null;
-            for (int csIdx = 0; (host == null) && (csIdx < candSetList.size()); csIdx++)
-            {
-                CandidateSet cs = (CandidateSet) candSetList.get(csIdx);
-                if (cs.m_type == CandidateSet.HOST)
-                {
-                    host = cs.m_modules[cs.m_idx];
-                }
-            }
-            // Instead of creating wires for the fragment, we will create them
-            // for the host.
-            importer = host;
-
-            // Make sure we haven't already seen the host to avoid a cycle.
-            if (wireMap.get(importer) != null)
-            {
-                return wireMap;
-            }
-
-            // Now add the fragments candidates to the host.
-            candSetList = (List) candidatesMap.get(host);
-            for (int csIdx = 0; (host == null) && (csIdx < candSetList.size()); csIdx++)
-            {
-                CandidateSet cs = (CandidateSet) candSetList.get(csIdx);
-                if (cs.m_type == CandidateSet.FRAGMENT)
-                {
-                    // Add the candidate fragment module to the cycle map
-                    // with no wires, since only its host will have wires.
-                    wireMap.put(cs.m_modules[cs.m_idx], new IWire[0]);
-
-                    // Get the candidate fragment and loop through its candidates
-                    // for resolving its dependencies.
-                    List fragmentCandSetList = (List) candidatesMap.get(cs.m_modules[cs.m_idx]);
-                    for (int csFragIdx = 0; csFragIdx < fragmentCandSetList.size(); csFragIdx++)
-                    {
-                        // Add all non-HOST candidates to the host candidate set,
-                        // since the resulting wires will be for the host not
-                        // the fragment.
-                        CandidateSet csFrag = (CandidateSet) fragmentCandSetList.get(csFragIdx);
-                        if (csFrag.m_type != CandidateSet.HOST)
-                        {
-                            candSetList.add(csFrag);
-                        }
-                    }
-                }
-            }
-        }
-
         List moduleWires = new ArrayList();
         List packageWires = new ArrayList();
 
@@ -1687,42 +1486,33 @@
             // 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_type == CandidateSet.FRAGMENT)
+            // Create a module wire for module dependencies.
+            if (cs.m_requirement.getNamespace().equals(ICapability.MODULE_NAMESPACE))
             {
-                moduleWires.add(new R4WireFragment(importer, cs.m_modules[cs.m_idx]));
+                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
+            // Create a package wire for package dependencies.
+            // Filter out the case where a module imports from
+            // itself, since the module should simply load from
+            // its internal class path in this case.
+            else if (importer != cs.m_candidates[cs.m_idx].m_module)
             {
-                // Create a module wire for module dependencies.
-                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)));
-                }
-                // Create a package wire for package dependencies.
-                // Filter out the case where a module imports from
-                // itself, since the module should simply load from
-                // its internal class path in this case.
-                else if (importer != cs.m_candidates[cs.m_idx].m_module)
-                {
-                    // 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));
-                }
+                // 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);
-            }
+            // 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);
@@ -1798,8 +1588,6 @@
     public static interface ResolverState
     {
         IModule[] getModules();
-        Map getPotentialFragments(IModule module);
-        List getPotentialHosts(IModule module);
         PackageSource[] getResolvedCandidates(IRequirement req);
         PackageSource[] getUnresolvedCandidates(IRequirement req);
     }
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
index d8e8e38..b7a336e 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
@@ -183,7 +183,7 @@
         for (int reqIdx = 0; reqIdx < importReqs.length; reqIdx++)
         {
             // Verify that the named package has not already been declared.
-            String pkgName = ((Requirement) importReqs[reqIdx]).getPackageName();
+            String pkgName = ((Requirement) importReqs[reqIdx]).getTargetName();
 
             if (dupeMap.get(pkgName) == null)
             {
@@ -221,7 +221,7 @@
         for (int reqIdx = 0; reqIdx < m_dynamicRequirements.length; reqIdx++)
         {
             // Verify that java.* packages are not imported.
-            String pkgName = ((Requirement) m_dynamicRequirements[reqIdx]).getPackageName();
+            String pkgName = ((Requirement) m_dynamicRequirements[reqIdx]).getTargetName();
             if (pkgName.startsWith("java."))
             {
                 throw new BundleException(
@@ -275,21 +275,19 @@
         String fragmentHost = (String) headerMap.get(Constants.FRAGMENT_HOST);
         if ((fragmentHost != null) && (parseExtensionBundleHeader(fragmentHost) == null))
         {
-            if ((headerMap.get(Constants.IMPORT_PACKAGE) != null)
-                || (headerMap.get(Constants.EXPORT_PACKAGE) != null)
-                || (headerMap.get(Constants.BUNDLE_NATIVECODE) != null))
+            if (headerMap.get(Constants.BUNDLE_NATIVECODE) != null)
             {
                 String s = (String) m_configMap.get(FelixConstants.FRAGMENT_VALIDATION_PROP);
                 s = (s == null) ? FelixConstants.FRAGMENT_VALIDATION_EXCEPTION_VALUE : s;
                 if (s.equalsIgnoreCase(FelixConstants.FRAGMENT_VALIDATION_WARNING_VALUE))
                 {
                     m_logger.log(Logger.LOG_WARNING,
-                        "Fragments with exports, imports, or native code are not currently supported.");
+                        "Fragments with native code are not currently supported.");
                 }
                 else
                 {
                     throw new BundleException(
-                        "Fragments with exports, imports, or native code are not currently supported.");
+                        "Fragments native code are not currently supported.");
                 }
             }
         }
@@ -671,7 +669,7 @@
             if (m_requirements[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
             {
                 map.put(
-                    ((Requirement) m_requirements[i]).getPackageName(),
+                    ((Requirement) m_requirements[i]).getTargetName(),
                     m_requirements[i]);
             }
         }
@@ -714,7 +712,7 @@
             {
                 usesValue = usesValue
                     + ((usesValue.length() > 0) ? "," : "")
-                    + ((Requirement) m_requirements[i]).getPackageName();
+                    + ((Requirement) m_requirements[i]).getTargetName();
             }
         }
         R4Directive uses = new R4Directive(
@@ -1119,6 +1117,7 @@
     }
 
     public static R4Directive parseExtensionBundleHeader(String header)
+        throws BundleException
     {
         Object[][][] clauses = parseStandardHeader(header);
 
@@ -1126,15 +1125,25 @@
 
         if (clauses.length == 1)
         {
-            if (FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses[0][CLAUSE_PATHS_INDEX][0]) ||
-                Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses[0][CLAUSE_PATHS_INDEX][0]))
+            // See if there is the "extension" directive.
+            for (int i = 0;
+                (result == null) && (i < clauses[0][CLAUSE_DIRECTIVES_INDEX].length);
+                i++)
             {
-                if (clauses[0][CLAUSE_DIRECTIVES_INDEX].length == 1)
+                if (Constants.EXTENSION_DIRECTIVE.equals(((R4Directive)
+                    clauses[0][CLAUSE_DIRECTIVES_INDEX][i]).getName()))
                 {
-                    if (Constants.EXTENSION_DIRECTIVE.equals(((R4Directive)
-                        clauses[0][CLAUSE_DIRECTIVES_INDEX][0]).getName()))
+                    // If the extension directive is specified, make sure
+                    // the target is the system bundle.
+                    if (FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses[0][CLAUSE_PATHS_INDEX][0]) ||
+                        Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses[0][CLAUSE_PATHS_INDEX][0]))
                     {
-                        result = (R4Directive) clauses[0][CLAUSE_DIRECTIVES_INDEX][0];
+                        result = (R4Directive) clauses[0][CLAUSE_DIRECTIVES_INDEX][i];
+                    }
+                    else
+                    {
+                        throw new BundleException(
+                            "Only the system bundle can have extension bundles.");
                     }
                 }
             }
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java
index 61d24a4..c8b97e6 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java
@@ -28,18 +28,23 @@
 public class Requirement implements IRequirement
 {
     private final String m_namespace;
-    private R4Directive[] m_directives;
-    private R4Attribute[] m_attributes;
-    private boolean m_isOptional = false;
+    private final R4Directive[] m_directives;
+    private final R4Attribute[] m_attributes;
+    private final boolean m_isOptional;
 
-    private String m_pkgName;
-    private VersionRange m_pkgVersionRange;
-    private Filter m_filter;
+    private final String m_targetName;
+    private final VersionRange m_targetVersionRange;
+    private volatile Filter m_filter;
 
     public Requirement(String namespace, String filterStr) throws InvalidSyntaxException
     {
         m_namespace = namespace;
         m_filter = new FilterImpl(filterStr);
+        m_directives = null;
+        m_attributes = null;
+        m_isOptional = false;
+        m_targetName = null;
+        m_targetVersionRange = null;
     }
 
     public Requirement(String namespace, R4Directive[] directives, R4Attribute[] attributes)
@@ -47,33 +52,59 @@
         m_namespace = namespace;
         m_directives = directives;
         m_attributes = attributes;
+        m_filter = null;
 
         // Find all import directives: resolution.
+        boolean optional = false;
         for (int i = 0; (m_directives != null) && (i < m_directives.length); i++)
         {
             if (m_directives[i].getName().equals(Constants.RESOLUTION_DIRECTIVE))
             {
-                m_isOptional = m_directives[i].getValue().equals(Constants.RESOLUTION_OPTIONAL);
+                optional = m_directives[i].getValue().equals(Constants.RESOLUTION_OPTIONAL);
             }
         }
+        m_isOptional = optional;
 
+        String targetName = null;
+        VersionRange targetVersionRange = VersionRange.infiniteRange;
         for (int i = 0; i < m_attributes.length; i++)
         {
-            if (m_attributes[i].getName().equals(ICapability.PACKAGE_PROPERTY))
+            if (m_namespace.equals(ICapability.MODULE_NAMESPACE))
             {
-                m_pkgName = (String) m_attributes[i].getValue();
+                if (m_attributes[i].getName().equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE))
+                {
+                    targetName = (String) m_attributes[i].getValue();
+                }
+                else if (m_attributes[i].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
+                {
+                    targetVersionRange = (VersionRange) m_attributes[i].getValue();
+                }
             }
-            else if (m_namespace.equals(ICapability.PACKAGE_NAMESPACE) &&
-                     m_attributes[i].getName().equals(ICapability.VERSION_PROPERTY))
+            else if (m_namespace.equals(ICapability.PACKAGE_NAMESPACE))
             {
-                m_pkgVersionRange = (VersionRange) m_attributes[i].getValue();
+                if (m_attributes[i].getName().equals(ICapability.PACKAGE_PROPERTY))
+                {
+                    targetName = (String) m_attributes[i].getValue();
+                }
+                else if (m_attributes[i].getName().equals(ICapability.VERSION_PROPERTY))
+                {
+                    targetVersionRange = (VersionRange) m_attributes[i].getValue();
+                }
+            }
+            else if (m_namespace.equals(ICapability.HOST_NAMESPACE))
+            {
+                if (m_attributes[i].getName().equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE))
+                {
+                    targetName = (String) m_attributes[i].getValue();
+                }
+                else if (m_attributes[i].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
+                {
+                    targetVersionRange = (VersionRange) m_attributes[i].getValue();
+                }
             }
         }
-
-        if (m_pkgVersionRange == null)
-        {
-            m_pkgVersionRange = VersionRange.infiniteRange;
-        }
+        m_targetName = targetName;
+        m_targetVersionRange = targetVersionRange;
     }
 
     public String getNamespace()
@@ -93,14 +124,14 @@
 // TODO: RB - We need to verify that the resolver code does not
 // touch these implementation-specific methods.
 
-    public String getPackageName()
+    public String getTargetName()
     {
-        return m_pkgName;
+        return m_targetName;
     }
 
-    public VersionRange getPackageVersionRange()
+    public VersionRange getTargetVersionRange()
     {
-        return m_pkgVersionRange;
+        return m_targetVersionRange;
     }
 
     public R4Directive[] getDirectives()