Refactor internal resolver APIs to align with upcoming OSGi resolver spec. (FELIX-3394)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1300618 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index ce063cb..287087e 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -1928,7 +1928,7 @@
                                 {
                                     try
                                     {
-                                        m_revision.getSecureAction()
+                                        BundleRevisionImpl.getSecureAction()
                                             .invokeWeavingHook(wh, wci);
                                     }
                                     catch (Throwable th)
@@ -2531,7 +2531,7 @@
                 BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName);
             BundleRequirementImpl req = new BundleRequirementImpl(
                 revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
-            Set<BundleCapability> exporters = resolver.getCandidates(req, false);
+            List<BundleCapability> exporters = resolver.findProviders(req, false);
 
             BundleRevision provider = null;
             try
@@ -2570,7 +2570,7 @@
             BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName);
         BundleRequirementImpl req = new BundleRequirementImpl(
             revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
-        Set<BundleCapability> exports = resolver.getCandidates(req, false);
+        List<BundleCapability> exports = resolver.findProviders(req, false);
         if (exports.size() > 0)
         {
             boolean classpath = false;
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 46a1162..dc1e144 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -3564,7 +3564,7 @@
             BundleRevision.PACKAGE_NAMESPACE,
             Collections.EMPTY_MAP,
             attrs);
-        Set<BundleCapability> exports = m_resolver.getCandidates(req, false);
+        List<BundleCapability> exports = m_resolver.findProviders(req, false);
 
         // We only want resolved capabilities.
         for (Iterator<BundleCapability> it = exports.iterator(); it.hasNext(); )
diff --git a/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java b/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java
new file mode 100644
index 0000000..c3a136f
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.apache.felix.framework.resolver.CandidateComparator;
+import org.apache.felix.framework.resolver.HostedCapability;
+import org.apache.felix.framework.resolver.ResolveContext;
+import org.apache.felix.framework.resolver.ResolveException;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWiring;
+
+/**
+ *
+ * @author rickhall
+ */
+public class ResolveContextImpl extends ResolveContext
+{
+    private final StatefulResolver m_state;
+    private final Map<BundleRevision, BundleWiring> m_wirings;
+    private final Collection<BundleRevision> m_mandatory;
+    private final Collection<BundleRevision> m_optional;
+    private final Collection<BundleRevision> m_ondemand;
+
+    ResolveContextImpl(
+        StatefulResolver state, Map<BundleRevision, BundleWiring> wirings,
+        Collection<BundleRevision> mandatory, Collection<BundleRevision> optional,
+        Collection<BundleRevision> ondemand)
+    {
+        m_state = state;
+        m_wirings = wirings;
+        m_mandatory = mandatory;
+        m_optional = optional;
+        m_ondemand = ondemand;
+    }
+
+    @Override
+    public Collection<BundleRevision> getMandatoryRevisions()
+    {
+        return new ArrayList<BundleRevision>(m_mandatory);
+    }
+
+    @Override
+    public Collection<BundleRevision> getOptionalRevisions()
+    {
+        return new ArrayList<BundleRevision>(m_optional);
+    }
+
+    public Collection<BundleRevision> getOndemandRevisions()
+    {
+        return new ArrayList<BundleRevision>(m_ondemand);
+    }
+
+    public List<BundleCapability> findProviders(BundleRequirement br, boolean obeyMandatory)
+    {
+        return m_state.findProviders(br, obeyMandatory);
+    }
+
+    public int insertHostedCapability(List<BundleCapability> caps, HostedCapability hc)
+    {
+        int idx = Collections.binarySearch(caps, hc, new CandidateComparator());
+        if (idx < 0)
+        {
+            idx = Math.abs(idx + 1);
+        }
+        caps.add(idx, hc);
+        return idx;
+    }
+
+    public boolean isEffective(BundleRequirement br)
+    {
+        return m_state.isEffective(br);
+    }
+
+    public Map<BundleRevision, BundleWiring> getWirings()
+    {
+        return m_wirings;
+    }
+
+    public void checkExecutionEnvironment(BundleRevision rev) throws ResolveException
+    {
+        m_state.checkExecutionEnvironment(rev);
+    }
+
+    public void checkNativeLibraries(BundleRevision rev) throws ResolveException
+    {
+        m_state.checkNativeLibraries(rev);
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
index c099f15..376ffcb 100644
--- a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
@@ -28,9 +28,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.SortedSet;
 import java.util.StringTokenizer;
-import java.util.TreeSet;
 import org.apache.felix.framework.capabilityset.CapabilitySet;
 import org.apache.felix.framework.capabilityset.SimpleFilter;
 import org.apache.felix.framework.resolver.CandidateComparator;
@@ -64,33 +62,265 @@
     private final Logger m_logger;
     private final Felix m_felix;
     private final Resolver m_resolver;
-    private final ResolverStateImpl m_resolverState;
     private final List<ResolverHook> m_hooks = new ArrayList<ResolverHook>();
     private boolean m_isResolving = false;
     private Collection<BundleRevision> m_whitelist = null;
 
+    // Set of all revisions.
+    private final Set<BundleRevision> m_revisions;
+    // Set of all fragments.
+    private final Set<BundleRevision> m_fragments;
+    // Capability sets.
+    private final Map<String, CapabilitySet> m_capSets;
+    // Maps singleton symbolic names to list of bundle revisions sorted by version.
+    private final Map<String, List<BundleRevision>> m_singletons;
+    // Selected singleton bundle revisions.
+    private final Set<BundleRevision> m_selectedSingletons;
+    // Execution environment.
+    private final String m_fwkExecEnvStr;
+    // Parsed framework environments
+    private final Set<String> m_fwkExecEnvSet;
+
     StatefulResolver(Felix felix)
     {
         m_felix = felix;
         m_logger = m_felix.getLogger();
         m_resolver = new ResolverImpl(m_logger);
-        m_resolverState = new ResolverStateImpl(
-            (String) m_felix.getConfig().get(Constants.FRAMEWORK_EXECUTIONENVIRONMENT));
+
+        m_revisions = new HashSet<BundleRevision>();
+        m_fragments = new HashSet<BundleRevision>();
+        m_capSets = new HashMap<String, CapabilitySet>();
+        m_singletons = new HashMap<String, List<BundleRevision>>();
+        m_selectedSingletons = new HashSet<BundleRevision>();
+
+        String fwkExecEnvStr =
+            (String) m_felix.getConfig().get(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
+        m_fwkExecEnvStr = (fwkExecEnvStr != null) ? fwkExecEnvStr.trim() : null;
+        m_fwkExecEnvSet = parseExecutionEnvironments(fwkExecEnvStr);
+
+        List<String> indices = new ArrayList<String>();
+        indices.add(BundleRevision.BUNDLE_NAMESPACE);
+        m_capSets.put(BundleRevision.BUNDLE_NAMESPACE, new CapabilitySet(indices, true));
+
+        indices = new ArrayList<String>();
+        indices.add(BundleRevision.PACKAGE_NAMESPACE);
+        m_capSets.put(BundleRevision.PACKAGE_NAMESPACE, new CapabilitySet(indices, true));
+
+        indices = new ArrayList<String>();
+        indices.add(BundleRevision.HOST_NAMESPACE);
+        m_capSets.put(BundleRevision.HOST_NAMESPACE,  new CapabilitySet(indices, true));
     }
 
-    void addRevision(BundleRevision br)
+    synchronized void addRevision(BundleRevision br)
     {
-        m_resolverState.addRevision(br);
+        // Always attempt to remove the revision, since
+        // this method can be used for re-indexing a revision
+        // after it has been resolved.
+        removeRevision(br);
+
+        m_revisions.add(br);
+
+        // Add singletons to the singleton map.
+        boolean isSingleton = Util.isSingleton(br);
+        if (isSingleton)
+        {
+            // Index the new singleton.
+            addToSingletonMap(m_singletons, br);
+        }
+
+        // We always need to index non-singleton bundle capabilities, but
+        // singleton bundles only need to be index if they are resolved.
+        // Unresolved singleton capabilities are only indexed before a
+        // resolve operation when singleton selection is performed.
+        if (!isSingleton || (br.getWiring() != null))
+        {
+            if (Util.isFragment(br))
+            {
+                m_fragments.add(br);
+            }
+            indexCapabilities(br);
+        }
     }
 
-    void removeRevision(BundleRevision br)
+    synchronized void removeRevision(BundleRevision br)
     {
-        m_resolverState.removeRevision(br);
+        if (m_revisions.remove(br))
+        {
+            m_fragments.remove(br);
+            deindexCapabilities(br);
+
+            // If this module is a singleton, then remove it from the
+            // singleton map.
+            List<BundleRevision> revisions = m_singletons.get(br.getSymbolicName());
+            if (revisions != null)
+            {
+                revisions.remove(br);
+                if (revisions.isEmpty())
+                {
+                    m_singletons.remove(br.getSymbolicName());
+                }
+            }
+        }
     }
 
-    Set<BundleCapability> getCandidates(BundleRequirementImpl req, boolean obeyMandatory)
+    boolean isEffective(BundleRequirement req)
     {
-        return m_resolverState.getCandidates(req, obeyMandatory);
+        String effective = req.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE);
+        return ((effective == null) || effective.equals(Constants.EFFECTIVE_RESOLVE));
+    }
+
+    synchronized List<BundleCapability> findProviders(
+        BundleRequirement req, boolean obeyMandatory)
+    {
+        BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
+        List<BundleCapability> result = new ArrayList<BundleCapability>();
+
+        CapabilitySet capSet = m_capSets.get(req.getNamespace());
+        if (capSet != null)
+        {
+            // Get the requirement's filter; if this is our own impl we
+            // have a shortcut to get the already parsed filter, otherwise
+            // we must parse it from the directive.
+            SimpleFilter sf = null;
+            if (req instanceof BundleRequirementImpl)
+            {
+                sf = ((BundleRequirementImpl) req).getFilter();
+            }
+            else
+            {
+                String filter = req.getDirectives().get(Constants.FILTER_DIRECTIVE);
+                if (filter == null)
+                {
+                    sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+                }
+                else
+                {
+                    sf = SimpleFilter.parse(filter);
+                }
+            }
+
+            // Find the matching candidates.
+            Set<BundleCapability> matches = capSet.match(sf, obeyMandatory);
+            // Filter matching candidates.
+            for (BundleCapability cap : matches)
+            {
+                // Filter according to security.
+                if (filteredBySecurity(req, cap))
+                {
+                    continue;
+                }
+                // Filter already resolved hosts, since we don't support
+                // dynamic attachment of fragments.
+                if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE)
+                    && (cap.getRevision().getWiring() != null))
+                {
+                    continue;
+                }
+
+                result.add(cap);
+            }
+        }
+
+        // If we have resolver hooks, then we may need to filter our results
+        // based on a whitelist and/or fine-grained candidate filtering.
+        if (!result.isEmpty() && !m_hooks.isEmpty())
+        {
+            // It we have a whitelist, then first filter out candidates
+            // from disallowed revisions.
+            if (m_whitelist != null)
+            {
+                for (Iterator<BundleCapability> it = result.iterator(); it.hasNext(); )
+                {
+                    if (!m_whitelist.contains(it.next().getRevision()))
+                    {
+                        it.remove();
+                    }
+                }
+            }
+
+            // Now give the hooks a chance to do fine-grained filtering.
+            ShrinkableCollection<BundleCapability> shrinkable =
+                new ShrinkableCollection<BundleCapability>(result);
+            for (ResolverHook hook : m_hooks)
+            {
+                try
+                {
+                    Felix.m_secureAction
+                        .invokeResolverHookMatches(hook, req, shrinkable);
+                }
+                catch (Throwable th)
+                {
+                    m_logger.log(Logger.LOG_WARNING, "Resolver hook exception.", th);
+                }
+            }
+        }
+
+        Collections.sort(result, new CandidateComparator());
+
+        return result;
+    }
+
+    private boolean filteredBySecurity(BundleRequirement req, BundleCapability cap)
+    {
+        if (System.getSecurityManager() != null)
+        {
+            BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
+
+            if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
+            {
+                if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+                    new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
+                    PackagePermission.EXPORTONLY)) ||
+                    !((reqRevision == null) ||
+                        ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+                            new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
+                            cap.getRevision().getBundle(),PackagePermission.IMPORT))
+                    ))
+                {
+                    if (reqRevision != cap.getRevision())
+                    {
+                        return true;
+                    }
+                }
+            }
+            else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
+            {   if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+                    new BundlePermission(cap.getRevision().getSymbolicName(), BundlePermission.PROVIDE)) ||
+                    !((reqRevision == null) ||
+                        ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+                            new BundlePermission(reqRevision.getSymbolicName(), BundlePermission.REQUIRE))
+                    ))
+                {
+                    return true;
+                }
+            }
+            else if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
+            {
+                if (!((BundleProtectionDomain) reqRevision.getProtectionDomain())
+                    .impliesDirect(new BundlePermission(
+                        reqRevision.getSymbolicName(),
+                        BundlePermission.FRAGMENT))
+                || !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain())
+                    .impliesDirect(new BundlePermission(
+                        cap.getRevision().getSymbolicName(),
+                        BundlePermission.HOST)))
+                {
+                    return true;
+                }
+            }
+            else  if (!req.getNamespace().equals("osgi.ee"))
+            {
+                if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+                    new CapabilityPermission(req.getNamespace(), CapabilityPermission.PROVIDE))
+                    ||
+                    !((reqRevision == null) || ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+                    new CapabilityPermission(req.getNamespace(), cap.getAttributes(), cap.getRevision().getBundle(), CapabilityPermission.REQUIRE))))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     void resolve(
@@ -129,7 +359,7 @@
                 prepareResolverHooks(mandatory, optional);
 
             // Select any singletons in the resolver state.
-            m_resolverState.selectSingletons();
+            selectSingletons();
 
             // Extensions are resolved differently.
             for (Iterator<BundleRevision> it = mandatory.iterator(); it.hasNext(); )
@@ -140,7 +370,7 @@
                 {
                     it.remove();
                 }
-                else if (Util.isSingleton(br) && !m_resolverState.isSelectedSingleton(br))
+                else if (Util.isSingleton(br) && !isSelectedSingleton(br))
                 {
                     throw new ResolveException("Singleton conflict.", br, null);
                 }
@@ -153,7 +383,7 @@
                 {
                     it.remove();
                 }
-                else if (Util.isSingleton(br) && !m_resolverState.isSelectedSingleton(br))
+                else if (Util.isSingleton(br) && !isSelectedSingleton(br))
                 {
                     it.remove();
                 }
@@ -166,10 +396,12 @@
             {
                 // Resolve the revision.
                 wireMap = m_resolver.resolve(
-                    m_resolverState,
-                    mandatory,
-                    optional,
-                    m_resolverState.getFragments());
+                    new ResolveContextImpl(
+                        this,
+                        getWirings(),
+                        mandatory,
+                        optional,
+                        getFragments()));
             }
             catch (ResolveException ex)
             {
@@ -249,7 +481,7 @@
                             Collections.singleton(revision), Collections.EMPTY_SET);
 
                     // Select any singletons in the resolver state.
