Continued improvements to fragment merging and object allocation in
resolver. (FELIX-1534, FELIX-1781)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@831694 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index a501b6a..a80c675 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2961,14 +2961,14 @@
     ExportedPackage[] getExportedPackages(String pkgName)
     {
         // First, get all exporters of the package.
-        ICapability[] exporters =
+        List exports =
             m_resolverState.getResolvedCandidates(
                 new Requirement(
                     ICapability.PACKAGE_NAMESPACE,
                     null,
                     new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) }));
 
-        if (exporters != null)
+        if (exports != null)
         {
             List pkgs = new ArrayList();
 
@@ -2976,10 +2976,11 @@
                 null,
                 new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) });
 
-            for (int pkgIdx = 0; pkgIdx < exporters.length; pkgIdx++)
+            for (int pkgIdx = 0; pkgIdx < exports.size(); pkgIdx++)
             {
                 // Get the bundle associated with the current exporting module.
-                BundleImpl bundle = (BundleImpl) exporters[pkgIdx].getModule().getBundle();
+                BundleImpl bundle = (BundleImpl)
+                    ((ICapability) exports.get(pkgIdx)).getModule().getBundle();
 
                 // We need to find the version of the exported package, but this
                 // is tricky since there may be multiple versions of the package
@@ -3090,20 +3091,19 @@
                 for (int capIdx = 0; capIdx < caps.length; capIdx++)
                 {
                     // See if the target bundle's module is one of the
-                    // "in use" exporters of the package.
+                    // resolved exporters of the package.
                     if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
                     {
-                        ICapability[] inUseCaps = m_resolverState.getResolvedCandidates(
+                        List resolvedCaps = m_resolverState.getResolvedCandidates(
                             new Requirement(
                                 ICapability.PACKAGE_NAMESPACE,
                                 null,
                                 new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, ((Capability) caps[capIdx]).getPackageName(), false) }));
 
-                        // Search through the current providers to find the target
-                        // module.
-                        for (int i = 0; (inUseCaps != null) && (i < inUseCaps.length); i++)
+                        // Search through the current providers to find the target module.
+                        for (int i = 0; (resolvedCaps != null) && (i < resolvedCaps.size()); i++)
                         {
-                            if (inUseCaps[i].getModule() == modules[modIdx])
+                            if (((ICapability) resolvedCaps.get(i)).getModule() == modules[modIdx])
                             {
                                 list.add(new ExportedPackageImpl(
                                     this, bundle, modules[modIdx], (Capability) caps[capIdx]));
@@ -3960,12 +3960,12 @@
             return candidateWire;
         }
 
-        public synchronized ICapability[] getResolvedCandidates(IRequirement req)
+        public synchronized List getResolvedCandidates(IRequirement req)
         {
             return m_resolverState.getResolvedCandidates(req);
         }
 
-        public synchronized ICapability[] getUnresolvedCandidates(IRequirement req)
+        public synchronized List getUnresolvedCandidates(IRequirement req)
         {
             return m_resolverState.getUnresolvedCandidates(req);
         }
diff --git a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
index 666c652..7b7f403 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -20,6 +20,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -43,19 +44,15 @@
     private final Logger m_logger;
     // List of all modules.
     private final List m_moduleList = new ArrayList();
-    // Map of fragment symbolic names to array of fragment modules sorted by version.
+    // Map of fragment symbolic names to list of fragment modules sorted by version.
     private final Map m_fragmentMap = new HashMap();
-    // Maps a package name to an array of exporting capabilities.
+    // Maps a package name to a list of exporting capabilities.
     private final Map m_unresolvedPkgIndex = new HashMap();
-    // Maps a package name to an array of exporting capabilities.
+    // Maps a package name to a list of exporting capabilities.
     private final Map m_resolvedPkgIndex = new HashMap();
-    // Maps a module to an array of capabilities.
+    // Maps a module to a list of capabilities.
     private final Map m_resolvedCapMap = new HashMap();
 
-    // Reusable empty array.
-    private static final IModule[] m_emptyModules = new IModule[0];
-    private static final ICapability[] m_emptyCandidates = new ICapability[0];
-
     public FelixResolverState(Logger logger)
     {
         m_logger = logger;
@@ -73,9 +70,9 @@
         }
 
 //System.out.println("UNRESOLVED PACKAGES:");
-//dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+//dumpPackageIndex(m_unresolvedPkgIndex);
 //System.out.println("RESOLVED PACKAGES:");
-//dumpPackageIndexMap(m_resolvedPkgIndexMap);
+//dumpPackageIndex(m_resolvedPkgIndex);
     }
 
     public synchronized void removeModule(IModule module)
@@ -152,11 +149,10 @@
                         String pkgName = (String)
                             caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
                         // Remove from "unresolved" package map.
-                        IModule[] modules = (IModule[]) m_unresolvedPkgIndex.get(pkgName);
-                        if (modules != null)
+                        List capList = (List) m_unresolvedPkgIndex.get(pkgName);
+                        if (capList != null)
                         {
-                            modules = removeModuleFromArray(modules, host);
-                            m_unresolvedPkgIndex.put(pkgName, modules);
+                            capList.remove(caps[i]);
                         }
                     }
                 }
