Previously fragments were only being attached to hosts when the host was
explicitly resolved; as part of the refactoring of the resolver, fragments
are now attached to hosts no matter how the host is resolved.
(FELIX-851, FELIX-852)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@729091 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 1d17403..8806f10 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -28,7 +28,6 @@
 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.*;
@@ -3789,13 +3788,10 @@
         {
             if (!m_resolverState.isResolved(rootModule))
             {
-                Resolver.Result result = m_resolver.resolve(m_resolverState, rootModule);
+                Map resolvedModuleWireMap = 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);
+                markResolvedModules(resolvedModuleWireMap);
             }
         }
 
@@ -3854,16 +3850,34 @@
             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();
                 IModule module = (IModule) entry.getKey();
                 IWire[] wires = (IWire[]) entry.getValue();
 
                 // Only add wires attribute if some exist; export
                 // only modules may not have wires.
+// TODO: RESOLVER - Seems stupid that we package these up as wires to tear them apart.
                 if (wires.length > 0)
                 {
+                    for (int wireIdx = 0; wireIdx < wires.length; wireIdx++)
+                    {
+                        if (wires[wireIdx] instanceof R4WireFragment)
+                        {
+                            fragmentList.add(wires[wireIdx].getExporter());
+                        }
+                        else
+                        {
+                            wireList.add(wires[wireIdx]);
+                        }
+                    }
+                    wires = (IWire[]) wireList.toArray(new IWire[wireList.size()]);
                     ((ModuleImpl) module).setWires(wires);
 for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
 {
@@ -3875,34 +3889,30 @@
                 m_resolverState.setResolved(module, true);
                 // 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, Map fragmentMap)
+        private void attachFragments(IModule host, List fragmentList)
         {
             // Attach fragments to host module.
-            if ((fragmentMap != null) && (fragmentMap.size() > 0))
+            if (fragmentList.size() > 0)
             {
-                List list = new ArrayList();
-                for (Iterator iter = fragmentMap.entrySet().iterator(); iter.hasNext(); )
+                for (int i = 0; i < fragmentList.size(); i++)
                 {
-                    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]);
+m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: " + host + " -> hosts -> " + fragmentList.get(i));
 
                     // Update the resolver state to show the module as resolved.
-                    m_resolverState.setResolved(fragments[0], true);
+                    m_resolverState.setResolved((IModule) fragmentList.get(i), true);
                     // Update the state of the module's bundle to resolved as well.
-                    markBundleResolved(fragments[0]);
+                    markBundleResolved((IModule) fragmentList.get(i));
                 }
                 try
                 {
                     ((ModuleImpl) host).attachFragments(
-                        (IModule[]) list.toArray(new IModule[list.size()]));
+                        (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]));
                 }
                 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
index c334276..8c0dbe5 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -77,10 +77,10 @@
             }
         }
 
-System.out.println("UNRESOLVED PACKAGES:");
-dumpPackageIndexMap(m_unresolvedPkgIndexMap);
-System.out.println("RESOLVED PACKAGES:");
-dumpPackageIndexMap(m_resolvedPkgIndexMap);
+//System.out.println("UNRESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+//System.out.println("RESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_resolvedPkgIndexMap);
     }
 
     public synchronized void removeModule(IModule module)
@@ -303,10 +303,10 @@
             }
         }
 
-System.out.println("UNRESOLVED PACKAGES:");
-dumpPackageIndexMap(m_unresolvedPkgIndexMap);
-System.out.println("RESOLVED PACKAGES:");
-dumpPackageIndexMap(m_resolvedPkgIndexMap);
+//System.out.println("UNRESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+//System.out.println("RESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_resolvedPkgIndexMap);
     }
 
     // TODO: FRAGMENT - Not very efficient.
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
new file mode 100644
index 0000000..929e8af
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireFragment.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework.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 c85efcb..55930d4 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
@@ -40,6 +40,7 @@
     private final Logger m_logger;
 
     // Reusable empty array.
+    private static final IModule[] m_emptyModules = new IModule[0];
     private static final PackageSource[] m_emptySources = new PackageSource[0];
 
     public Resolver(Logger logger)
@@ -51,50 +52,14 @@
     // 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
+    public Map 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
@@ -135,10 +100,7 @@
         // 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);
+        return populateWireMap(state, candidatesMap, rootModule, new HashMap());
     }
 
     // TODO: RESOLVER - Fix this return type.
@@ -372,95 +334,207 @@
     }
 
     private static void populateCandidatesMap(
-        ResolverState state, Map candidatesMap, IModule module)
+        ResolverState state, Map candidatesMap, IModule targetModule)
         throws ResolveException
     {
         // Detect cycles.
-        if (candidatesMap.get(module) != null)
+        if (candidatesMap.get(targetModule) != null)
         {
             return;
         }
 
-        // List to hold the resolving candidate sets for the module's
-        // requirements.
+        // List to hold the resolving candidate sets for the target
+        // 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);
+        candidatesMap.put(targetModule, 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++)
+        // 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(); )
         {
-            // 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);
+            Map.Entry entry = (Map.Entry) it.next();
+            IModule[] fragments = (IModule[]) entry.getValue();
 
-            // If we have candidates, then we need to recursively populate
+            // If we have fragment candidates, then we need to recursively populate
             // the resolver map with each of them.
-            ResolveException rethrow = null;
-            if (candidates.length > 0)
+            if (fragments.length > 0)
             {
-                for (int candIdx = 0; candIdx < candidates.length; candIdx++)
+                for (int fragIdx = 0; fragIdx < fragments.length; fragIdx++)
                 {
                     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);
-                        }
+                        // 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 candidate is not resolvable for some
+                        // current fragment 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;
+                        // fragments. For now, just null it.
+                        fragments[fragIdx] = null;
                     }
                 }
 