-                    m_resolverState.selectSingletons();
+                    selectSingletons();
 
                     // Catch any resolve exception to rethrow later because
                     // we may need to call end() on resolver hooks.
@@ -257,8 +489,13 @@
                     try
                     {
                         wireMap = m_resolver.resolve(
-                            m_resolverState, revision, pkgName,
-                            m_resolverState.getFragments());
+                            new ResolveContextImpl(
+                                this,
+                                getWirings(),
+                                Collections.EMPTY_LIST,
+                                Collections.EMPTY_LIST,
+                                getFragments()),
+                            revision, pkgName);
                     }
                     catch (ResolveException ex)
                     {
@@ -373,9 +610,7 @@
             }
 
             // Ask hooks to indicate which revisions should not be resolved.
-            m_whitelist =
-                new ShrinkableCollection<BundleRevision>(
-                    m_resolverState.getUnresolvedRevisions());
+            m_whitelist = new ShrinkableCollection<BundleRevision>(getUnresolvedRevisions());
             int originalSize = m_whitelist.size();
             for (ResolverHook hook : m_hooks)
             {
@@ -518,7 +753,7 @@
             BundleRevision.PACKAGE_NAMESPACE,
             Collections.EMPTY_MAP,
             attrs);
-        Set<BundleCapability> candidates = m_resolverState.getCandidates(req, false);
+        List<BundleCapability> candidates = findProviders(req, false);
 
         return !candidates.isEmpty();
     }
@@ -713,7 +948,7 @@
                 // Reindex the revision's capabilities since its resolved
                 // capabilities could be different than its declared ones
                 // (e.g., due to substitutable exports).
-                m_resolverState.addRevision(revision);
+                addRevision(revision);
 
                 // Update the state of the revision's bundle to resolved as well.
                 markBundleResolved(revision);
@@ -855,635 +1090,378 @@
         return pkgs;
     }
 