@@ -192,7 +188,7 @@
                 {
                     if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
                     {
-                        indexPackageCapability(m_unresolvedPkgIndex, host, caps[i]);
+                        indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
                     }
                 }
             }
@@ -201,88 +197,89 @@
 
     private void removeFragment(IModule fragment)
     {
-        // If module is a fragment, then remove from fragment map.
-        IModule[] fragments = (IModule[]) m_fragmentMap.get(fragment.getSymbolicName());
-        fragments = removeModuleFromArray(fragments, fragment);
-        if (fragments.length == 0)
+        // Get fragment list, which may be null for system bundle fragments.
+        List fragList = (List) m_fragmentMap.get(fragment.getSymbolicName());
+        if (fragList != null)
         {
-            m_fragmentMap.remove(fragment.getSymbolicName());
-        }
-        else
-        {
-            m_fragmentMap.put(fragment.getSymbolicName(), fragments);
-        }
-
-        // If we have any matching hosts, then remove  fragment while
-        // removing any older version of the new fragment. Also remove host's
-        // existing capabilities from the package index and reindex its new
-        // ones after attaching the fragment.
-        List matchingHosts = getMatchingHosts(fragment);
-        for (int hostIdx = 0; hostIdx < matchingHosts.size(); hostIdx++)
-        {
-            IModule host = ((ICapability) matchingHosts.get(hostIdx)).getModule();
-
-            // Check to see if the removed fragment was actually merged with
-            // the host, since it might not be if it wasn't the highest version.
-            // If it was, recalculate the fragments for the host.
-            fragments = ((ModuleImpl) host).getFragments();
-            for (int fragIdx = 0; (fragments != null) && (fragIdx < fragments.length); fragIdx++)
+            // Remove from fragment map.
+            fragList.remove(fragment);
+            if (fragList.size() == 0)
             {
-                if (!fragments[fragIdx].equals(fragment))
-                {
-                    List fragmentList = getMatchingFragments(host);
+                m_fragmentMap.remove(fragment.getSymbolicName());
+            }
 
-                    // Remove host's existing exported packages from index.
-                    ICapability[] caps = host.getCapabilities();
-                    for (int i = 0; (caps != null) && (i < caps.length); i++)
+            // If we have any matching hosts, then remove  fragment while
+            // removing any older version of the new fragment. Also remove host's
+            // existing capabilities from the package index and reindex its new
+            // ones after attaching the fragment.
+            List matchingHosts = getMatchingHosts(fragment);
+            for (int hostIdx = 0; hostIdx < matchingHosts.size(); hostIdx++)
+            {
+                IModule host = ((ICapability) matchingHosts.get(hostIdx)).getModule();
+
+                // Check to see if the removed fragment was actually merged with
+                // the host, since it might not be if it wasn't the highest version.
+                // If it was, recalculate the fragments for the host.
+                IModule[] fragments = ((ModuleImpl) host).getFragments();
+                for (int fragIdx = 0;
+                    (fragments != null) && (fragIdx < fragments.length);
+                    fragIdx++)
+                {
+                    if (!fragments[fragIdx].equals(fragment))
                     {
-                        if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                        List fragmentList = getMatchingFragments(host);
+
+                        // Remove host's existing exported packages from index.
+                        ICapability[] caps = host.getCapabilities();
+                        for (int i = 0; (caps != null) && (i < caps.length); i++)
                         {
-                            // Get package name.
-                            String pkgName = (String)
-                                caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
-                            // Remove from "unresolved" package map.
-                            IModule[] modules = (IModule[]) m_unresolvedPkgIndex.get(pkgName);
-                            if (modules != null)
+                            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
                             {
-                                modules = removeModuleFromArray(modules, host);
-                                m_unresolvedPkgIndex.put(pkgName, modules);
+                                // Get package name.
+                                String pkgName = (String)
+                                    caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
+                                // Remove from "unresolved" package map.
+                                List capList = (List) m_unresolvedPkgIndex.get(pkgName);
+                                if (capList != null)
+                                {
+                                    capList.remove(caps[i]);
+                                }
                             }
                         }
-                    }
 
-                    // Check if fragment conflicts with existing metadata.
-                    checkForConflicts(host, fragmentList);
+                        // Check if fragment conflicts with existing metadata.
+                        checkForConflicts(host, fragmentList);
 
-                    // Attach the fragments to the host.
-                    fragments = (fragmentList.size() == 0)
-                        ? null
-                        : (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]);
-                    try
-                    {
-                        ((ModuleImpl) host).attachFragments(fragments);
-                    }
-                    catch (Exception ex)
-                    {
-                        // Try to clean up by removing all fragments.
+                        // Attach the fragments to the host.
+                        fragments = (fragmentList.size() == 0)
+                            ? null
+                            : (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]);
                         try
                         {
-                            ((ModuleImpl) host).attachFragments(null);
+                            ((ModuleImpl) host).attachFragments(fragments);
                         }
-                        catch (Exception ex2)
+                        catch (Exception ex)
                         {
+                            // Try to clean up by removing all fragments.
+                            try
+                            {
+                                ((ModuleImpl) host).attachFragments(null);
+                            }
+                            catch (Exception ex2)
+                            {
+                            }
+                            m_logger.log(Logger.LOG_ERROR,
+                                "Serious error attaching fragments.", ex);
                         }
-                        m_logger.log(Logger.LOG_ERROR,
-                            "Serious error attaching fragments.", ex);
-                    }
 
-                    // Reindex the host's exported packages.
-                    caps = host.getCapabilities();
-                    for (int i = 0; (caps != null) && (i < caps.length); i++)
-                    {
-                        if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                        // Reindex the host's exported packages.
+                        caps = host.getCapabilities();
+                        for (int i = 0; (caps != null) && (i < caps.length); i++)
                         {
-                            indexPackageCapability(m_unresolvedPkgIndex, host, caps[i]);
+                            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                            {
+                                indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
+                            }
                         }
                     }
                 }
@@ -575,7 +572,7 @@
         {
             if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
             {
-                indexPackageCapability(m_unresolvedPkgIndex, host, caps[i]);
+                indexPackageCapability(m_unresolvedPkgIndex, caps[i]);
             }
         }
     }
@@ -597,25 +594,24 @@
                 String pkgName = (String)
                     caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
                 // Remove from "unresolved" package map.
-                IModule[] modules = (IModule[]) m_unresolvedPkgIndex.get(pkgName);
-                if (modules != null)
+                List capList = (List) m_unresolvedPkgIndex.get(pkgName);
+                if (capList != null)
                 {
-                    modules = removeModuleFromArray(modules, host);
-                    m_unresolvedPkgIndex.put(pkgName, modules);
+                    capList.remove(caps[i]);
                 }
 
                 // Remove from "resolved" package map.
-                modules = (IModule[]) m_resolvedPkgIndex.get(pkgName);
-                if (modules != null)
+                capList = (List) m_resolvedPkgIndex.get(pkgName);
+                if (capList != null)
                 {
-                    modules = removeModuleFromArray(modules, host);
-                    m_resolvedPkgIndex.put(pkgName, modules);
+                    capList.remove(caps[i]);
                 }
             }
         }
 
         // Remove the module from the "resolved" map.
         m_resolvedCapMap.remove(host);