-                // Remove any nulled candidates to create the final list
-                // of available candidates.
-                candidates = shrinkCandidateArray(candidates);
+                // Remove any nulled fragments to create the final list
+                // of potential fragment candidates.
+                fragments = shrinkModuleArray(fragments);
             }
 
-            // 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)
+            // 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(module, reqs[reqIdx], candidates));
+                    new CandidateSet(CandidateSet.FRAGMENT, targetModule, null, fragments));
+            }
+        }
+
+        // Loop through each requirement and calculate its resolving
+        // set of candidates.
+        IRequirement[] reqs = targetModule.getDefinition().getRequirements();
+        for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
+        {
+            if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+            {
+                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 hostIdx = 0; hostIdx < hosts.length; hostIdx++)
+                    {
+                        try
+                        {
+                            // Only populate the resolver map with hosts that
+                            // are not already resolved.
+                            if (!state.isResolved(hosts[hostIdx]))
+                            {
+                                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;
+                        }
+                    }
+
+                    // 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)
+                    {
+                        throw rethrow;
+                    }
+                    else
+                    {
+                        throw new ResolveException(
+                            "Unable to find host for fragment.",
+                            targetModule, reqs[reqIdx]);
+                    }
+                }
+                candSetList.add(
+                    new CandidateSet(CandidateSet.HOST, targetModule, reqs[reqIdx], hosts));
+            }
+            else
+            {
+                // 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 candidates map, rethrow that exception since it might
+                    // be useful. NOTE: This is not necessarily the "only"
+                    // correct exception, since it is possible that multiple
+                    // candidates were not resolvable, but it is better than
+                    // nothing.
+                    if (rethrow != null)
+                    {
+                        throw rethrow;
+                    }
+                    else
+                    {
+                        throw new ResolveException(
+                            "Unable to resolve.", targetModule, reqs[reqIdx]);
+                    }
+                }
+                else if (candidates.length > 0)
+                {
+                    candSetList.add(
+                        new CandidateSet(CandidateSet.NORMAL, targetModule, reqs[reqIdx], candidates));
+                }
             }
         }
     }
@@ -964,6 +1038,18 @@
         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))
@@ -1048,6 +1134,18 @@
         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.
@@ -1164,6 +1262,18 @@
         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
@@ -1424,7 +1534,55 @@
             return wireMap;
         }
 
+        // 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;
+            // 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();
         IWire[] wires = new IWire[candSetList.size()];
@@ -1442,28 +1600,35 @@
 
             // Create a wire for the current candidate based on the type
             // of requirement it resolves.
-            if (cs.m_requirement.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            if (cs.m_type == CandidateSet.FRAGMENT)
             {
-                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)));
+                moduleWires.add(new R4WireFragment(importer, cs.m_modules[cs.m_idx]));
             }
             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));
-            }
+                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);
+                // 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);
@@ -1476,6 +1641,34 @@
     // Utility methods.
     //
 
+    private static IModule[] shrinkModuleArray(IModule[] modules)
+    {
+        if (modules == null)
+        {
+            return m_emptyModules;
+        }
+
+        // Move all non-null values to one end of the array.
+        int lower = 0;
+        for (int i = 0; i < modules.length; i++)
+        {
+            if (modules[i] != null)
+            {
+                modules[lower++] = modules[i];
+            }
+        }
+
+        if (lower == 0)
+        {
+            return m_emptyModules;
+        }
+
+        // Copy non-null values into a new array and return.
+        IModule[] newModules = new IModule[lower];
+        System.arraycopy(modules, 0, newModules, 0, lower);
+        return newModules;
+    }
+
     private static PackageSource[] shrinkCandidateArray(PackageSource[] candidates)
     {
         if (candidates == null)
@@ -1523,30 +1716,33 @@
 
     private static class CandidateSet
     {
-        public IModule m_module = null;
-        public IRequirement m_requirement = null;
-        public PackageSource[] m_candidates = null;
+        public static final int NORMAL = 0;
+        public static final int FRAGMENT = 1;
+        public static final int HOST = 2;
+
+        public final int m_type;
+        public final IModule m_module;
+        public final IRequirement m_requirement;
+        public final PackageSource[] m_candidates;
+        public final IModule[] m_modules;
         public int m_idx = 0;
-        public CandidateSet(IModule module, IRequirement requirement, PackageSource[] candidates)
+
+        public CandidateSet(int type, IModule module, IRequirement requirement, PackageSource[] candidates)
         {
+            m_type = type;
             m_module = module;
             m_requirement = requirement;
             m_candidates = candidates;
+            m_modules = null;
         }
-    }
 
-    // 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)
+        public CandidateSet(int type, IModule module, IRequirement requirement, IModule[] fragments)
         {
-            m_host = host;
-            m_fragmentMap = fragmentMap;
-            m_resolvedModuleWireMap = resolvedModuleWireMap;
+            m_type = type;
+            m_module = module;
+            m_requirement = requirement;
+            m_candidates = null;
+            m_modules = fragments;
         }
     }
 }
\ No newline at end of file