-    class ResolverStateImpl implements Resolver.ResolverState
+    private synchronized void indexCapabilities(BundleRevision br)
     {
-        // Set of all revisions.
-        private final Set<BundleRevision> m_revisions;
-        // Set of all fragments.
-        private final Set<BundleRevision> m_fragments;
-        // Capability sets.
-        private final Map<String, CapabilitySet> m_capSets;
-        // Maps singleton symbolic names to list of bundle revisions sorted by version.
-        private final Map<String, List<BundleRevision>> m_singletons;
-        // Selected singleton bundle revisions.
-        private final Set<BundleRevision> m_selectedSingletons;
-        // Execution environment.
-        private final String m_fwkExecEnvStr;
-        // Parsed framework environments
-        private final Set<String> m_fwkExecEnvSet;
-
-//    void dump()
-//    {
-//        for (Entry<String, CapabilitySet> entry : m_capSets.entrySet())
-//        {
-//            System.out.println("+++ START CAPSET " + entry.getKey());
-//            entry.getValue().dump();
-//            System.out.println("+++ END CAPSET " + entry.getKey());
-//        }
-//    }
-
-        ResolverStateImpl(String fwkExecEnvStr)
+        List<BundleCapability> caps =
+            (Util.isFragment(br) || (br.getWiring() == null))
+                ? br.getDeclaredCapabilities(null)
+                : br.getWiring().getCapabilities(null);
+        if (caps != null)
         {
-            m_revisions = new HashSet<BundleRevision>();
-            m_fragments = new HashSet<BundleRevision>();
-            m_capSets = new HashMap<String, CapabilitySet>();
-            m_singletons = new HashMap<String, List<BundleRevision>>();
-            m_selectedSingletons = new HashSet<BundleRevision>();
-
-            m_fwkExecEnvStr = (fwkExecEnvStr != null) ? fwkExecEnvStr.trim() : null;
-            m_fwkExecEnvSet = parseExecutionEnvironments(fwkExecEnvStr);
-
-            List<String> indices = new ArrayList<String>();
-            indices.add(BundleRevision.BUNDLE_NAMESPACE);
-            m_capSets.put(BundleRevision.BUNDLE_NAMESPACE, new CapabilitySet(indices, true));
-
-            indices = new ArrayList<String>();
-            indices.add(BundleRevision.PACKAGE_NAMESPACE);
-            m_capSets.put(BundleRevision.PACKAGE_NAMESPACE, new CapabilitySet(indices, true));
-
-            indices = new ArrayList<String>();
-            indices.add(BundleRevision.HOST_NAMESPACE);
-            m_capSets.put(BundleRevision.HOST_NAMESPACE,  new CapabilitySet(indices, true));
-        }
-
-        synchronized Set<BundleRevision> getUnresolvedRevisions()
-        {
-            Set<BundleRevision> unresolved = new HashSet<BundleRevision>();
-            for (BundleRevision revision : m_revisions)
+            for (BundleCapability cap : caps)
             {
-                if (revision.getWiring() == null)
-                {
-                    unresolved.add(revision);
-                }
-            }
-            return unresolved;
-        }
-
-        synchronized void addRevision(BundleRevision br)
-        {
-            // Always attempt to remove the revision, since
-            // this method can be used for re-indexing a revision
-            // after it has been resolved.
-            removeRevision(br);
-
-            m_revisions.add(br);
-
-            // Add singletons to the singleton map.
-            boolean isSingleton = Util.isSingleton(br);
-            if (isSingleton)
-            {
-                // Index the new singleton.
-                addToSingletonMap(m_singletons, br);
-            }
-
-            // We always need to index non-singleton bundle capabilities, but
-            // singleton bundles only need to be index if they are resolved.
-            // Unresolved singleton capabilities are only indexed before a
-            // resolve operation when singleton selection is performed.
-            if (!isSingleton || (br.getWiring() != null))
-            {
-                if (Util.isFragment(br))
-                {
-                    m_fragments.add(br);
-                }
-                indexCapabilities(br);
-            }
-        }
-
-        private synchronized void indexCapabilities(BundleRevision br)
-        {
-            List<BundleCapability> caps =
-                (Util.isFragment(br) || (br.getWiring() == null))
-                    ? br.getDeclaredCapabilities(null)
-                    : br.getWiring().getCapabilities(null);
-            if (caps != null)
-            {
-                for (BundleCapability cap : caps)
-                {
-                    // If the capability is from a different revision, then
-                    // don't index it since it is a capability from a fragment.
-                    // In that case, the fragment capability is still indexed.
-                    // It will be the resolver's responsibility to find all
-                    // attached hosts for fragments.
-                    if (cap.getRevision() == br)
-                    {
-                        CapabilitySet capSet = m_capSets.get(cap.getNamespace());
-                        if (capSet == null)
-                        {
-                            capSet = new CapabilitySet(null, true);
-                            m_capSets.put(cap.getNamespace(), capSet);
-                        }
-                        capSet.addCapability(cap);
-                    }
-                }
-            }
-        }
-
-        private synchronized void deindexCapabilities(BundleRevision br)
-        {
-            // We only need be concerned with declared capabilities here,
-            // because resolved capabilities will be a subset, since fragment
-            // capabilities are not considered to be part of the host.
-            List<BundleCapability> caps = br.getDeclaredCapabilities(null);
-            if (caps != null)
-            {
-                for (BundleCapability cap : caps)
+                // If the capability is from a different revision, then
+                // don't index it since it is a capability from a fragment.
+                // In that case, the fragment capability is still indexed.
+                // It will be the resolver's responsibility to find all
+                // attached hosts for fragments.
+                if (cap.getRevision() == br)
                 {
                     CapabilitySet capSet = m_capSets.get(cap.getNamespace());
-                    if (capSet != null)
+                    if (capSet == null)
                     {
-                        capSet.removeCapability(cap);
+                        capSet = new CapabilitySet(null, true);
+                        m_capSets.put(cap.getNamespace(), capSet);
                     }
-                }
-            }
-        }
-
-        synchronized void removeRevision(BundleRevision br)
-        {
-            if (m_revisions.remove(br))
-            {
-                m_fragments.remove(br);
-                deindexCapabilities(br);
-
-                // If this module is a singleton, then remove it from the
-                // singleton map.
-                List<BundleRevision> revisions = m_singletons.get(br.getSymbolicName());
-                if (revisions != null)
-                {
-                    revisions.remove(br);
-                    if (revisions.isEmpty())
-                    {
-                        m_singletons.remove(br.getSymbolicName());
-                    }
-                }
-            }
-        }
-
-        synchronized Set<BundleRevision> getFragments()
-        {
-            Set<BundleRevision> fragments = new HashSet(m_fragments);
-            // Filter out any fragments that are not the current revision.
-            for (Iterator<BundleRevision> it = fragments.iterator(); it.hasNext(); )
-            {
-                BundleRevision fragment = it.next();
-                BundleRevision currentFragmentRevision =
-                    fragment.getBundle().adapt(BundleRevision.class);
-                if (fragment != currentFragmentRevision)
-                {
-                    it.remove();
-                }
-            }
-            return fragments;
-        }
-
-        synchronized boolean isSelectedSingleton(BundleRevision br)
-        {
-            return m_selectedSingletons.contains(br);
-        }
-
-        synchronized void selectSingletons()
-            throws BundleException
-        {
-            // First deindex any unresolved singletons to make sure
-            // there aren't any available from previous resolves.
-            // Also remove them from the fragment list, for the same
-            // reason.
-            m_selectedSingletons.clear();
-            for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
-            {
-                for (BundleRevision singleton : entry.getValue())
-                {
-                    if (singleton.getWiring() == null)
-                    {
-                        deindexCapabilities(singleton);
-                        m_fragments.remove(singleton);
-                    }
-                }
-            }
-
-            // If no resolver hooks, then use default singleton selection
-            // algorithm, otherwise defer to the resolver hooks.
-            if (m_hooks.isEmpty())
-            {
-                selectDefaultSingletons();
-            }
-            else
-            {
-                selectSingletonsUsingHooks();
-            }
-        }
-
-        /*
-         * Selects the singleton with the highest version from groupings
-         * based on the symbolic name. No selection is made if the group
-         * already has a resolved singleton.
-         */
-        private void selectDefaultSingletons()
-        {
-            // Now select the singletons available for this resolve operation.
-            for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
-            {
-                selectSingleton(entry.getValue());
-            }
-        }
-
-        /*
-         * Groups singletons based on resolver hook filtering and then selects
-         * the singleton from each group with the highest version that is in
-         * the resolver hook whitelist. No selection is made if a group already
-         * has a resolved singleton in it.
-         */
-        private void selectSingletonsUsingHooks()
-            throws BundleException
-        {
-            // Convert singleton bundle revision map into a map using
-            // bundle capabilities instead, since this is what the resolver
-            // hooks require.
-            Map<BundleCapability, Collection<BundleCapability>> allCollisions
-                = new HashMap<BundleCapability, Collection<BundleCapability>>();
-            for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
-            {
-                Collection<BundleCapability> bundleCaps =
-                    new ArrayList<BundleCapability>();
-                for (BundleRevision br : entry.getValue())
-                {
-                    List<BundleCapability> caps =
-                        br.getDeclaredCapabilities(BundleRevision.BUNDLE_NAMESPACE);
-                    if (!caps.isEmpty())
-                    {
-                        bundleCaps.add(caps.get(0));
-                    }
-                }
-
-                for (BundleCapability bc : bundleCaps)
-                {
-                    Collection<BundleCapability> capCopy =
-                        new ShrinkableCollection<BundleCapability>(
-                            new ArrayList<BundleCapability>(bundleCaps));
-                    capCopy.remove(bc);
-                    allCollisions.put(bc, capCopy);
-                }
-            }
-
-            // Invoke hooks to allow them to filter singleton collisions.
-            for (ResolverHook hook : m_hooks)
-            {
-                for (Entry<BundleCapability, Collection<BundleCapability>> entry
-                    : allCollisions.entrySet())
-                {
-                    try
-                    {
-                        Felix.m_secureAction
-                            .invokeResolverHookSingleton(hook, entry.getKey(), entry.getValue());
-                    }
-                    catch (Throwable ex)
-                    {
-                        throw new BundleException(
-                            "Resolver hook exception: " + ex.getMessage(),
-                            BundleException.REJECTED_BY_HOOK,
-                            ex);
-                    }
-                }
-            }
-
-            // Create groups according to how the resolver hooks filtered the
-            // collisions.
-            List<List<BundleRevision>> groups = new ArrayList<List<BundleRevision>>();
-            while (!allCollisions.isEmpty())
-            {
-                BundleCapability target = allCollisions.entrySet().iterator().next().getKey();
-                groups.add(groupSingletons(allCollisions, target, new ArrayList<BundleRevision>()));
-            }
-
-            // Now select the singletons available for this resolve operation.
-            for (List<BundleRevision> group : groups)
-            {
-                selectSingleton(group);
-            }
-        }
-
-        private List<BundleRevision> groupSingletons(
-            Map<BundleCapability, Collection<BundleCapability>> allCollisions,
-            BundleCapability target, List<BundleRevision> group)
-        {
-            if (!group.contains(target.getRevision()))
-            {
-                // Add the target since it is implicitly part of the group.
-                group.add(target.getRevision());
-
-                // Recursively add the revisions of any singleton's in the
-                // target's collisions.
-                Collection<BundleCapability> collisions = allCollisions.remove(target);
-                for (BundleCapability collision : collisions)
-                {
-                    groupSingletons(allCollisions, collision, group);
-                }
-
-                // Need to check the values of other collisions for this target
-                // and add those to the target's group too, since collisions are
-                // treated as two-way relationships. Repeat until there are no
-                // collision groups left that contain the target capability.
-                boolean repeat;
-                do
-                {
-                    repeat = false;
-                    for (Entry<BundleCapability, Collection<BundleCapability>> entry:
-                        allCollisions.entrySet())
-                    {
-                        if (entry.getValue().contains(target))
-                        {
-                            repeat = true;
-                            groupSingletons(allCollisions, entry.getKey(), group);
-                            break;
-                        }
-                    }
-                }
-                while (repeat);
-            }
-            return group;
-        }
-
-        /*
-         * Selects the highest bundle revision from the group that is
-         * in the resolver hook whitelist (if there are hooks). No
-         * selection is made if there is an already resolved singleton
-         * in the group, since it is already indexed.
-         */
-        private void selectSingleton(List<BundleRevision> singletons)
-        {
-            BundleRevision selected = null;
-            for (BundleRevision singleton : singletons)
-            {
-                // If a singleton is already resolved,
-                // then there is nothing to do.
-                if (singleton.getWiring() != null)
-                {
-                    selected = null;
-                    break;
-                }
-                // If this singleton is not in the whitelist, then it cannot
-                // be selected. If it is, in can only be selected if it has
-                // a higher version than the currently selected singleton, if
-                // there is one.
-                if (((m_whitelist == null) || m_whitelist.contains(singleton))
-                    && ((selected == null)
-                        || (selected.getVersion().compareTo(singleton.getVersion()) > 0)))
-                {
-                    selected = singleton;
-                }
-            }
-            if (selected != null)
-            {
-                // Record the selected singleton.
-                m_selectedSingletons.add(selected);
-                // Index its capabilities.
-                indexCapabilities(selected);
-                // If the selected singleton is a fragment, then
-                // add it to the list of fragments.
-                if (Util.isFragment(selected))
-                {
-                    m_fragments.add(selected);
-                }
-            }
-        }
-
-        //
-        // ResolverState methods.
-        //
-
-        public boolean isEffective(BundleRequirement req)
-        {
-            String effective = req.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE);
-            return ((effective == null) || effective.equals(Constants.EFFECTIVE_RESOLVE));
-        }
-
-        public synchronized SortedSet<BundleCapability> getCandidates(
-            BundleRequirement req, boolean obeyMandatory)
-        {
-            BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
-            SortedSet<BundleCapability> result =
-                new TreeSet<BundleCapability>(new CandidateComparator());
-
-            CapabilitySet capSet = m_capSets.get(req.getNamespace());
-            if (capSet != null)
-            {
-                // Get the requirement's filter; if this is our own impl we
-                // have a shortcut to get the already parsed filter, otherwise
-                // we must parse it from the directive.
-                SimpleFilter sf = null;
-                if (req instanceof BundleRequirementImpl)
-                {
-                    sf = ((BundleRequirementImpl) req).getFilter();
-                }
-                else
-                {
-                    String filter = req.getDirectives().get(Constants.FILTER_DIRECTIVE);
-                    if (filter == null)
-                    {
-                        sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
-                    }
-                    else
-                    {
-                        sf = SimpleFilter.parse(filter);
-                    }
-                }
-
-                // Find the matching candidates.
-                Set<BundleCapability> matches = capSet.match(sf, obeyMandatory);
-                // Filter matching candidates.
-                for (BundleCapability cap : matches)
-                {
-                    // Filter according to security.
-                    if (filteredBySecurity(req, cap))
-                    {
-                        continue;
-                    }
-                    // Filter already resolved hosts, since we don't support
-                    // dynamic attachment of fragments.
-                    if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE)
-                        && (cap.getRevision().getWiring() != null))
-                    {
-                        continue;
-                    }
-
-                    result.add(cap);
-                }
-            }
-
-            // If we have resolver hooks, then we may need to filter our results
-            // based on a whitelist and/or fine-grained candidate filtering.
-            if (!result.isEmpty() && !m_hooks.isEmpty())
-            {
-                // It we have a whitelist, then first filter out candidates
-                // from disallowed revisions.
-                if (m_whitelist != null)
-                {
-                    for (Iterator<BundleCapability> it = result.iterator(); it.hasNext(); )
-                    {
-                        if (!m_whitelist.contains(it.next().getRevision()))
-                        {
-                            it.remove();
-                        }
-                    }
-                }
-
-                // Now give the hooks a chance to do fine-grained filtering.
-                ShrinkableCollection<BundleCapability> shrinkable =
-                    new ShrinkableCollection<BundleCapability>(result);
-                for (ResolverHook hook : m_hooks)
-                {
-                    try
-                    {
-                        Felix.m_secureAction
-                            .invokeResolverHookMatches(hook, req, shrinkable);
-                    }
-                    catch (Throwable th)
-                    {
-                        m_logger.log(Logger.LOG_WARNING, "Resolver hook exception.", th);
-                    }
-                }
-            }
-
-            return result;
-        }
-
-        private boolean filteredBySecurity(BundleRequirement req, BundleCapability cap)
-        {
-            if (System.getSecurityManager() != null)
-            {
-                BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
-
-                if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
-                {
-                    if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
-                        new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
-                        PackagePermission.EXPORTONLY)) ||
-                        !((reqRevision == null) ||
-                            ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
-                                new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
-                                cap.getRevision().getBundle(),PackagePermission.IMPORT))
-                        ))
-                    {
-                        if (reqRevision != cap.getRevision())
-                        {
-                            return true;
-                        }
-                    }
-                }
-                else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
-                {   if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
-                        new BundlePermission(cap.getRevision().getSymbolicName(), BundlePermission.PROVIDE)) ||
-                        !((reqRevision == null) ||
-                            ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
-                                new BundlePermission(reqRevision.getSymbolicName(), BundlePermission.REQUIRE))
-                        ))
-                    {
-                        return true;
-                    }
-                }
-                else if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
-                {
-                    if (!((BundleProtectionDomain) reqRevision.getProtectionDomain())
-                        .impliesDirect(new BundlePermission(
-                            reqRevision.getSymbolicName(),
-                            BundlePermission.FRAGMENT))
-                    || !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain())
-                        .impliesDirect(new BundlePermission(
-                            cap.getRevision().getSymbolicName(),
-                            BundlePermission.HOST)))
-                    {
-                        return true;
-                    }
-                }
-                else  if (!req.getNamespace().equals("osgi.ee"))
-                {
-                    if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
-                        new CapabilityPermission(req.getNamespace(), CapabilityPermission.PROVIDE))
-                        ||
-                        !((reqRevision == null) || ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
-                        new CapabilityPermission(req.getNamespace(), cap.getAttributes(), cap.getRevision().getBundle(), CapabilityPermission.REQUIRE))))
-                    {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-
-        public void checkExecutionEnvironment(BundleRevision revision) throws ResolveException
-        {
-            String bundleExecEnvStr = (String)
-                ((BundleRevisionImpl) revision).getHeaders().get(
-                    Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
-            if (bundleExecEnvStr != null)
-            {
-                bundleExecEnvStr = bundleExecEnvStr.trim();
-
-                // If the bundle has specified an execution environment and the
-                // framework has an execution environment specified, then we must
-                // check for a match.
-                if (!bundleExecEnvStr.equals("")
-                    && (m_fwkExecEnvStr != null)
-                    && (m_fwkExecEnvStr.length() > 0))
-                {
-                    StringTokenizer tokens = new StringTokenizer(bundleExecEnvStr, ",");
-                    boolean found = false;
-                    while (tokens.hasMoreTokens() && !found)
-                    {
-                        if (m_fwkExecEnvSet.contains(tokens.nextToken().trim()))
-                        {
-                            found = true;
-                        }
-                    }
-                    if (!found)
-                    {
-                        throw new ResolveException(
-                            "Execution environment not supported: "
-                            + bundleExecEnvStr, revision, null);
-                    }
-                }
-            }
-        }
-
-        public void checkNativeLibraries(BundleRevision revision) throws ResolveException
-        {
-            // Next, try to resolve any native code, since the revision is
-            // not resolvable if its native code cannot be loaded.
-            List<R4Library> libs = ((BundleRevisionImpl) revision).getDeclaredNativeLibraries();
-            if (libs != null)
-            {
-                String msg = null;
-                // Verify that all native libraries exist in advance; this will
-                // throw an exception if the native library does not exist.
-                for (int libIdx = 0; (msg == null) && (libIdx < libs.size()); libIdx++)
-                {
-                    String entryName = libs.get(libIdx).getEntryName();
-                    if (entryName != null)
-                    {
-                        if (!((BundleRevisionImpl) revision).getContent().hasEntry(entryName))
-                        {
-                            msg = "Native library does not exist: " + entryName;
-                        }
-                    }
-                }
-                // If we have a zero-length native library array, then
-                // this means no native library class could be selected
-                // so we should fail to resolve.
-                if (libs.isEmpty())
-                {
-                    msg = "No matching native libraries found.";
-                }
-                if (msg != null)
-                {
-                    throw new ResolveException(msg, revision, null);
+                    capSet.addCapability(cap);
                 }
             }
         }
     }
 
-    //
-    // Utility methods.
-    //
+    private synchronized void deindexCapabilities(BundleRevision br)
+    {
+        // We only need be concerned with declared capabilities here,
+        // because resolved capabilities will be a subset, since fragment
+        // capabilities are not considered to be part of the host.
+        List<BundleCapability> caps = br.getDeclaredCapabilities(null);
+        if (caps != null)
+        {
+            for (BundleCapability cap : caps)
+            {
+                CapabilitySet capSet = m_capSets.get(cap.getNamespace());
+                if (capSet != null)
+                {
+                    capSet.removeCapability(cap);
+                }
+            }
+        }
+    }
+
+    private synchronized boolean isSelectedSingleton(BundleRevision br)
+    {
+        return m_selectedSingletons.contains(br);
+    }
+
+    private synchronized void selectSingletons()
+        throws BundleException
+    {
+        // First deindex any unresolved singletons to make sure
+        // there aren't any available from previous resolves.
+        // Also remove them from the fragment list, for the same
+        // reason.
+        m_selectedSingletons.clear();
+        for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
+        {
+            for (BundleRevision singleton : entry.getValue())
+            {
+                if (singleton.getWiring() == null)
+                {
+                    deindexCapabilities(singleton);
+                    m_fragments.remove(singleton);
+                }
+            }
+        }
+
+        // If no resolver hooks, then use default singleton selection
+        // algorithm, otherwise defer to the resolver hooks.
+        if (m_hooks.isEmpty())
+        {
+            selectDefaultSingletons();
+        }
+        else
+        {
+            selectSingletonsUsingHooks();
+        }
+    }
+
+    /*
+     * Selects the singleton with the highest version from groupings
+     * based on the symbolic name. No selection is made if the group
+     * already has a resolved singleton.
+     */
+    private void selectDefaultSingletons()
+    {
+        // Now select the singletons available for this resolve operation.
+        for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
+        {
+            selectSingleton(entry.getValue());
+        }
+    }
+
+    /*
+     * Groups singletons based on resolver hook filtering and then selects
+     * the singleton from each group with the highest version that is in
+     * the resolver hook whitelist. No selection is made if a group already
+     * has a resolved singleton in it.
+     */
+    private void selectSingletonsUsingHooks()
+        throws BundleException
+    {
+        // Convert singleton bundle revision map into a map using
+        // bundle capabilities instead, since this is what the resolver
+        // hooks require.
+        Map<BundleCapability, Collection<BundleCapability>> allCollisions
+            = new HashMap<BundleCapability, Collection<BundleCapability>>();
+        for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
+        {
+            Collection<BundleCapability> bundleCaps =
+                new ArrayList<BundleCapability>();
+            for (BundleRevision br : entry.getValue())
+            {
+                List<BundleCapability> caps =
+                    br.getDeclaredCapabilities(BundleRevision.BUNDLE_NAMESPACE);
+                if (!caps.isEmpty())
+                {
+                    bundleCaps.add(caps.get(0));
+                }
+            }
+
+            for (BundleCapability bc : bundleCaps)
+            {
+                Collection<BundleCapability> capCopy =
+                    new ShrinkableCollection<BundleCapability>(
+                        new ArrayList<BundleCapability>(bundleCaps));
+                capCopy.remove(bc);
+                allCollisions.put(bc, capCopy);
+            }
+        }
+
+        // Invoke hooks to allow them to filter singleton collisions.
+        for (ResolverHook hook : m_hooks)
+        {
+            for (Entry<BundleCapability, Collection<BundleCapability>> entry
+                : allCollisions.entrySet())
+            {
+                try
+                {
+                    Felix.m_secureAction
+                        .invokeResolverHookSingleton(hook, entry.getKey(), entry.getValue());
+                }
+                catch (Throwable ex)
+                {
+                    throw new BundleException(
+                        "Resolver hook exception: " + ex.getMessage(),
+                        BundleException.REJECTED_BY_HOOK,
+                        ex);
+                }
+            }
+        }
+
+        // Create groups according to how the resolver hooks filtered the
+        // collisions.
+        List<List<BundleRevision>> groups = new ArrayList<List<BundleRevision>>();
+        while (!allCollisions.isEmpty())
+        {
+            BundleCapability target = allCollisions.entrySet().iterator().next().getKey();
+            groups.add(groupSingletons(allCollisions, target, new ArrayList<BundleRevision>()));
+        }
+
+        // Now select the singletons available for this resolve operation.
+        for (List<BundleRevision> group : groups)
+        {
+            selectSingleton(group);
+        }
+    }
+
+    private List<BundleRevision> groupSingletons(
+        Map<BundleCapability, Collection<BundleCapability>> allCollisions,
+        BundleCapability target, List<BundleRevision> group)
+    {
+        if (!group.contains(target.getRevision()))
+        {
+            // Add the target since it is implicitly part of the group.
+            group.add(target.getRevision());
+
+            // Recursively add the revisions of any singleton's in the
+            // target's collisions.
+            Collection<BundleCapability> collisions = allCollisions.remove(target);
+            for (BundleCapability collision : collisions)
+            {
+                groupSingletons(allCollisions, collision, group);
+            }
+
+            // Need to check the values of other collisions for this target
+            // and add those to the target's group too, since collisions are
+            // treated as two-way relationships. Repeat until there are no
+            // collision groups left that contain the target capability.
+            boolean repeat;
+            do
+            {
+                repeat = false;
+                for (Entry<BundleCapability, Collection<BundleCapability>> entry:
+                    allCollisions.entrySet())
+                {
+                    if (entry.getValue().contains(target))
+                    {
+                        repeat = true;
+                        groupSingletons(allCollisions, entry.getKey(), group);
+                        break;
+                    }
+                }
+            }
+            while (repeat);
+        }
+        return group;
+    }
+
+    /*
+     * Selects the highest bundle revision from the group that is
+     * in the resolver hook whitelist (if there are hooks). No
+     * selection is made if there is an already resolved singleton
+     * in the group, since it is already indexed.
+     */
+    private void selectSingleton(List<BundleRevision> singletons)
+    {
+        BundleRevision selected = null;
+        for (BundleRevision singleton : singletons)
+        {
+            // If a singleton is already resolved,
+            // then there is nothing to do.
+            if (singleton.getWiring() != null)
+            {
+                selected = null;
+                break;
+            }
+            // If this singleton is not in the whitelist, then it cannot
+            // be selected. If it is, in can only be selected if it has
+            // a higher version than the currently selected singleton, if
+            // there is one.
+            if (((m_whitelist == null) || m_whitelist.contains(singleton))
+                && ((selected == null)
+                    || (selected.getVersion().compareTo(singleton.getVersion()) > 0)))
+            {
+                selected = singleton;
+            }
+        }
+        if (selected != null)
+        {
+            // Record the selected singleton.
+            m_selectedSingletons.add(selected);
+            // Index its capabilities.
+            indexCapabilities(selected);
+            // If the selected singleton is a fragment, then
+            // add it to the list of fragments.
+            if (Util.isFragment(selected))
+            {
+                m_fragments.add(selected);
+            }
+        }
+    }
+
+    private synchronized Set<BundleRevision> getFragments()
+    {
+        Set<BundleRevision> fragments = new HashSet(m_fragments);
+        // Filter out any fragments that are not the current revision.
+        for (Iterator<BundleRevision> it = fragments.iterator(); it.hasNext(); )
+        {
+            BundleRevision fragment = it.next();
+            BundleRevision currentFragmentRevision =
+                fragment.getBundle().adapt(BundleRevision.class);
+            if (fragment != currentFragmentRevision)
+            {
+                it.remove();
+            }
+        }
+        return fragments;
+    }
+
+    void checkExecutionEnvironment(BundleRevision revision) throws ResolveException
+    {
+        String bundleExecEnvStr = (String)
+            ((BundleRevisionImpl) revision).getHeaders().get(
+                Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
+        if (bundleExecEnvStr != null)
+        {
+            bundleExecEnvStr = bundleExecEnvStr.trim();
+
+            // If the bundle has specified an execution environment and the
+            // framework has an execution environment specified, then we must
+            // check for a match.
+            if (!bundleExecEnvStr.equals("")
+                && (m_fwkExecEnvStr != null)
+                && (m_fwkExecEnvStr.length() > 0))
+            {
+                StringTokenizer tokens = new StringTokenizer(bundleExecEnvStr, ",");
+                boolean found = false;
+                while (tokens.hasMoreTokens() && !found)
+                {
+                    if (m_fwkExecEnvSet.contains(tokens.nextToken().trim()))
+                    {
+                        found = true;
+                    }
+                }
+                if (!found)
+                {
+                    throw new ResolveException(
+                        "Execution environment not supported: "
+                        + bundleExecEnvStr, revision, null);
+                }
+            }
+        }
+    }
+
+    void checkNativeLibraries(BundleRevision revision) throws ResolveException
+    {
+        // Next, try to resolve any native code, since the revision is
+        // not resolvable if its native code cannot be loaded.
+        List<R4Library> libs = ((BundleRevisionImpl) revision).getDeclaredNativeLibraries();
+        if (libs != null)
+        {
+            String msg = null;
+            // Verify that all native libraries exist in advance; this will
+            // throw an exception if the native library does not exist.
+            for (int libIdx = 0; (msg == null) && (libIdx < libs.size()); libIdx++)
+            {
+                String entryName = libs.get(libIdx).getEntryName();
+                if (entryName != null)
+                {
+                    if (!((BundleRevisionImpl) revision).getContent().hasEntry(entryName))
+                    {
+                        msg = "Native library does not exist: " + entryName;
+                    }
+                }
+            }
+            // If we have a zero-length native library array, then
+            // this means no native library class could be selected
+            // so we should fail to resolve.
+            if (libs.isEmpty())
+            {
+                msg = "No matching native libraries found.";
+            }
+            if (msg != null)
+            {
+                throw new ResolveException(msg, revision, null);
+            }
+        }
+    }
+
+    private synchronized Set<BundleRevision> getUnresolvedRevisions()
+    {
+        Set<BundleRevision> unresolved = new HashSet<BundleRevision>();
+        for (BundleRevision revision : m_revisions)
+        {
+            if (revision.getWiring() == null)
+            {
+                unresolved.add(revision);
+            }
+        }
+        return unresolved;
+    }
+
+    private synchronized Map<BundleRevision, BundleWiring> getWirings()
+    {
+        Map<BundleRevision, BundleWiring> wirings = new HashMap<BundleRevision, BundleWiring>();
+
+        for (BundleRevision revision : m_revisions)
+        {
+            if (revision.getWiring() != null)
+            {
+                wirings.put(revision, revision.getWiring());
+            }
+        }
+        return wirings;
+    }
 
     /**
      * Updates the framework wide execution environment string and a cached Set of
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java b/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
index d244685..1d8722a 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
@@ -27,11 +27,8 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.SortedSet;
 import java.util.TreeMap;
-import java.util.TreeSet;
-import org.apache.felix.framework.BundleRevisionImpl;
-import org.apache.felix.framework.resolver.Resolver.ResolverState;
+import org.apache.felix.framework.ResolveContextImpl;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.framework.wiring.BundleCapabilityImpl;
@@ -50,15 +47,14 @@
     public static final int OPTIONAL = 1;
     public static final int ON_DEMAND = 2;
 
-    // Set of all mandatory bundle revisions.
     private final Set<BundleRevision> m_mandatoryRevisions;
     // Maps a capability to requirements that match it.
     private final Map<BundleCapability, Set<BundleRequirement>> m_dependentMap;
     // Maps a requirement to the capability it matches.
-    private final Map<BundleRequirement, SortedSet<BundleCapability>> m_candidateMap;
+    private final Map<BundleRequirement, List<BundleCapability>> m_candidateMap;
     // Maps a bundle revision to its associated wrapped revision; this only happens
     // when a revision being resolved has fragments to attach to it.
-    private final Map<BundleRevision, HostBundleRevision> m_allWrappedHosts;
+    private final Map<BundleRevision, WrappedRevision> m_allWrappedHosts;
     // Map used when populating candidates to hold intermediate and final results.
     private final Map<BundleRevision, Object> m_populateResultCache;
 
@@ -75,8 +71,8 @@
     private Candidates(
         Set<BundleRevision> mandatoryRevisions,
         Map<BundleCapability, Set<BundleRequirement>> dependentMap,
-        Map<BundleRequirement, SortedSet<BundleCapability>> candidateMap,
-        Map<BundleRevision, HostBundleRevision> wrappedHosts, Map<BundleRevision, Object> populateResultCache,
+        Map<BundleRequirement, List<BundleCapability>> candidateMap,
+        Map<BundleRevision, WrappedRevision> wrappedHosts, Map<BundleRevision, Object> populateResultCache,
         boolean fragmentsPresent)
     {
         m_mandatoryRevisions = mandatoryRevisions;
@@ -94,8 +90,8 @@
     {
         m_mandatoryRevisions = new HashSet<BundleRevision>();
         m_dependentMap = new HashMap<BundleCapability, Set<BundleRequirement>>();
-        m_candidateMap = new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
-        m_allWrappedHosts = new HashMap<BundleRevision, HostBundleRevision>();
+        m_candidateMap = new HashMap<BundleRequirement, List<BundleCapability>>();
+        m_allWrappedHosts = new HashMap<BundleRevision, WrappedRevision>();
         m_populateResultCache = new HashMap<BundleRevision, Object>();
     }
 
@@ -116,7 +112,7 @@
      * @param resolution indicates the resolution type.
      */
     public final void populate(
-        ResolverState state, BundleRevision revision, int resolution)
+        ResolveContext rc, BundleRevision revision, int resolution)
     {
         // Get the current result cache value, to make sure the revision
         // hasn't already been populated.
@@ -146,7 +142,7 @@
         // However, for on-demand fragments only populate if their host
         // is already populated.
         if ((resolution != ON_DEMAND)
-            || (isFragment && populateFragmentOndemand(state, revision)))
+            || (isFragment && populateFragmentOndemand(rc, revision)))
         {
             if (resolution == MANDATORY)
             {
@@ -155,7 +151,7 @@
             try
             {
                 // Try to populate candidates for the optional revision.
-                populateRevision(state, revision);
+                populateRevision(rc, revision);
             }
             catch (ResolveException ex)
             {
@@ -174,7 +170,7 @@
      * @param revision the revision whose candidates should be populated.
      */
 // TODO: FELIX3 - Modify to not be recursive.
-    private void populateRevision(ResolverState state, BundleRevision revision)
+    private void populateRevision(ResolveContext rc, BundleRevision revision)
     {
         // Determine if we've already calculated this revision's candidates.
         // The result cache will have one of three values:
@@ -196,7 +192,7 @@
 
         // Keeps track of the candidates we've already calculated for the
         // current revision's requirements.
-        Map<BundleRequirement, SortedSet<BundleCapability>> localCandidateMap = null;
+        Map<BundleRequirement, List<BundleCapability>> localCandidateMap = null;
 
         // Keeps track of the current revision's requirements for which we
         // haven't yet found candidates.
@@ -234,10 +230,10 @@
         if ((remainingReqs == null) && (localCandidateMap == null))
         {
             // Verify that any required execution environment is satisfied.
-            state.checkExecutionEnvironment(revision);
+            ((ResolveContextImpl) rc).checkExecutionEnvironment(revision);
 
             // Verify that any native libraries match the current platform.
-            state.checkNativeLibraries(revision);
+            ((ResolveContextImpl) rc).checkNativeLibraries(revision);
 
             // Record cycle count.
             cycleCount = new Integer(0);
@@ -263,7 +259,7 @@
 
             // Ignore non-effective and dynamic requirements.
             String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE);
-            if (!state.isEffective(req)
+            if (!rc.isEffective(req)
                 || ((resolution != null)
                     && resolution.equals(FelixConstants.RESOLUTION_DYNAMIC)))
             {
@@ -272,9 +268,8 @@
 
             // Process the candidates, removing any candidates that
             // cannot resolve.
-            SortedSet<BundleCapability> candidates =
-                state.getCandidates((BundleRequirementImpl) req, true);
-            ResolveException rethrow = processCandidates(state, revision, candidates);
+            List<BundleCapability> candidates = rc.findProviders(req, true);
+            ResolveException rethrow = processCandidates(rc, revision, candidates);
 
             // First, due to cycles, makes sure we haven't already failed in
             // a deeper recursion.
@@ -324,7 +319,7 @@
         }
     }
 
-    private boolean populateFragmentOndemand(ResolverState state, BundleRevision revision)
+    private boolean populateFragmentOndemand(ResolveContext rc, BundleRevision revision)
         throws ResolveException
     {
         // Create a modifiable list of the revision's requirements.
@@ -344,8 +339,7 @@
             }
         }
         // Get candidates hosts and keep any that have been populated.
-        SortedSet<BundleCapability> hosts =
-            state.getCandidates((BundleRequirementImpl) hostReq, false);
+        List<BundleCapability> hosts = rc.findProviders(hostReq, false);
         for (Iterator<BundleCapability> it = hosts.iterator(); it.hasNext(); )
         {
             BundleCapability host = it.next();
@@ -364,16 +358,16 @@
         // some other checks and prepopulate the result cache with
         // the work we've done so far.
         // Verify that any required execution environment is satisfied.
-        state.checkExecutionEnvironment(revision);
+        ((ResolveContextImpl) rc).checkExecutionEnvironment(revision);
         // Verify that any native libraries match the current platform.
-        state.checkNativeLibraries(revision);
+        ((ResolveContextImpl) rc).checkNativeLibraries(revision);
         // Record cycle count, but start at -1 since it will
         // be incremented again in populate().
         Integer cycleCount = new Integer(-1);
         // Create a local map for populating candidates first, just in case
         // the revision is not resolvable.
-        Map<BundleRequirement, SortedSet<BundleCapability>> localCandidateMap =
-            new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
+        Map<BundleRequirement, List<BundleCapability>> localCandidateMap =
+            new HashMap<BundleRequirement, List<BundleCapability>>();
         // Add the discovered host candidates to the local candidate map.
         localCandidateMap.put(hostReq, hosts);
         // Add these value to the result cache so we know we are
@@ -385,8 +379,8 @@
     }
 
     public void populateDynamic(
-        ResolverState state, BundleRevision revision,
-        BundleRequirement req, SortedSet<BundleCapability> candidates)
+        ResolveContext rc, BundleRevision revision,
+        BundleRequirement req, List<BundleCapability> candidates)
     {
         // Record the revision associated with the dynamic require
         // as a mandatory revision.
@@ -397,7 +391,7 @@
 
         // Process the candidates, removing any candidates that
         // cannot resolve.
-        ResolveException rethrow = processCandidates(state, revision, candidates);
+        ResolveException rethrow = processCandidates(rc, revision, candidates);
 
         if (candidates.isEmpty())
         {
@@ -423,9 +417,9 @@
      * @return a resolve exception to be re-thrown, if any, or null.
      */
     private ResolveException processCandidates(
-        ResolverState state,
+        ResolveContext rc,
         BundleRevision revision,
-        SortedSet<BundleCapability> candidates)
+        List<BundleCapability> candidates)
     {
         // Get satisfying candidates and populate their candidates if necessary.
         ResolveException rethrow = null;
@@ -466,7 +460,7 @@
             {
                 try
                 {
-                    populateRevision(state, candCap.getRevision());
+                    populateRevision(rc, candCap.getRevision());
                 }
                 catch (ResolveException ex)
                 {
@@ -505,8 +499,19 @@
                         {
                             // Note that we can just add this as a candidate
                             // directly, since we know it is already resolved.
-                            candidates.add(
-                                new HostedCapability(
+                            // NOTE: We are synthesizing a hosted capability here,
+                            // but we are not using a ShadowList like we do when
+                            // we synthesizing capabilities for unresolved hosts.
+                            // It is not necessary to use the ShadowList here since
+                            // the host is resolved, because in that case we can
+                            // calculate the proper package space by traversing
+                            // the wiring. In the unresolved case, this isn't possible
+                            // so we need to use the ShadowList so we can keep
+                            // a reference to a synthesized resource with attached
+                            // fragments so we can correctly calculate its package
+                            // space.
+                            rc.insertHostedCapability(candidates,
+                                new WrappedCapability(
                                     wire.getCapability().getRevision(),
                                     (BundleCapabilityImpl) fragCand));
                         }
@@ -540,7 +545,7 @@
      * @param req the requirement to add.
      * @param candidates the candidates matching the requirement.
     **/
-    private void add(BundleRequirement req, SortedSet<BundleCapability> candidates)
+    private void add(BundleRequirement req, List<BundleCapability> candidates)
     {
         if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
         {
@@ -557,9 +562,9 @@
      * be further modified by the caller.
      * @param candidates the bulk requirements and candidates to add.
     **/
-    private void add(Map<BundleRequirement, SortedSet<BundleCapability>> candidates)
+    private void add(Map<BundleRequirement, List<BundleCapability>> candidates)
     {
-        for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry : candidates.entrySet())
+        for (Entry<BundleRequirement, List<BundleCapability>> entry : candidates.entrySet())
         {
             add(entry.getKey(), entry.getValue());
         }
@@ -583,7 +588,7 @@
      * @param req the requirement whose candidates are desired.
      * @return the matching candidates or null.
     **/
-    public SortedSet<BundleCapability> getCandidates(BundleRequirement req)
+    public List<BundleCapability> getCandidates(BundleRequirement req)
     {
         return m_candidateMap.get(req);
     }
@@ -604,7 +609,7 @@
      * @throws ResolveException if the removal of any unselected fragments result
      *         in the root module being unable to resolve.
     **/
-    public void prepare()
+    public void prepare(ResolveContext rc)
     {
         // Maps a host capability to a map containing its potential fragments;
         // the fragment map maps a fragment symbolic name to a map that maps
@@ -632,7 +637,7 @@
         //      with host's attached fragment capabilities.
 
         // Steps 1 and 2
-        List<HostBundleRevision> hostRevisions = new ArrayList<HostBundleRevision>();
+        List<WrappedRevision> hostRevisions = new ArrayList<WrappedRevision>();
         List<BundleRevision> unselectedFragments = new ArrayList<BundleRevision>();
         for (Entry<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
             hostEntry : hostFragments.entrySet())
@@ -667,7 +672,7 @@
                         else
                         {
                             m_dependentMap.get(hostCap).remove(hostReq);
-                            SortedSet<BundleCapability> hosts = m_candidateMap.get(hostReq);
+                            List<BundleCapability> hosts = m_candidateMap.get(hostReq);
                             hosts.remove(hostCap);
                             if (hosts.isEmpty())
                             {
@@ -679,8 +684,8 @@
             }
 
             // Step 2
-            HostBundleRevision wrappedHost =
-                new HostBundleRevision(hostCap.getRevision(), selectedFragments);
+            WrappedRevision wrappedHost =
+                new WrappedRevision(hostCap.getRevision(), selectedFragments);
             hostRevisions.add(wrappedHost);
             m_allWrappedHosts.put(hostCap.getRevision(), wrappedHost);
         }
@@ -694,7 +699,7 @@
         }
 
         // Step 4
-        for (HostBundleRevision hostRevision : hostRevisions)
+        for (WrappedRevision hostRevision : hostRevisions)
         {
             // Replaces capabilities from fragments with the capabilities
             // from the merged host.
@@ -704,8 +709,7 @@
                 // really be attached to the original host, not the wrapper.
                 if (!c.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
                 {
-                    BundleCapability origCap =
-                        ((HostedCapability) c).getOriginalCapability();
+                    BundleCapability origCap = ((HostedCapability) c).getDeclaredCapability();
                     // Note that you might think we could remove the original cap
                     // from the dependent map, but you can't since it may come from
                     // a fragment that is attached to multiple hosts, so each host
@@ -717,9 +721,63 @@
                         m_dependentMap.put(c, dependents);
                         for (BundleRequirement r : dependents)
                         {
-                            Set<BundleCapability> cands = m_candidateMap.get(r);
-                            cands.remove(origCap);
-                            cands.add(c);
+                            // We have synthesized hosted capabilities for all
+                            // fragments that have been attached to hosts by
+                            // wrapping the host bundle and their attached
+                            // fragments. We need to use the ResolveContext to
+                            // determine the proper priority order for hosted
+                            // capabilities since the order may depend on the
+                            // declaring host/fragment combination. However,
+                            // internally we completely wrap the host revision
+                            // and make all capabilities/requirements point back
+                            // to the wrapped host not the declaring host. The
+                            // ResolveContext expects HostedCapabilities to point
+                            // to the declaring revision, so we need two separate
+                            // candidate lists: one for the ResolveContext with
+                            // HostedCapabilities pointing back to the declaring
+                            // host and one for the resolver with HostedCapabilities
+                            // pointing back to the wrapped host. We ask the
+                            // ResolveContext to insert its appropriate HostedCapability
+                            // into its list, then we mirror the insert into a
+                            // shadow list with the resolver's HostedCapability.
+                            // We only need to ask the ResolveContext to find
+                            // the insert position for fragment caps since these
+                            // were synthesized and we don't know their priority.
+                            // However, in the resolver's candidate list we need
+                            // to replace all caps with the wrapped caps, no
+                            // matter if they come from the host or fragment,
+                            // since we are completing replacing the declaring
+                            // host and fragments with the wrapped host.
+                            List<BundleCapability> cands = m_candidateMap.get(r);
+                            if (!(cands instanceof ShadowList))
+                            {
+                                ShadowList<BundleCapability> shadow =
+                                    new ShadowList<BundleCapability>(cands);
+                                m_candidateMap.put(r, shadow);
+                                cands = shadow;
+                            }
+
+                            // If the original capability is from a fragment, then
+                            // ask the ResolveContext to insert it and update the
+                            // shadow copy of the list accordingly.
+                            if (!origCap.getRevision().equals(hostRevision.getHost()))
+                            {
+                                List<BundleCapability> original = ((ShadowList) cands).getOriginal();
+                                int removeIdx = original.indexOf(origCap);
+                                original.remove(removeIdx);
+                                int insertIdx = rc.insertHostedCapability(
+                                    original,
+                                    new SimpleHostedCapability(hostRevision.getHost(), origCap));
+                                cands.remove(removeIdx);
+                                cands.add(insertIdx, c);
+                            }
+                            // If the original capability is from the host, then
+                            // we just need to replace it in the shadow list.
+                            else
+                            {
+                                int idx = cands.indexOf(origCap);
+                                cands.set(idx, c);
+                            }
                         }
                     }
                 }
@@ -729,11 +787,11 @@
             for (BundleRequirement r : hostRevision.getDeclaredRequirements(null))
             {
                 BundleRequirement origReq =
-                    ((HostedRequirement) r).getOriginalRequirement();
-                SortedSet<BundleCapability> cands = m_candidateMap.get(origReq);
+                    ((WrappedRequirement) r).getOriginalRequirement();
+                List<BundleCapability> cands = m_candidateMap.get(origReq);
                 if (cands != null)
                 {
-                    m_candidateMap.put(r, new TreeSet<BundleCapability>(cands));
+                    m_candidateMap.put(r, new ArrayList<BundleCapability>(cands));
                     for (BundleCapability cand : cands)
                     {
                         Set<BundleRequirement> dependents = m_dependentMap.get(cand);
@@ -766,11 +824,10 @@
         Map<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
             hostFragments = new HashMap<BundleCapability,
                 Map<String, Map<Version, List<BundleRequirement>>>>();
-        for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry
-            : m_candidateMap.entrySet())
+        for (Entry<BundleRequirement, List<BundleCapability>> entry : m_candidateMap.entrySet())
         {
             BundleRequirement req = entry.getKey();
-            SortedSet<BundleCapability> caps = entry.getValue();
+            List<BundleCapability> caps = entry.getValue();
             for (BundleCapability cap : caps)
             {
                 // Record the requirement as dependent on the capability.
@@ -871,7 +928,7 @@
     {
         boolean isFragment = req.getNamespace().equals(BundleRevision.HOST_NAMESPACE);
 
-        SortedSet<BundleCapability> candidates = m_candidateMap.remove(req);
+        List<BundleCapability> candidates = m_candidateMap.remove(req);
         if (candidates != null)
         {
             for (BundleCapability cap : candidates)
@@ -902,7 +959,7 @@
         {
             for (BundleRequirement r : dependents)
             {
-                SortedSet<BundleCapability> candidates = m_candidateMap.get(r);
+                List<BundleCapability> candidates = m_candidateMap.get(r);
                 candidates.remove(c);
                 if (candidates.isEmpty())
                 {
@@ -935,13 +992,13 @@
             dependentMap.put(entry.getKey(), dependents);
         }
 
-        Map<BundleRequirement, SortedSet<BundleCapability>> candidateMap =
-            new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
-        for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry
+        Map<BundleRequirement, List<BundleCapability>> candidateMap =
+            new HashMap<BundleRequirement, List<BundleCapability>>();
+        for (Entry<BundleRequirement, List<BundleCapability>> entry
             : m_candidateMap.entrySet())
         {
-            SortedSet<BundleCapability> candidates =
-                new TreeSet<BundleCapability>(entry.getValue());
+            List<BundleCapability> candidates =
+                new ArrayList<BundleCapability>(entry.getValue());
             candidateMap.put(entry.getKey(), candidates);
         }
 
@@ -954,7 +1011,7 @@
     {
         // Create set of all revisions from requirements.
         Set<BundleRevision> revisions = new HashSet<BundleRevision>();
-        for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry
+        for (Entry<BundleRequirement, List<BundleCapability>> entry
             : m_candidateMap.entrySet())
         {
             revisions.add(entry.getKey().getRevision());
@@ -970,7 +1027,7 @@
                 : br.getDeclaredRequirements(null);
             for (BundleRequirement req : reqs)
             {
-                Set<BundleCapability> candidates = m_candidateMap.get(req);
+                List<BundleCapability> candidates = m_candidateMap.get(req);
                 if ((candidates != null) && (candidates.size() > 0))
                 {
                     System.out.println("    " + req + ": " + candidates);
@@ -981,7 +1038,7 @@
                 : Util.getDynamicRequirements(br.getDeclaredRequirements(null));
             for (BundleRequirement req : reqs)
             {
-                Set<BundleCapability> candidates = m_candidateMap.get(req);
+                List<BundleCapability> candidates = m_candidateMap.get(req);
                 if ((candidates != null) && (candidates.size() > 0))
                 {
                     System.out.println("    " + req + ": " + candidates);
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java b/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
index dbdad1c..fc45301 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
@@ -1,122 +1,26 @@
 /*
- * 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
+ * Copyright (c) OSGi Alliance (2012). All Rights Reserved.
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * Licensed 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
  *
- * 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.
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 package org.apache.felix.framework.resolver;
 
-import java.util.List;
-import java.util.Map;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRevision;
 
-public class HostedCapability extends BundleCapabilityImpl
-{
-    private final BundleRevision m_host;
-    private final BundleCapabilityImpl m_cap;
+public interface HostedCapability extends BundleCapability {
 
-    public HostedCapability(BundleRevision host, BundleCapabilityImpl cap)
-    {
-        super(host, cap.getNamespace(), cap.getDirectives(), cap.getAttributes());
-        m_host = host;
-        m_cap = cap;
-    }
+	BundleRevision getRevision();
 
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj == null)
-        {
-            return false;
-        }
-        if (getClass() != obj.getClass())
-        {
-            return false;
-        }
-        final HostedCapability other = (HostedCapability) obj;
-        if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host)))
-        {
-            return false;
-        }
-        if (m_cap != other.m_cap && (m_cap == null || !m_cap.equals(other.m_cap)))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public int hashCode()
-    {
-        int hash = 7;
-        hash = 37 * hash + (m_host != null ? m_host.hashCode() : 0);
-        hash = 37 * hash + (m_cap != null ? m_cap.hashCode() : 0);
-        return hash;
-    }
-
-    public BundleCapabilityImpl getOriginalCapability()
-    {
-        return m_cap;
-    }
-
-    @Override
-    public BundleRevision getRevision()
-    {
-        return m_host;
-    }
-
-    @Override
-    public String getNamespace()
-    {
-        return m_cap.getNamespace();
-    }
-
-    @Override
-    public Map<String, String> getDirectives()
-    {
-        return m_cap.getDirectives();
-    }
-
-    @Override
-    public Map<String, Object> getAttributes()
-    {
-        return m_cap.getAttributes();
-    }
-
-    @Override
-    public List<String> getUses()
-    {
-        return m_cap.getUses();
-    }
-
-    @Override
-    public String toString()
-    {
-        if (m_host == null)
-        {
-            return getAttributes().toString();
-        }
-        if (getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
-        {
-            return "[" + m_host + "] "
-                + getNamespace()
-                + "; "
-                + getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
-        }
-        return "[" + m_host + "] " + getNamespace() + "; " + getAttributes();
-    }
-}
\ No newline at end of file
+	BundleCapability getDeclaredCapability();
+}
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolveContext.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveContext.java
new file mode 100644
index 0000000..2af0696
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveContext.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.framework.resolver;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWiring;
+
+public abstract class ResolveContext
+{
+    public Collection<BundleRevision> getMandatoryRevisions()
+    {
+        return emptyCollection();
+    }
+
+    public Collection<BundleRevision> getOptionalRevisions()
+    {
+        return emptyCollection();
+    }
+
+    private static <T> Collection<T> emptyCollection()
+    {
+        return Collections.EMPTY_LIST;
+    }
+
+    public abstract List<BundleCapability> findProviders(BundleRequirement br, boolean obeyMandatory);
+
+    public abstract int insertHostedCapability(List<BundleCapability> caps, HostedCapability hc);
+
+    public abstract boolean isEffective(BundleRequirement br);
+
+    public abstract Map<BundleRevision, BundleWiring> getWirings();
+}
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java b/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
index eabfdd1..107e4a7 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
@@ -28,21 +28,7 @@
 
 public interface Resolver
 {
+    Map<BundleRevision, List<ResolverWire>> resolve(ResolveContext rc);
     Map<BundleRevision, List<ResolverWire>> resolve(
-        ResolverState state,
-        Set<BundleRevision> mandatoryRevisions,
-        Set<BundleRevision> optionalRevisions,
-        Set<BundleRevision> ondemandFragments);
-    Map<BundleRevision, List<ResolverWire>> resolve(
-        ResolverState state, BundleRevision revision, String pkgName,
-        Set<BundleRevision> ondemandFragments);
-
-    public static interface ResolverState
-    {
-        boolean isEffective(BundleRequirement req);
-        SortedSet<BundleCapability> getCandidates(
-            BundleRequirement req, boolean obeyMandatory);
-        void checkExecutionEnvironment(BundleRevision revision) throws ResolveException;
-        void checkNativeLibraries(BundleRevision revision) throws ResolveException;
-    }
+        ResolveContext rc, BundleRevision revision, String pkgName);
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
index 56203b3..8f1fabc 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
@@ -19,6 +19,7 @@
 package org.apache.felix.framework.resolver;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -30,6 +31,7 @@
 import java.util.SortedSet;
 import org.apache.felix.framework.BundleWiringImpl;
 import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.ResolveContextImpl;
 import org.apache.felix.framework.capabilityset.CapabilitySet;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.Util;
@@ -57,17 +59,17 @@
         m_logger = logger;
     }
 
-    public Map<BundleRevision, List<ResolverWire>> resolve(
-        ResolverState state,
-        Set<BundleRevision> mandatoryRevisions,
-        Set<BundleRevision> optionalRevisions,
-        Set<BundleRevision> ondemandFragments)
+    public Map<BundleRevision, List<ResolverWire>> resolve(ResolveContext rc)
     {
         Map<BundleRevision, List<ResolverWire>> wireMap =
             new HashMap<BundleRevision, List<ResolverWire>>();
         Map<BundleRevision, Packages> revisionPkgMap =
             new HashMap<BundleRevision, Packages>();
 
+        Collection<BundleRevision> mandatoryRevisions = rc.getMandatoryRevisions();
+        Collection<BundleRevision> optionalRevisions = rc.getOptionalRevisions();
+        Collection<BundleRevision> ondemandFragments = (rc instanceof ResolveContextImpl)
+            ? ((ResolveContextImpl) rc).getOndemandRevisions() : Collections.EMPTY_LIST;
         boolean retry;
         do
         {
@@ -86,7 +88,7 @@
                     BundleRevision br = it.next();
                     if (Util.isFragment(br) || (br.getWiring() == null))
                     {
-                        allCandidates.populate(state, br, Candidates.MANDATORY);
+                        allCandidates.populate(rc, br, Candidates.MANDATORY);
                     }
                     else
                     {
@@ -101,7 +103,7 @@
                     boolean isFragment = Util.isFragment(br);
                     if (isFragment || (br.getWiring() == null))
                     {
-                        allCandidates.populate(state, br, Candidates.OPTIONAL);
+                        allCandidates.populate(rc, br, Candidates.OPTIONAL);
                     }
                 }
 
@@ -112,12 +114,12 @@
                     boolean isFragment = Util.isFragment(br);
                     if (isFragment)
                     {
-                        allCandidates.populate(state, br, Candidates.ON_DEMAND);
+                        allCandidates.populate(rc, br, Candidates.ON_DEMAND);
                     }
                 }
 
                 // Merge any fragments into hosts.
-                allCandidates.prepare();
+                allCandidates.prepare(rc);
 
                 // Create a combined list of populated revisions; for
                 // optional revisions. We do not need to consider ondemand
@@ -207,11 +209,11 @@
                 if (rethrow != null)
                 {
                     BundleRevision faultyRevision =
-                        getActualBundleRevision(rethrow.getRevision());
-                    if (rethrow.getRequirement() instanceof HostedRequirement)
+                        getDeclaringBundleRevision(rethrow.getRevision());
+                    if (rethrow.getRequirement() instanceof WrappedRequirement)
                     {
                         faultyRevision =
-                            ((HostedRequirement) rethrow.getRequirement())
+                            ((WrappedRequirement) rethrow.getRequirement())
                                 .getOriginalRequirement().getRevision();
                     }
                     if (optionalRevisions.remove(faultyRevision))
@@ -267,8 +269,7 @@
     }
 
     public Map<BundleRevision, List<ResolverWire>> resolve(
-        ResolverState state, BundleRevision revision, String pkgName,
-        Set<BundleRevision> ondemandFragments)
+        ResolveContext rc, BundleRevision revision, String pkgName)
     {
         // We can only create a dynamic import if the following
         // conditions are met:
@@ -280,11 +281,16 @@
         // The following call checks all of these conditions and returns
         // the associated dynamic import and matching capabilities.
         Candidates allCandidates =
-            getDynamicImportCandidates(state, revision, pkgName);
+            getDynamicImportCandidates(rc, revision, pkgName);
         if (allCandidates != null)
         {
-            Map<BundleRevision, List<ResolverWire>> wireMap = new HashMap<BundleRevision, List<ResolverWire>>();
-            Map<BundleRevision, Packages> revisionPkgMap = new HashMap<BundleRevision, Packages>();
+            Collection<BundleRevision> ondemandFragments = (rc instanceof ResolveContextImpl)
+                ? ((ResolveContextImpl) rc).getOndemandRevisions() : Collections.EMPTY_LIST;
+
+            Map<BundleRevision, List<ResolverWire>> wireMap =
+                new HashMap<BundleRevision, List<ResolverWire>>();
+            Map<BundleRevision, Packages> revisionPkgMap =
+                new HashMap<BundleRevision, Packages>();
 
             boolean retry;
             do
@@ -298,12 +304,12 @@
                     {
                         if (Util.isFragment(br))
                         {
-                            allCandidates.populate(state, br, Candidates.ON_DEMAND);
+                            allCandidates.populate(rc, br, Candidates.ON_DEMAND);
                         }
                     }
 
                     // Merge any fragments into hosts.
-                    allCandidates.prepare();
+                    allCandidates.prepare(rc);
 
                     // Record the initial candidate permutation.
                     m_usesPermutations.add(allCandidates);
@@ -355,11 +361,11 @@
                     if (rethrow != null)
                     {
                         BundleRevision faultyRevision =
-                            getActualBundleRevision(rethrow.getRevision());
-                        if (rethrow.getRequirement() instanceof HostedRequirement)
+                            getDeclaringBundleRevision(rethrow.getRevision());
+                        if (rethrow.getRequirement() instanceof WrappedRequirement)
                         {
                             faultyRevision =
-                                ((HostedRequirement) rethrow.getRequirement())
+                                ((WrappedRequirement) rethrow.getRequirement())
                                     .getOriginalRequirement().getRevision();
                         }
                         if (ondemandFragments.remove(faultyRevision))
@@ -394,7 +400,7 @@
     }
 
     private static Candidates getDynamicImportCandidates(
-        ResolverState state, BundleRevision revision, String pkgName)
+        ResolveContext rc, BundleRevision revision, String pkgName)
     {
         // Unresolved revisions cannot dynamically import, nor can the default
         // package be dynamically imported.
@@ -438,7 +444,7 @@
             BundleRevision.PACKAGE_NAMESPACE,
             Collections.EMPTY_MAP,
             attrs);
-        SortedSet<BundleCapability> candidates = state.getCandidates(req, false);
+        List<BundleCapability> candidates = rc.findProviders(req, false);
 
         // Try to find a dynamic requirement that matches the capabilities.
         BundleRequirementImpl dynReq = null;
@@ -484,7 +490,7 @@
         if (candidates.size() > 0)
         {
             allCandidates = new Candidates();
-            allCandidates.populateDynamic(state, revision, dynReq, candidates);
+            allCandidates.populateDynamic(rc, revision, dynReq, candidates);
         }
 
         return allCandidates;
@@ -523,7 +529,7 @@
                     || ((r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE) != null)
                         && r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE).equals("dynamic")))
                 {
-                    r = new HostedRequirement(
+                    r = new WrappedRequirement(
                         wire.getRequirerWiring().getRevision(),
                         (BundleRequirementImpl) r);
                 }
@@ -532,7 +538,7 @@
                 BundleCapability c = wire.getCapability();
                 if (!c.getRevision().equals(wire.getProviderWiring().getRevision()))
                 {
-                    c = new HostedCapability(
+                    c = new WrappedCapability(
                         wire.getProviderWiring().getRevision(),
                         (BundleCapabilityImpl) c);
                 }
@@ -547,15 +553,15 @@
                 : Util.getDynamicRequirements(revision.getWiring().getRequirements(null)))
             {
                 // Get the candidates for the current requirement.
-                SortedSet<BundleCapability> candCaps =
-                    allCandidates.getCandidates((BundleRequirementImpl) req);
+                List<BundleCapability> candCaps = allCandidates.getCandidates(req);
                 // Optional requirements may not have any candidates.
                 if (candCaps == null)
                 {
                     continue;
                 }
 
-                BundleCapability cap = candCaps.iterator().next();
+                // Grab first (i.e., highest priority) candidate.
+                BundleCapability cap = candCaps.get(0);
                 reqs.add(req);
                 caps.add(cap);
                 isDynamicImporting = true;
@@ -573,15 +579,15 @@
                     || !resolution.equals(FelixConstants.RESOLUTION_DYNAMIC))
                 {
                     // Get the candidates for the current requirement.
-                    SortedSet<BundleCapability> candCaps =
-                        allCandidates.getCandidates((BundleRequirementImpl) req);
+                    List<BundleCapability> candCaps = allCandidates.getCandidates(req);
                     // Optional requirements may not have any candidates.
                     if (candCaps == null)
                     {
                         continue;
                     }
 
-                    BundleCapability cap = candCaps.iterator().next();
+                    // Grab first (i.e., highest priority) candidate.
+                    BundleCapability cap = candCaps.get(0);
                     reqs.add(req);
                     caps.add(cap);
                 }
@@ -974,6 +980,7 @@
             }
         }
 
+        // Check if there are any uses conflicts with exported packages.
         for (Entry<String, Blame> entry : pkgs.m_exportedPkgs.entrySet())
         {
             String pkgName = entry.getKey();
@@ -1026,14 +1033,12 @@
                         // See if we can permutate the candidates for blamed
                         // requirement; there may be no candidates if the revision
                         // associated with the requirement is already resolved.
-                        SortedSet<BundleCapability> candidates =
-                            permutation.getCandidates(req);
+                        List<BundleCapability> candidates = permutation.getCandidates(req);
                         if ((candidates != null) && (candidates.size() > 1))
                         {
                             mutated.add(req);
-                            Iterator it = candidates.iterator();
-                            it.next();
-                            it.remove();
+                            // Remove the conflicting candidate.
+                            candidates.remove(0);
                             // Continue with the next uses constraint.
                             break;
                         }
@@ -1115,14 +1120,12 @@
                             // See if we can permutate the candidates for blamed
                             // requirement; there may be no candidates if the revision
                             // associated with the requirement is already resolved.
-                            SortedSet<BundleCapability> candidates =
-                                permutation.getCandidates(req);
+                            List<BundleCapability> candidates = permutation.getCandidates(req);
                             if ((candidates != null) && (candidates.size() > 1))
                             {
                                 mutated.add(req);
-                                Iterator it = candidates.iterator();
-                                it.next();
-                                it.remove();
+                                // Remove the conflicting candidate.
+                                candidates.remove(0);
                                 // Continue with the next uses constraint.
                                 break;
                             }
@@ -1207,14 +1210,12 @@
     private static void permutate(
         Candidates allCandidates, BundleRequirement req, List<Candidates> permutations)
     {
-        SortedSet<BundleCapability> candidates = allCandidates.getCandidates(req);
+        List<BundleCapability> candidates = allCandidates.getCandidates(req);
         if (candidates.size() > 1)
         {
             Candidates perm = allCandidates.copy();
             candidates = perm.getCandidates(req);
-            Iterator it = candidates.iterator();
-            it.next();
-            it.remove();
+            candidates.remove(0);
             permutations.add(perm);
         }
     }
@@ -1222,7 +1223,7 @@
     private static void permutateIfNeeded(
         Candidates allCandidates, BundleRequirement req, List<Candidates> permutations)
     {
-        SortedSet<BundleCapability> candidates = allCandidates.getCandidates(req);
+        List<BundleCapability> candidates = allCandidates.getCandidates(req);
         if (candidates.size() > 1)
         {
             // Check existing permutations to make sure we haven't
@@ -1234,8 +1235,8 @@
             boolean permutated = false;
             for (Candidates existingPerm : permutations)
             {
-                Set<BundleCapability> existingPermCands = existingPerm.getCandidates(req);
-                if (!existingPermCands.iterator().next().equals(candidates.iterator().next()))
+                List<BundleCapability> existingPermCands = existingPerm.getCandidates(req);
+                if (!existingPermCands.get(0).equals(candidates.get(0)))
                 {
                     permutated = true;
                 }
@@ -1273,7 +1274,7 @@
             {
                 if (!cap.getRevision().equals(revision))
                 {
-                    cap = new HostedCapability(revision, (BundleCapabilityImpl) cap);
+                    cap = new WrappedCapability(revision, (BundleCapabilityImpl) cap);
                 }
                 exports.put(
                     (String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
@@ -1293,11 +1294,10 @@
                 {
                     if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
                     {
-                        Set<BundleCapability> cands =
-                            allCandidates.getCandidates((BundleRequirementImpl) req);
+                        List<BundleCapability> cands = allCandidates.getCandidates(req);
                         if ((cands != null) && !cands.isEmpty())
                         {
-                            String pkgName = (String) cands.iterator().next()
+                            String pkgName = (String) cands.get(0)
                                 .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
                             exports.remove(pkgName);
                         }
@@ -1401,7 +1401,7 @@
                     if (!cap.getRevision().equals(sourceCap.getRevision()))
                     {
                         sources.add(
-                            new HostedCapability(cap.getRevision(), (BundleCapabilityImpl) sourceCap));
+                            new WrappedCapability(cap.getRevision(), (BundleCapabilityImpl) sourceCap));
                     }
                     else
                     {
@@ -1425,29 +1425,29 @@
         return sources;
     }
 
-    private static BundleRevision getActualBundleRevision(BundleRevision br)
+    private static BundleRevision getDeclaringBundleRevision(BundleRevision br)
     {
-        if (br instanceof HostBundleRevision)
+        if (br instanceof WrappedRevision)
         {
-            return ((HostBundleRevision) br).getHost();
+            return ((WrappedRevision) br).getHost();
         }
         return br;
     }
 
-    private static BundleCapability getActualCapability(BundleCapability c)
+    private static BundleCapability getDeclaredCapability(BundleCapability c)
     {
         if (c instanceof HostedCapability)
         {
-            return ((HostedCapability) c).getOriginalCapability();
+            return ((HostedCapability) c).getDeclaredCapability();
         }
         return c;
     }
 
-    private static BundleRequirement getActualRequirement(BundleRequirement r)
+    private static BundleRequirement getDeclaredRequirement(BundleRequirement r)
     {
-        if (r instanceof HostedRequirement)
+        if (r instanceof WrappedRequirement)
         {
-            return ((HostedRequirement) r).getOriginalRequirement();
+            return ((WrappedRequirement) r).getOriginalRequirement();
         }
         return r;
     }
@@ -1457,7 +1457,7 @@
         Map<BundleRevision, List<ResolverWire>> wireMap,
         Candidates allCandidates)
     {
-        BundleRevision unwrappedRevision = getActualBundleRevision(revision);
+        BundleRevision unwrappedRevision = getDeclaringBundleRevision(revision);
         if ((unwrappedRevision.getWiring() == null)
             && !wireMap.containsKey(unwrappedRevision))
         {
@@ -1469,10 +1469,10 @@
 
             for (BundleRequirement req : revision.getDeclaredRequirements(null))
             {
-                SortedSet<BundleCapability> cands = allCandidates.getCandidates(req);
+                List<BundleCapability> cands = allCandidates.getCandidates(req);
                 if ((cands != null) && (cands.size() > 0))
                 {
-                    BundleCapability cand = cands.iterator().next();
+                    BundleCapability cand = cands.get(0);
                     // Ignore revisions that import themselves.
                     if (!revision.equals(cand.getRevision()))
                     {
@@ -1484,9 +1484,9 @@
                         Packages candPkgs = revisionPkgMap.get(cand.getRevision());
                         ResolverWire wire = new ResolverWireImpl(
                             unwrappedRevision,
-                            getActualRequirement(req),
-                            getActualBundleRevision(cand.getRevision()),
-                            getActualCapability(cand));
+                            getDeclaredRequirement(req),
+                            getDeclaringBundleRevision(cand.getRevision()),
+                            getDeclaredCapability(cand));
                         if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
                         {
                             packageWires.add(wire);
@@ -1509,9 +1509,9 @@
             wireMap.put(unwrappedRevision, packageWires);
 
             // Add host wire for any fragments.
-            if (revision instanceof HostBundleRevision)
+            if (revision instanceof WrappedRevision)
             {
-                List<BundleRevision> fragments = ((HostBundleRevision) revision).getFragments();
+                List<BundleRevision> fragments = ((WrappedRevision) revision).getFragments();
                 for (BundleRevision fragment : fragments)
                 {
                     List<ResolverWire> hostWires = wireMap.get(fragment);
@@ -1522,7 +1522,7 @@
                     }
                     hostWires.add(
                         new ResolverWireImpl(
-                            getActualBundleRevision(fragment),
+                            getDeclaringBundleRevision(fragment),
                             fragment.getDeclaredRequirements(
                                 BundleRevision.HOST_NAMESPACE).get(0),
                             unwrappedRevision,
@@ -1549,8 +1549,7 @@
             : Util.getDynamicRequirements(revision.getWiring().getRequirements(null)))
         {
             // Get the candidates for the current dynamic requirement.
-            SortedSet<BundleCapability> candCaps =
-                allCandidates.getCandidates((BundleRequirementImpl) req);
+            List<BundleCapability> candCaps = allCandidates.getCandidates(req);
             // Optional requirements may not have any candidates.
             if ((candCaps == null) || candCaps.isEmpty())
             {
@@ -1559,7 +1558,7 @@
 
             // Record the dynamic requirement.
             dynReq = req;
-            dynCand = candCaps.first();
+            dynCand = candCaps.get(0);
 
             // Can only dynamically import one at a time, so break
             // out of the loop after the first.
@@ -1580,8 +1579,8 @@
                 new ResolverWireImpl(
                     revision,
                     dynReq,
-                    getActualBundleRevision(dynCand.getRevision()),
-                    getActualCapability(dynCand)));
+                    getDeclaringBundleRevision(dynCand.getRevision()),
+                    getDeclaredCapability(dynCand)));
         }
 
         wireMap.put(revision, packageWires);
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ShadowList.java b/framework/src/main/java/org/apache/felix/framework/resolver/ShadowList.java
new file mode 100644
index 0000000..e64b559
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ShadowList.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework.resolver;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+public class ShadowList<T> implements List<T>
+{
+    private final List<T> m_original;
+    private final List<T> m_shadow;
+
+    public ShadowList(List<T> original)
+    {
+        m_original = original;
+        m_shadow = new ArrayList<T>(original);
+    }
+
+    public List<T> getOriginal()
+    {
+        return m_original;
+    }
+
+    public int size()
+    {
+        return m_shadow.size();
+    }
+
+    public boolean isEmpty()
+    {
+        return m_shadow.isEmpty();
+    }
+
+    public boolean contains(Object o)
+    {
+        return m_shadow.contains(o);
+    }
+
+    public Iterator<T> iterator()
+    {
+        return m_shadow.iterator();
+    }
+
+    public Object[] toArray()
+    {
+        return m_shadow.toArray();
+    }
+
+    public <T> T[] toArray(T[] ts)
+    {
+        return m_shadow.toArray(ts);
+    }
+
+    public boolean add(T e)
+    {
+        return m_shadow.add(e);
+    }
+
+    public boolean remove(Object o)
+    {
+        return m_shadow.remove(o);
+    }
+
+    public boolean containsAll(Collection<?> clctn)
+    {
+        return m_shadow.containsAll(clctn);
+    }
+
+    public boolean addAll(Collection<? extends T> clctn)
+    {
+        return m_shadow.addAll(clctn);
+    }
+
+    public boolean addAll(int i, Collection<? extends T> clctn)
+    {
+        return m_shadow.addAll(i, clctn);
+    }
+
+    public boolean removeAll(Collection<?> clctn)
+    {
+        return m_shadow.removeAll(clctn);
+    }
+
+    public boolean retainAll(Collection<?> clctn)
+    {
+        return m_shadow.retainAll(clctn);
+    }
+
+    public void clear()
+    {
+        m_shadow.clear();
+    }
+
+    public T get(int i)
+    {
+        return m_shadow.get(i);
+    }
+
+    public T set(int i, T e)
+    {
+        return m_shadow.set(i, e);
+    }
+
+    public void add(int i, T e)
+    {
+        m_shadow.add(i, e);
+    }
+
+    public T remove(int i)
+    {
+        return m_shadow.remove(i);
+    }
+
+    public int indexOf(Object o)
+    {
+        return m_shadow.indexOf(o);
+    }
+
+    public int lastIndexOf(Object o)
+    {
+        return m_shadow.lastIndexOf(o);
+    }
+
+    public ListIterator<T> listIterator()
+    {
+        return m_shadow.listIterator();
+    }
+
+    public ListIterator<T> listIterator(int i)
+    {
+        return m_shadow.listIterator(i);
+    }
+
+    public List<T> subList(int i, int i1)
+    {
+        return m_shadow.subList(i, i1);
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/SimpleHostedCapability.java b/framework/src/main/java/org/apache/felix/framework/resolver/SimpleHostedCapability.java
new file mode 100644
index 0000000..5e31d03
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/SimpleHostedCapability.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework.resolver;
+
+import java.util.Map;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRevision;
+
+class SimpleHostedCapability implements HostedCapability
+{
+    private final BundleRevision m_host;
+    private final BundleCapability m_cap;
+
+    SimpleHostedCapability(BundleRevision host, BundleCapability cap)
+    {
+        m_host = host;
+        m_cap = cap;
+    }
+
+    public BundleRevision getRevision()
+    {
+        return m_host;
+    }
+
+    public BundleCapability getDeclaredCapability()
+    {
+        return m_cap;
+    }
+
+    public String getNamespace()
+    {
+        return m_cap.getNamespace();
+    }
+
+    public Map<String, String> getDirectives()
+    {
+        return m_cap.getDirectives();
+    }
+
+    public Map<String, Object> getAttributes()
+    {
+        return m_cap.getAttributes();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedCapability.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedCapability.java
new file mode 100644
index 0000000..7a21ec4
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedCapability.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) OSGi Alliance (2012). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.framework.resolver;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.felix.framework.wiring.BundleCapabilityImpl;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRevision;
+
+public class WrappedCapability extends BundleCapabilityImpl implements HostedCapability
+{
+    private final BundleRevision m_host;
+    private final BundleCapabilityImpl m_cap;
+
+    public WrappedCapability(BundleRevision host, BundleCapabilityImpl cap)
+    {
+        super(host, cap.getNamespace(), cap.getDirectives(), cap.getAttributes());
+        m_host = host;
+        m_cap = cap;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        final WrappedCapability other = (WrappedCapability) obj;
+        if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host)))
+        {
+            return false;
+        }
+        if (m_cap != other.m_cap && (m_cap == null || !m_cap.equals(other.m_cap)))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 7;
+        hash = 37 * hash + (m_host != null ? m_host.hashCode() : 0);
+        hash = 37 * hash + (m_cap != null ? m_cap.hashCode() : 0);
+        return hash;
+    }
+
+    public BundleCapability getDeclaredCapability()
+    {
+        return m_cap;
+    }
+
+    @Override
+    public BundleRevision getRevision()
+    {
+        return m_host;
+    }
+
+    @Override
+    public String getNamespace()
+    {
+        return m_cap.getNamespace();
+    }
+
+    @Override
+    public Map<String, String> getDirectives()
+    {
+        return m_cap.getDirectives();
+    }
+
+    @Override
+    public Map<String, Object> getAttributes()
+    {
+        return m_cap.getAttributes();
+    }
+
+    @Override
+    public List<String> getUses()
+    {
+        return m_cap.getUses();
+    }
+
+    @Override
+    public String toString()
+    {
+        if (m_host == null)
+        {
+            return getAttributes().toString();
+        }
+        if (getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
+        {
+            return "[" + m_host + "] "
+                + getNamespace()
+                + "; "
+                + getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
+        }
+        return "[" + m_host + "] " + getNamespace() + "; " + getAttributes();
+    }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/HostedRequirement.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
similarity index 93%
rename from framework/src/main/java/org/apache/felix/framework/resolver/HostedRequirement.java
rename to framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
index 58dadce..c0d15e0 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/HostedRequirement.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
@@ -23,12 +23,12 @@
 import org.apache.felix.framework.wiring.BundleRequirementImpl;
 import org.osgi.framework.wiring.BundleRevision;
 
-public class HostedRequirement extends BundleRequirementImpl
+public class WrappedRequirement extends BundleRequirementImpl
 {
     private final BundleRevision m_host;
     private final BundleRequirementImpl m_req;
 
-    public HostedRequirement(BundleRevision host, BundleRequirementImpl req)
+    public WrappedRequirement(BundleRevision host, BundleRequirementImpl req)
     {
         super(host, req.getNamespace(), req.getDirectives(), req.getAttributes());
         m_host = host;
@@ -46,7 +46,7 @@
         {
             return false;
         }
-        final HostedRequirement other = (HostedRequirement) obj;
+        final WrappedRequirement other = (WrappedRequirement) obj;
         if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host)))
         {
             return false;
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/HostBundleRevision.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
similarity index 89%
rename from framework/src/main/java/org/apache/felix/framework/resolver/HostBundleRevision.java
rename to framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
index 3f052bb..81c41ee 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/HostBundleRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
@@ -30,14 +30,14 @@
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.framework.wiring.BundleWiring;
 
-class HostBundleRevision implements BundleRevision
+class WrappedRevision implements BundleRevision
 {
     private final BundleRevision m_host;
     private final List<BundleRevision> m_fragments;
     private List<BundleCapability> m_cachedCapabilities = null;
     private List<BundleRequirement> m_cachedRequirements = null;
 
-    public HostBundleRevision(BundleRevision host, List<BundleRevision> fragments)
+    public WrappedRevision(BundleRevision host, List<BundleRevision> fragments)
     {
         m_host = host;
         m_fragments = fragments;
@@ -72,7 +72,7 @@
             // Wrap host capabilities.
             for (BundleCapability cap : m_host.getDeclaredCapabilities(null))
             {
-                caps.add(new HostedCapability(this, (BundleCapabilityImpl) cap));
+                caps.add(new WrappedCapability(this, (BundleCapabilityImpl) cap));
             }
 
             // Wrap fragment capabilities.
@@ -84,7 +84,7 @@
                     {
 // TODO: OSGi R4.4 - OSGi R4.4 may introduce an identity capability, if so
 //       that will need to be excluded from here.
-                        caps.add(new HostedCapability(this, (BundleCapabilityImpl) cap));
+                        caps.add(new WrappedCapability(this, (BundleCapabilityImpl) cap));
                     }
                 }
             }
@@ -102,7 +102,7 @@
             // Wrap host requirements.
             for (BundleRequirement req : m_host.getDeclaredRequirements(null))
             {
-                reqs.add(new HostedRequirement(this, (BundleRequirementImpl) req));
+                reqs.add(new WrappedRequirement(this, (BundleRequirementImpl) req));
             }
 
             // Wrap fragment requirements.
@@ -114,7 +114,7 @@
                     {
                         if (!req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
                         {
-                            reqs.add(new HostedRequirement(this, (BundleRequirementImpl) req));
+                            reqs.add(new WrappedRequirement(this, (BundleRequirementImpl) req));
                         }
                     }
                 }