+
         // Set fragments to null, which will remove the module from all
         // of its dependent fragment modules.
         try
@@ -643,14 +639,15 @@
         for (Iterator it = m_fragmentMap.entrySet().iterator(); (hostCap != null) && it.hasNext(); )
         {
             Map.Entry entry = (Map.Entry) it.next();
-            IModule[] fragments = ((IModule[]) entry.getValue());
+            List fragments = (List) entry.getValue();
             IModule fragment = null;
-            for (int i = 0; (fragment == null) && (i < fragments.length); i++)
+            for (int i = 0; (fragment == null) && (i < fragments.size()); i++)
             {
-                if (!((BundleImpl) fragments[i].getBundle()).isStale()
-                    && !((BundleImpl) fragments[i].getBundle()).isRemovalPending())
+                IModule f = (IModule) fragments.get(i);
+                if (!((BundleImpl) f.getBundle()).isStale()
+                    && !((BundleImpl) f.getBundle()).isRemovalPending())
                 {
-                    fragment = fragments[i];
+                    fragment = f;
                 }
             }
 
@@ -745,9 +742,15 @@
         ICapability[] caps = module.getCapabilities();
         for (int i = 0; (caps != null) && (i < caps.length); i++)
         {
-            ICapability[] resolvedCaps = (ICapability[]) m_resolvedCapMap.get(module);
-            resolvedCaps = addCapabilityToArray(resolvedCaps, caps[i]);
-            m_resolvedCapMap.put(module, resolvedCaps);
+            List resolvedCaps = (List) m_resolvedCapMap.get(module);
+            if (resolvedCaps == null)
+            {
+                m_resolvedCapMap.put(module, resolvedCaps = new ArrayList());
+            }
+            if (!resolvedCaps.contains(caps[i]))
+            {
+                resolvedCaps.add(caps[i]);
+            }
 
             // If the capability is a package, then add the exporter module
             // of the wire to the "resolved" package index and remove it
@@ -755,45 +758,25 @@
             if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
             {
                 // Add to "resolved" package index.
-                indexPackageCapability(m_resolvedPkgIndex, module, caps[i]);
+                indexPackageCapability(m_resolvedPkgIndex, caps[i]);
             }
         }
     }
 
-    private void dumpModuleIndexMap(Map moduleIndexMap)
+    private void dumpPackageIndex(Map pkgIndex)
     {
-        for (Iterator i = moduleIndexMap.entrySet().iterator(); i.hasNext(); )
+        for (Iterator i = pkgIndex.entrySet().iterator(); i.hasNext(); )
         {
             Map.Entry entry = (Map.Entry) i.next();
-            IModule[] modules = (IModule[]) entry.getValue();
-            if ((modules != null) && (modules.length > 0))
+            List capList = (List) entry.getValue();
+            if (capList.size() > 0)
             {
-                if (!((modules.length == 1) && modules[0].getId().equals("0")))
+                if (!((capList.size() == 1) && ((ICapability) capList.get(0)).getModule().getId().equals("0")))
                 {
                     System.out.println("  " + entry.getKey());
-                    for (int j = 0; j < modules.length; j++)
+                    for (int j = 0; j < capList.size(); j++)
                     {
-                        System.out.println("    " + modules[j]);
-                    }
-                }
-            }
-        }
-    }
-
-    private void dumpPackageIndexMap(Map pkgIndexMap)
-    {
-        for (Iterator i = pkgIndexMap.entrySet().iterator(); i.hasNext(); )
-        {
-            Map.Entry entry = (Map.Entry) i.next();
-            IModule[] modules = (IModule[]) entry.getValue();
-            if ((modules != null) && (modules.length > 0))
-            {
-                if (!((modules.length == 1) && modules[0].getId().equals("0")))
-                {
-                    System.out.println("  " + entry.getKey());
-                    for (int j = 0; j < modules.length; j++)
-                    {
-                        System.out.println("    " + modules[j]);
+                        System.out.println("    " + ((ICapability) capList.get(j)).getModule());
                     }
                 }
             }
@@ -828,11 +811,8 @@
                     String pkgName = (String)
                         caps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
                     // Remove the module's capability for the package.
-                    m_unresolvedPkgIndex.put(
-                        pkgName,
-                        removeModuleFromArray(
-                            (IModule[]) m_unresolvedPkgIndex.get(pkgName),
-                            module));
+                    List capList = (List) m_unresolvedPkgIndex.get(pkgName);
+                    capList.remove(caps[capIdx]);
                 }
             }
 
@@ -875,9 +855,15 @@
             {
                 if (capsCopy[capIdx] != null)
                 {
-                    ICapability[] resolvedCaps = (ICapability[]) m_resolvedCapMap.get(module);
-                    resolvedCaps = addCapabilityToArray(resolvedCaps, capsCopy[capIdx]);
-                    m_resolvedCapMap.put(module, resolvedCaps);
+                    List resolvedCaps = (List) m_resolvedCapMap.get(module);
+                    if (resolvedCaps == null)
+                    {
+                        m_resolvedCapMap.put(module, resolvedCaps = new ArrayList());
+                    }
+                    if (!resolvedCaps.contains(capsCopy[capIdx]))
+                    {
+                        resolvedCaps.add(capsCopy[capIdx]);
+                    }
 
                     // If the capability is a package, then add the exporter module
                     // of the wire to the "resolved" package index and remove it
@@ -885,51 +871,47 @@
                     if (capsCopy[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
                     {
                         // Add to "resolved" package index.
-                        indexPackageCapability(m_resolvedPkgIndex, module, capsCopy[capIdx]);
+                        indexPackageCapability(m_resolvedPkgIndex, capsCopy[capIdx]);
                     }
                 }
             }
         }
 
 //System.out.println("UNRESOLVED PACKAGES:");
-//dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+//dumpPackageIndex(m_unresolvedPkgIndex);
 //System.out.println("RESOLVED PACKAGES:");
-//dumpPackageIndexMap(m_resolvedPkgIndexMap);
+//dumpPackageIndex(m_resolvedPkgIndex);
     }
 
-    public synchronized ICapability[] getResolvedCandidates(IRequirement req)
+    public synchronized List getResolvedCandidates(IRequirement req)
     {
         // Synchronized on the module manager to make sure that no
         // modules are added, removed, or resolved.
-        ICapability[] candidates = m_emptyCandidates;
+        List candidates = new ArrayList();
         if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
             && (((Requirement) req).getTargetName() != null))
         {
             String pkgName = ((Requirement) req).getTargetName();
-            IModule[] modules = (IModule[]) m_resolvedPkgIndex.get(pkgName);
+            List capList = (List) m_resolvedPkgIndex.get(pkgName);
 
-            for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
+            for (int capIdx = 0; (capList != null) && (capIdx < capList.size()); capIdx++)
             {
-                ICapability resolvedCap = Util.getSatisfyingCapability(modules[modIdx], req);
-                if (resolvedCap != null)
+                ICapability cap = (ICapability) capList.get(capIdx);
+                if (req.isSatisfied(cap))
                 {
 // TODO: RB - Is this permission check correct.
                     if ((System.getSecurityManager() != null) &&
-                        !((BundleProtectionDomain) modules[modIdx].getSecurityContext()).impliesDirect(
-                            new PackagePermission(pkgName,
-                                PackagePermission.EXPORT)))
+                        !((BundleProtectionDomain) cap.getModule().getSecurityContext())
+                            .impliesDirect(new PackagePermission(pkgName, PackagePermission.EXPORT)))
                     {
                         m_logger.log(Logger.LOG_DEBUG,
                             "PackagePermission.EXPORT denied for "
                             + pkgName
-                            + "from " + modules[modIdx].getId());
+                            + "from " + cap.getModule().getId());
                     }
                     else
                     {
-                        ICapability[] tmp = new ICapability[candidates.length + 1];
-                        System.arraycopy(candidates, 0, tmp, 0, candidates.length);
-                        tmp[candidates.length] = resolvedCap;
-                        candidates = tmp;
+                        candidates.add(cap);
                     }
                 }
             }
@@ -941,70 +923,73 @@
             {
                 Map.Entry entry = (Map.Entry) i.next();
                 IModule module = (IModule) entry.getKey();
-                ICapability[] resolvedCaps = (ICapability[]) entry.getValue();
-                for (int capIdx = 0; capIdx < resolvedCaps.length; capIdx++)
+                List caps = (List) entry.getValue();
+                for (int capIdx = 0; (caps != null) && (capIdx < caps.size()); capIdx++)
                 {
-                    if (req.isSatisfied(resolvedCaps[capIdx]))
+                    ICapability cap = (ICapability) caps.get(capIdx);
+                    if (req.isSatisfied(cap))
                     {
 // TODO: RB - Is this permission check correct.
-                        if (resolvedCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+                        if (cap.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
                             (System.getSecurityManager() != null) &&
                             !((BundleProtectionDomain) module.getSecurityContext()).impliesDirect(
                                 new PackagePermission(
-                                    (String) resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY),
+                                    (String) cap.getProperties().get(ICapability.PACKAGE_PROPERTY),
                                     PackagePermission.EXPORT)))
                         {
                             m_logger.log(Logger.LOG_DEBUG,
                                 "PackagePermission.EXPORT denied for "
-                                + resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY)
+                                + cap.getProperties().get(ICapability.PACKAGE_PROPERTY)
                                 + "from " + module.getId());
                         }
                         else
                         {
-                            ICapability[] tmp = new ICapability[candidates.length + 1];
-                            System.arraycopy(candidates, 0, tmp, 0, candidates.length);
-                            tmp[candidates.length] = resolvedCaps[capIdx];
-                            candidates = tmp;
+                            candidates.add(cap);
                         }
                     }
                 }
             }
         }
-        Arrays.sort(candidates);
+        Collections.sort(candidates);
         return candidates;
     }
 
-    public synchronized ICapability[] getUnresolvedCandidates(IRequirement req)
+    public synchronized List getUnresolvedCandidates(IRequirement req)
     {
-        // Get all modules.
-        IModule[] modules = null;
+        // Get all matching unresolved capabilities.
+        List candidates = new ArrayList();
         if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
             (((Requirement) req).getTargetName() != null))
         {
-            modules = (IModule[]) m_unresolvedPkgIndex.get(((Requirement) req).getTargetName());
+            List capList = (List) m_unresolvedPkgIndex.get(((Requirement) req).getTargetName());
+            for (int capIdx = 0; (capList != null) && (capIdx < capList.size()); capIdx++)
+            {
+                // If compatible and it is not currently resolved, then add
+                // the unresolved candidate to the list.
+                if (req.isSatisfied((ICapability) capList.get(capIdx)))
+                {
+                    candidates.add(capList.get(capIdx));
+                }
+            }
         }
         else
         {
-            modules = getModules();
+            IModule[] modules = getModules();
+            for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
+            {
+                // Get the module's export package for the target package.
+                ICapability cap = Util.getSatisfyingCapability(modules[modIdx], req);
+                // If compatible and it is not currently resolved, then add
+                // the unresolved candidate to the list.
+                if ((cap != null) && !modules[modIdx].isResolved())
+                {
+                    candidates.add(cap);
+                }
+            }
         }
 
         // Create list of compatible providers.
-        ICapability[] candidates = m_emptyCandidates;
-        for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
-        {
-            // Get the module's export package for the target package.
-            ICapability cap = Util.getSatisfyingCapability(modules[modIdx], req);
-            // If compatible and it is not currently resolved, then add
-            // the unresolved candidate to the list.
-            if ((cap != null) && !modules[modIdx].isResolved())
-            {
-                ICapability[] tmp = new ICapability[candidates.length + 1];
-                System.arraycopy(candidates, 0, tmp, 0, candidates.length);
-                tmp[candidates.length] = cap;
-                candidates = tmp;
-            }
-        }
-        Arrays.sort(candidates);
+        Collections.sort(candidates);
         return candidates;
     }
 
@@ -1012,35 +997,34 @@
     // Utility methods.
     //
 
-    private void indexPackageCapability(Map map, IModule module, ICapability capability)
+    private void indexPackageCapability(Map map, ICapability capability)
     {
         if (capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
         {
             String pkgName = (String)
                 capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
-            IModule[] modules = (IModule[]) map.get(pkgName);
+            List capList = (List) map.get(pkgName);
 
-            // We want to add the module into the list of exporters
+            // We want to add the capability into the list of exporters
             // in sorted order (descending version and ascending bundle
             // identifier). Insert using a simple binary search algorithm.
-            if (modules == null)
+            if (capList == null)
             {
-                modules = new IModule[] { module };
+                capList = new ArrayList();
+                capList.add(capability);
             }
             else
             {
                 Version version = (Version)
                     capability.getProperties().get(ICapability.VERSION_PROPERTY);
                 Version middleVersion = null;
-                int top = 0, bottom = modules.length - 1, middle = 0;
+                int top = 0, bottom = capList.size() - 1, middle = 0;
                 while (top <= bottom)
                 {
                     middle = (bottom - top) / 2 + top;
                     middleVersion = (Version)
-                        getExportPackageCapability(
-                            modules[middle], pkgName)
-                                .getProperties()
-                                    .get(ICapability.VERSION_PROPERTY);
+                        ((ICapability) capList.get(middle))
+                            .getProperties().get(ICapability.VERSION_PROPERTY);
                     // Sort in reverse version order.
                     int cmp = middleVersion.compareTo(version);
                     if (cmp < 0)
@@ -1050,8 +1034,9 @@
                     else if (cmp == 0)
                     {
                         // Sort further by ascending bundle ID.
-                        long middleId = modules[middle].getBundle().getBundleId();
-                        long exportId = module.getBundle().getBundleId();
+                        long middleId = ((ICapability) capList.get(middle))
+                            .getModule().getBundle().getBundleId();
+                        long exportId = capability.getModule().getBundle().getBundleId();
                         if (middleId < exportId)
                         {
                             top = middle + 1;
@@ -1068,23 +1053,19 @@
                 }
 
                 // Ignore duplicates.
-                if ((top >= modules.length) || (modules[top] != module))
+                if ((top >= capList.size()) || (capList.get(top) != capability))
                 {
-                    IModule[] newMods = new IModule[modules.length + 1];
-                    System.arraycopy(modules, 0, newMods, 0, top);
-                    System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
-                    newMods[top] = module;
-                    modules = newMods;
+                    capList.add(top, capability);
                 }
             }
 
-            map.put(pkgName, modules);
+            map.put(pkgName, capList);
         }
     }
 
     private IModule indexFragment(Map map, IModule module)
     {
-        IModule[] modules = (IModule[]) map.get(module.getSymbolicName());
+        List modules = (List) map.get(module.getSymbolicName());
 
         // We want to add the fragment into the list of matching
         // fragments in sorted order (descending version and
@@ -1092,17 +1073,18 @@
         // binary search algorithm.
         if (modules == null)
         {
-            modules = new IModule[] { module };
+            modules = new ArrayList();
+            modules.add(module);
         }
         else
         {
             Version version = module.getVersion();
             Version middleVersion = null;
-            int top = 0, bottom = modules.length - 1, middle = 0;
+            int top = 0, bottom = modules.size() - 1, middle = 0;
             while (top <= bottom)
             {
                 middle = (bottom - top) / 2 + top;
-                middleVersion = modules[middle].getVersion();
+                middleVersion = ((IModule) modules.get(middle)).getVersion();
                 // Sort in reverse version order.
                 int cmp = middleVersion.compareTo(version);
                 if (cmp < 0)
@@ -1112,7 +1094,7 @@
                 else if (cmp == 0)
                 {
                     // Sort further by ascending bundle ID.
-                    long middleId = modules[middle].getBundle().getBundleId();
+                    long middleId = ((IModule) modules.get(middle)).getBundle().getBundleId();
                     long exportId = module.getBundle().getBundleId();
                     if (middleId < exportId)
                     {
@@ -1130,104 +1112,14 @@
             }
 
             // Ignore duplicates.
-            if ((top >= modules.length) || (modules[top] != module))
+            if ((top >= modules.size()) || (modules.get(top) != module))
             {
-                IModule[] newMods = new IModule[modules.length + 1];
-                System.arraycopy(modules, 0, newMods, 0, top);
-                System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
-                newMods[top] = module;
-                modules = newMods;
+                modules.add(top, module);
             }
         }
 
         map.put(module.getSymbolicName(), modules);
 
-        return modules[0];
-    }
-
-    private static IModule[] removeModuleFromArray(IModule[] modules, IModule m)
-    {
-        if (modules == null)
-        {
-            return m_emptyModules;
-        }
-
-        int idx = -1;
-        do
-        {
-            idx = -1;
-            for (int i = 0; i < modules.length; i++)
-            {
-                if (modules[i] == m)
-                {
-                    idx = i;
-                    break;
-                }
-            }
-
-            if (idx >= 0)
-            {
-                // If this is the module, then point to empty list.
-                if ((modules.length - 1) == 0)
-                {
-                    modules = m_emptyModules;
-                }
-                // Otherwise, we need to do some array copying.
-                else
-                {
-                    IModule[] newModules = new IModule[modules.length - 1];
-                    System.arraycopy(modules, 0, newModules, 0, idx);
-                    if (idx < newModules.length)
-                    {
-                        System.arraycopy(
-                            modules, idx + 1, newModules, idx, newModules.length - idx);
-                    }
-                    modules = newModules;
-                }
-            }
-        }
-        while (idx >= 0);
-
-        return modules;
-    }
-
-    public static ICapability getExportPackageCapability(IModule m, String pkgName)
-    {
-        ICapability[] caps = m.getCapabilities();
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
-        {
-            if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-                caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
-            {
-                return caps[i];
-            }
-        }
-        return null;
-    }
-
-    private static ICapability[] addCapabilityToArray(ICapability[] caps, ICapability cap)
-    {
-        // Verify that the capability is not already in the array.
-        for (int i = 0; (caps != null) && (i < caps.length); i++)
-        {
-            if (caps[i].equals(cap))
-            {
-                return caps;
-            }
-        }
-
-        if (caps != null)
-        {
-            ICapability[] newCaps = new ICapability[caps.length + 1];
-            System.arraycopy(caps, 0, newCaps, 0, caps.length);
-            newCaps[caps.length] = cap;
-            caps = newCaps;
-        }
-        else
-        {
-            caps = new ICapability[] { cap };
-        }
-
-        return caps;
+        return (IModule) modules.get(0);
     }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
index a294357..bc2757a 100644
--- a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
@@ -2166,12 +2166,12 @@
         {
             // This should never happen.
         }
-        ICapability[] exporters =
+        List exports =
             resolver.getResolvedCandidates(pkgReq);
-        exporters = (exporters.length == 0)
+        exports = (exports.size() == 0)
             ? resolver.getUnresolvedCandidates(pkgReq)
-            : exporters;
-        if (exporters.length > 0)
+            : exports;
+        if (exports.size() > 0)
         {
             boolean classpath = false;
             try
@@ -2188,7 +2188,7 @@
                 // Ignore
             }
 
-            long expId = exporters[0].getModule().getBundle().getBundleId();
+            long expId = ((ICapability) exports.get(0)).getModule().getBundle().getBundleId();
 
             StringBuffer sb = new StringBuffer("*** Class '");
             sb.append(name);
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
index 0873b3a..cdb36d3 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
@@ -158,17 +158,12 @@
             {
                 // Get "resolved" and "unresolved" candidates and put
                 // the "resolved" candidates first.
-                ICapability[] resolved = state.getResolvedCandidates(target);
-                ICapability[] unresolved = state.getUnresolvedCandidates(target);
-                ICapability[] candidates =
-                    new ICapability[resolved.length + unresolved.length];
-                System.arraycopy(resolved, 0, candidates, 0, resolved.length);
-                System.arraycopy(
-                    unresolved, 0, candidates, resolved.length, unresolved.length);
+                List candidates = state.getResolvedCandidates(target);
+                candidates.addAll(state.getUnresolvedCandidates(target));
 
                 // Take the first candidate that can resolve.
                 for (int candIdx = 0;
-                    (candidate == null) && (candIdx < candidates.length);
+                    (candidate == null) && (candIdx < candidates.size());
                     candIdx++)
                 {
                     try
@@ -177,10 +172,11 @@
                         // consistently with the importer.
                         resolvedModuleWireMap =
                             resolveDynamicImportCandidate(
-                                state, candidates[candIdx].getModule(), importer);
+                                state, ((ICapability) candidates.get(candIdx)).getModule(),
+                                importer);
                         if (resolvedModuleWireMap != null)
                         {
-                            candidate = candidates[candIdx];
+                            candidate = (ICapability) candidates.get(candIdx);
                         }
                     }
                     catch (ResolveException ex)
@@ -380,29 +376,26 @@
             // package maps. The "resolved" candidates have higher priority
             // than "unresolved" ones, so put the "resolved" candidates
             // at the front of the list of candidates.
-            ICapability[] resolved = state.getResolvedCandidates(reqs[reqIdx]);
-            ICapability[] unresolved = state.getUnresolvedCandidates(reqs[reqIdx]);
-            ICapability[] cand = new ICapability[resolved.length + unresolved.length];
-            System.arraycopy(resolved, 0, cand, 0, resolved.length);
-            System.arraycopy(unresolved, 0, cand, resolved.length, unresolved.length);
-            List candidates = new ArrayList(Arrays.asList(cand));
+            List candidates = state.getResolvedCandidates(reqs[reqIdx]);
+            candidates.addAll(state.getUnresolvedCandidates(reqs[reqIdx]));
 
             // If we have candidates, then we need to recursively populate
             // the resolver map with each of them.
             ResolveException rethrow = null;
             if (candidates.size() > 0)
             {
-                for (int candIdx = 0; candIdx < candidates.size(); candIdx++)
+                for (Iterator it = candidates.iterator(); it.hasNext(); )
                 {
+                    ICapability candidate = (ICapability) it.next();
+
                     try
                     {
                         // Only populate the resolver map with modules that
                         // are not already resolved.
-                        if (!((ICapability) candidates.get(candIdx)).getModule().isResolved())
+                        if (!candidate.getModule().isResolved())
                         {
                             populateCandidatesMap(
-                                state, candidatesMap,
-                                ((ICapability) candidates.get(candIdx)).getModule());
+                                state, candidatesMap, candidate.getModule());
                         }
                     }
                     catch (ResolveException ex)
@@ -411,8 +404,7 @@
                         // current candidate is not resolvable for some
                         // reason and should be removed from the list of
                         // candidates. For now, just null it.
-                        candidates.remove(candIdx);
-                        candIdx--;
+                        it.remove();
                         rethrow = ex;
                     }
                 }
@@ -1762,7 +1754,7 @@
     public static interface ResolverState
     {
         IModule[] getModules();
-        ICapability[] getResolvedCandidates(IRequirement req);
-        ICapability[] getUnresolvedCandidates(IRequirement req);
+        List getResolvedCandidates(IRequirement req);
+        List getUnresolvedCandidates(IRequirement req);
     }
 }
\ No newline at end of file