You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2010/03/03 16:04:42 UTC

svn commit: r918500 [2/4] - in /felix/trunk/framework/src/main/java/org/apache/felix: framework/ framework/capabilityset/ framework/resolver/ framework/searchpolicy/ moduleloader/

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java?rev=918500&r1=918499&r2=918500&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java Wed Mar  3 15:04:41 2010
@@ -18,8 +18,9 @@
  */
 package org.apache.felix.framework;
 
-import org.apache.felix.framework.searchpolicy.*;
-import org.apache.felix.moduleloader.*;
+import org.apache.felix.framework.resolver.ResourceNotFoundException;
+import org.apache.felix.framework.resolver.Content;
+import org.apache.felix.framework.capabilityset.SimpleFilter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Constructor;
@@ -31,7 +32,7 @@
 import java.security.ProtectionDomain;
 import java.security.SecureClassLoader;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -42,29 +43,37 @@
 import java.util.Vector;
 import org.apache.felix.framework.Felix.FelixResolver;
 import org.apache.felix.framework.cache.JarContent;
+import org.apache.felix.framework.capabilityset.Attribute;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Directive;
+import org.apache.felix.framework.resolver.Module;
+import org.apache.felix.framework.capabilityset.Requirement;
+import org.apache.felix.framework.resolver.Wire;
+import org.apache.felix.framework.resolver.ResolveException;
+import org.apache.felix.framework.resolver.WireImpl;
+import org.apache.felix.framework.resolver.WireModuleImpl;
 import org.apache.felix.framework.util.CompoundEnumeration;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.SecureAction;
 import org.apache.felix.framework.util.SecurityManagerEx;
 import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.Capability;
+import org.apache.felix.framework.util.manifestparser.CapabilityImpl;
 import org.apache.felix.framework.util.manifestparser.ManifestParser;
 import org.apache.felix.framework.util.manifestparser.R4Library;
-import org.apache.felix.framework.util.manifestparser.Requirement;
+import org.apache.felix.framework.util.manifestparser.RequirementImpl;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.BundleReference;
 import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.Version;
 
-public class ModuleImpl implements IModule
+public class ModuleImpl implements Module
 {
     private final Logger m_logger;
     private final Map m_configMap;
     private final FelixResolver m_resolver;
     private final String m_id;
-    private final IContent m_content;
+    private final Content m_content;
     private final Map m_headerMap;
     private final URLStreamHandler m_streamHandler;
 
@@ -73,28 +82,28 @@
     private final String m_symbolicName;
     private final Version m_version;
 
-    private final ICapability[] m_capabilities;
-    private ICapability[] m_cachedCapabilities = null;
-    private final IRequirement[] m_requirements;
-    private IRequirement[] m_cachedRequirements = null;
-    private final IRequirement[] m_dynamicRequirements;
-    private IRequirement[] m_cachedDynamicRequirements = null;
-    private final R4Library[] m_nativeLibraries;
+    private final List<Capability> m_capabilities;
+    private List<Capability> m_cachedCapabilities = null;
+    private final List<Requirement> m_requirements;
+    private List<Requirement> m_cachedRequirements = null;
+    private final List<Requirement> m_dynamicRequirements;
+    private List<Requirement> m_cachedDynamicRequirements = null;
+    private final List<R4Library> m_nativeLibraries;
     private final int m_declaredActivationPolicy;
-    private final String[] m_activationIncludes;
-    private final String[] m_activationExcludes;
+    private final List<String> m_activationIncludes;
+    private final List<String> m_activationExcludes;
 
     private final Bundle m_bundle;
 
-    private IModule[] m_fragments = null;
-    private IWire[] m_wires = null;
-    private IModule[] m_dependentHosts = new IModule[0];
-    private IModule[] m_dependentImporters = new IModule[0];
-    private IModule[] m_dependentRequirers = new IModule[0];
+    private List<Module> m_fragments = null;
+    private List<Wire> m_wires = null;
+    private List<Module> m_dependentHosts = new ArrayList<Module>(0);
+    private List<Module> m_dependentImporters = new ArrayList<Module>(0);
+    private List<Module> m_dependentRequirers = new ArrayList<Module>(0);
     private volatile boolean m_isResolved = false;
 
-    private IContent[] m_contentPath;
-    private IContent[] m_fragmentContents = null;
+    private Content[] m_contentPath;
+    private Content[] m_fragmentContents = null;
     private ModuleClassLoader m_classLoader;
     private boolean m_isActivationTriggered = false;
     private ProtectionDomain m_protectionDomain = null;
@@ -184,7 +193,7 @@
 
     public ModuleImpl(
         Logger logger, Map configMap, FelixResolver resolver,
-        Bundle bundle, String id, Map headerMap, IContent content,
+        Bundle bundle, String id, Map headerMap, Content content,
         URLStreamHandler streamHandler, String[] bootPkgs,
         boolean[] bootPkgWildcards)
         throws BundleException
@@ -269,163 +278,110 @@
         return m_version;
     }
 
-    public synchronized ICapability[] getCapabilities()
+    public synchronized List<Capability> getCapabilities()
     {
         if (m_cachedCapabilities == null)
         {
             List capList = (m_capabilities == null)
-                ? new ArrayList() : new ArrayList(Arrays.asList(m_capabilities));
+                ? new ArrayList<Capability>()
+                : new ArrayList<Capability>(m_capabilities);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                ICapability[] caps = m_fragments[fragIdx].getCapabilities();
+                List<Capability> caps = m_fragments.get(fragIdx).getCapabilities();
                 for (int capIdx = 0;
-                    (caps != null) && (capIdx < caps.length);
+                    (caps != null) && (capIdx < caps.size());
                     capIdx++)
                 {
-                    if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                    if (caps.get(capIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
                     {
                         capList.add(
-                            new Capability(
+                            new CapabilityImpl(
                                 this,
-                                caps[capIdx].getNamespace(),
-                                ((Capability) caps[capIdx]).getDirectives(),
-                                ((Capability) caps[capIdx]).getAttributes()));
+                                caps.get(capIdx).getNamespace(),
+                                caps.get(capIdx).getDirectives(),
+                                caps.get(capIdx).getAttributes()));
                     }
                 }
             }
-            m_cachedCapabilities = (ICapability[])
-                capList.toArray(new ICapability[capList.size()]);
+            m_cachedCapabilities = Collections.unmodifiableList(capList);
         }
         return m_cachedCapabilities;
     }
 
-    public synchronized IRequirement[] getRequirements()
+    public synchronized List<Requirement> getRequirements()
     {
         if (m_cachedRequirements == null)
         {
-            List allReqs = new ArrayList();
-            Map pkgMap = new HashMap();
-            Map rbMap = new HashMap();
-            for (int i = 0; (m_requirements != null) && i < m_requirements.length; i++)
-            {
-                if (m_requirements[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                {
-                    pkgMap.put(
-                        ((Requirement) m_requirements[i]).getTargetName(),
-                        m_requirements[i]);
-                }
-                else if (m_requirements[i].getNamespace().equals(ICapability.MODULE_NAMESPACE))
-                {
-                    rbMap.put(
-                        ((Requirement) m_requirements[i]).getTargetName(),
-                        m_requirements[i]);
-                }
-                else
-                {
-                    allReqs.add(m_requirements[i]);
-                }
-            }
-
-            // Aggregate host and fragment bundle and package requirements.
+            List<Requirement> reqList = (m_requirements == null)
+                ? new ArrayList() : new ArrayList(m_requirements);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                IRequirement[] reqs = m_fragments[fragIdx].getRequirements();
+                List<Requirement> reqs = m_fragments.get(fragIdx).getRequirements();
                 for (int reqIdx = 0;
-                    (reqs != null) && (reqIdx < reqs.length);
+                    (reqs != null) && (reqIdx < reqs.size());
                     reqIdx++)
                 {
-                    if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
-                    {
-                        // If the current fragment requirement overlaps a previously
-                        // added requirement, then calculate a new intersecting requirement.
-                        Requirement req = (Requirement) pkgMap.get(
-                            ((Requirement) reqs[reqIdx]).getTargetName());
-                        if (req != null)
-                        {
-                            req = FelixResolverState.calculateVersionIntersection(
-                                req, (Requirement) reqs[reqIdx]);
-                        }
-                        else
-                        {
-                            req = (Requirement) reqs[reqIdx];
-                        }
-                        pkgMap.put(req.getTargetName(), req);
-                    }
-                    else if (reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+                    if (reqs.get(reqIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+                        || reqs.get(reqIdx).getNamespace().equals(Capability.MODULE_NAMESPACE))
                     {
-                        // If the current fragment requirement overlaps a previously
-                        // added requirement, then calculate a new intersecting requirement.
-                        Requirement req = (Requirement) pkgMap.get(
-                            ((Requirement) reqs[reqIdx]).getTargetName());
-                        if (req != null)
-                        {
-                            req = FelixResolverState.calculateVersionIntersection(
-                                req, (Requirement) reqs[reqIdx]);
-                        }
-                        else
-                        {
-                            req = (Requirement) reqs[reqIdx];
-                        }
-                        rbMap.put(req.getTargetName(), req);
+                        reqList.add(
+                            new FragmentRequirement(
+                                reqs.get(reqIdx), m_fragments.get(fragIdx)));
                     }
                 }
             }
-            allReqs.addAll(pkgMap.values());
-            allReqs.addAll(rbMap.values());
-            m_cachedRequirements = (IRequirement[])
-                allReqs.toArray(new IRequirement[allReqs.size()]);
+            m_cachedRequirements = Collections.unmodifiableList(reqList);
         }
         return m_cachedRequirements;
     }
 
-    public synchronized IRequirement[] getDynamicRequirements()
+    public synchronized List<Requirement> getDynamicRequirements()
     {
         if (m_cachedDynamicRequirements == null)
         {
-            List reqList = (m_dynamicRequirements == null)
-                ? new ArrayList() : new ArrayList(Arrays.asList(m_dynamicRequirements));
+            List<Requirement> reqList = (m_dynamicRequirements == null)
+                ? new ArrayList() : new ArrayList(m_dynamicRequirements);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                IRequirement[] reqs = m_fragments[fragIdx].getDynamicRequirements();
+                List<Requirement> reqs = m_fragments.get(fragIdx).getDynamicRequirements();
                 for (int reqIdx = 0;
-                    (reqs != null) && (reqIdx < reqs.length);
+                    (reqs != null) && (reqIdx < reqs.size());
                     reqIdx++)
                 {
-                    if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+                    if (reqs.get(reqIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
                     {
-                        reqList.add(reqs[reqIdx]);
+                        reqList.add(reqs.get(reqIdx));
                     }
                 }
             }
-            m_cachedDynamicRequirements = (IRequirement[])
-                reqList.toArray(new IRequirement[reqList.size()]);
+            m_cachedDynamicRequirements = Collections.unmodifiableList(reqList);
         }
         return m_cachedDynamicRequirements;
     }
 
-    public synchronized R4Library[] getNativeLibraries()
+    public synchronized List<R4Library> getNativeLibraries()
     {
-        R4Library[] result = null;
+        List<R4Library> result = null;
         if (m_isResolved)
         {
-            List nativeList = (m_nativeLibraries == null)
-                ? new ArrayList() : new ArrayList(Arrays.asList(m_nativeLibraries));
+            List<R4Library> nativeList = (m_nativeLibraries == null)
+                ? new ArrayList() : new ArrayList(m_nativeLibraries);
             for (int fragIdx = 0;
-                (m_fragments != null) && (fragIdx < m_fragments.length);
+                (m_fragments != null) && (fragIdx < m_fragments.size());
                 fragIdx++)
             {
-                R4Library[] libs = m_fragments[fragIdx].getNativeLibraries();
+                List<R4Library> libs = m_fragments.get(fragIdx).getNativeLibraries();
                 for (int reqIdx = 0;
-                    (libs != null) && (reqIdx < libs.length);
+                    (libs != null) && (reqIdx < libs.size());
                     reqIdx++)
                 {
-                    nativeList.add(libs[reqIdx]);
+                    nativeList.add(libs.get(reqIdx));
                 }
             }
 
@@ -434,7 +390,7 @@
             // could not be found when resolving the bundle.
             result = (nativeList.size() == 0)
                 ? null
-                : (R4Library[]) nativeList.toArray(new R4Library[nativeList.size()]);
+                : Collections.unmodifiableList(nativeList);
         }
         else
         {
@@ -465,20 +421,20 @@
         // by default, otherwise try to find one match.
         boolean included = (m_activationIncludes == null);
         for (int i = 0;
-            (!included) && (m_activationIncludes != null) && (i < m_activationIncludes.length);
+            (!included) && (m_activationIncludes != null) && (i < m_activationIncludes.size());
             i++)
         {
-            included = m_activationIncludes[i].equals(pkgName);
+            included = m_activationIncludes.get(i).equals(pkgName);
         }
 
         // If there are no exclude filters then no classes are excluded
         // by default, otherwise try to find one match.
         boolean excluded = false;
         for (int i = 0;
-            (!excluded) && (m_activationExcludes != null) && (i < m_activationExcludes.length);
+            (!excluded) && (m_activationExcludes != null) && (i < m_activationExcludes.size());
             i++)
         {
-            excluded = m_activationExcludes[i].equals(pkgName);
+            excluded = m_activationExcludes.get(i).equals(pkgName);
         }
         return included && !excluded;
     }
@@ -497,40 +453,40 @@
         return m_id;
     }
 
-    public synchronized IWire[] getWires()
+    public synchronized List<Wire> getWires()
     {
         return m_wires;
     }
 
-    public synchronized void setWires(IWire[] wires)
+    public synchronized void setWires(List<Wire> wires)
     {
         // Remove module from old wire modules' dependencies,
         // since we are no longer dependent on any the moduels
         // from the old wires.
-        for (int i = 0; (m_wires != null) && (i < m_wires.length); i++)
+        for (int i = 0; (m_wires != null) && (i < m_wires.size()); i++)
         {
-            if (m_wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            if (m_wires.get(i).getCapability().getNamespace().equals(Capability.MODULE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).removeDependentRequirer(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).removeDependentRequirer(this);
             }
-            else if (m_wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            else if (m_wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).removeDependentImporter(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).removeDependentImporter(this);
             }
         }
 
         m_wires = wires;
 
         // Add ourself as a dependent to the new wires' modules.
-        for (int i = 0; (m_wires != null) && (i < m_wires.length); i++)
+        for (int i = 0; (m_wires != null) && (i < m_wires.size()); i++)
         {
-            if (m_wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
+            if (m_wires.get(i).getCapability().getNamespace().equals(Capability.MODULE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).addDependentRequirer(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).addDependentRequirer(this);
             }
-            else if (m_wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            else if (m_wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE))
             {
-                ((ModuleImpl) m_wires[i].getExporter()).addDependentImporter(this);
+                ((ModuleImpl) m_wires.get(i).getExporter()).addDependentImporter(this);
             }
         }
     }
@@ -549,12 +505,12 @@
     // Content access methods.
     //
 
-    public IContent getContent()
+    public Content getContent()
     {
         return m_content;
     }
 
-    private synchronized IContent[] getContentPath()
+    private synchronized Content[] getContentPath()
     {
         if (m_contentPath == null)
         {
@@ -570,19 +526,19 @@
         return m_contentPath;
     }
 
-    private IContent[] initializeContentPath() throws Exception
+    private Content[] initializeContentPath() throws Exception
     {
         List contentList = new ArrayList();
         calculateContentPath(this, m_content, contentList, true);
         for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
         {
-            calculateContentPath(m_fragments[i], m_fragmentContents[i], contentList, false);
+            calculateContentPath(m_fragments.get(i), m_fragmentContents[i], contentList, false);
         }
-        return (IContent[]) contentList.toArray(new IContent[contentList.size()]);
+        return (Content[]) contentList.toArray(new Content[contentList.size()]);
     }
 
     private List calculateContentPath(
-        IModule module, IContent content, List contentList, boolean searchFragments)
+        Module module, Content content, List contentList, boolean searchFragments)
         throws Exception
     {
         // Creating the content path entails examining the bundle's
@@ -596,25 +552,25 @@
         // Find class path meta-data.
         String classPath = (String) module.getHeaders().get(FelixConstants.BUNDLE_CLASSPATH);
         // Parse the class path into strings.
-        String[] classPathStrings = ManifestParser.parseDelimitedString(
+        List<String> classPathStrings = ManifestParser.parseDelimitedString(
             classPath, FelixConstants.CLASS_PATH_SEPARATOR);
 
         if (classPathStrings == null)
         {
-            classPathStrings = new String[0];
+            classPathStrings = new ArrayList<String>(0);
         }
 
         // Create the bundles class path.
-        for (int i = 0; i < classPathStrings.length; i++)
+        for (int i = 0; i < classPathStrings.size(); i++)
         {
             // Remove any leading slash, since all bundle class path
             // entries are relative to the root of the bundle.
-            classPathStrings[i] = (classPathStrings[i].startsWith("/"))
-                ? classPathStrings[i].substring(1)
-                : classPathStrings[i];
+            classPathStrings.set(i, (classPathStrings.get(i).startsWith("/"))
+                ? classPathStrings.get(i).substring(1)
+                : classPathStrings.get(i));
 
             // Check for the bundle itself on the class path.
-            if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
+            if (classPathStrings.get(i).equals(FelixConstants.CLASS_PATH_DOT))
             {
                 localContentList.add(content);
             }
@@ -622,7 +578,7 @@
             {
                 // Try to find the embedded class path entry in the current
                 // content.
-                IContent embeddedContent = content.getEntryAsContent(classPathStrings[i]);
+                Content embeddedContent = content.getEntryAsContent(classPathStrings.get(i));
                 // If the embedded class path entry was not found, it might be
                 // in one of the fragments if the current content is the bundle,
                 // so try to search the fragments if necessary.
@@ -631,7 +587,8 @@
                         && (m_fragmentContents != null) && (fragIdx < m_fragmentContents.length);
                     fragIdx++)
                 {
-                    embeddedContent = m_fragmentContents[fragIdx].getEntryAsContent(classPathStrings[i]);
+                    embeddedContent =
+                        m_fragmentContents[fragIdx].getEntryAsContent(classPathStrings.get(i));
                 }
                 // If we found the embedded content, then add it to the
                 // class path content list.
@@ -645,7 +602,7 @@
 //       need to create an "Eventer" class like "Logger" perhaps.
                     m_logger.log(Logger.LOG_INFO,
                         "Class path entry not found: "
-                        + classPathStrings[i]);
+                        + classPathStrings.get(i));
                 }
             }
         }
@@ -840,7 +797,7 @@
         }
 
         // Check the module class path.
-        IContent[] contentPath = getContentPath();
+        Content[] contentPath = getContentPath();
         for (int i = 0;
             (url == null) &&
             (i < contentPath.length); i++)
@@ -936,15 +893,15 @@
 
         // Note that the search may be aborted if this method throws an
         // exception, otherwise it continues if a null is returned.
-        IWire[] wires = getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        List<Wire> wires = getWires();
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
-            if (wires[i] instanceof R4Wire)
+            if (wires.get(i) instanceof WireImpl)
             {
                 try
                 {
                     // If we find the class or resource, then return it.
-                    urls = wires[i].getResources(name);
+                    urls = wires.get(i).getResources(name);
                 }
                 catch (ResourceNotFoundException ex)
                 {
@@ -962,14 +919,14 @@
         // See whether we can get the resource from the required bundles and
         // regardless of whether or not this is the case continue to the next
         // step potentially passing on the result of this search (if any).
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
-            if (wires[i] instanceof R4WireModule)
+            if (wires.get(i) instanceof WireModuleImpl)
             {
                 try
                 {
                     // If we find the class or resource, then add it.
-                    urls = wires[i].getResources(name);
+                    urls = wires.get(i).getResources(name);
                 }
                 catch (ResourceNotFoundException ex)
                 {
@@ -996,10 +953,10 @@
             // At this point, the module's imports were searched and so was the
             // the module's content. Now we make an attempt to load the
             // class/resource via a dynamic import, if possible.
-            IWire wire = null;
+            Wire wire = null;
             try
             {
-                wire = m_resolver.resolveDynamicImport(this, pkgName);
+                wire = m_resolver.resolve(this, pkgName);
             }
             catch (ResolveException ex)
             {
@@ -1033,7 +990,7 @@
         // Special case "/" so that it returns a root URLs for
         // each bundle class path entry...this isn't very
         // clean or meaningful, but the Spring guys want it.
-        final IContent[] contentPath = getContentPath();
+        final Content[] contentPath = getContentPath();
         if (name.equals("/"))
         {
             for (int i = 0; i < contentPath.length; i++)
@@ -1139,8 +1096,8 @@
 
          try
          {
-             return m_secureAction.createURL(null, 
-                 FelixConstants.BUNDLE_URL_PROTOCOL + "://" +  
+             return m_secureAction.createURL(null,
+                 FelixConstants.BUNDLE_URL_PROTOCOL + "://" +
                  m_id + ":" + port + path, m_streamHandler);
          }
          catch (MalformedURLException ex)
@@ -1157,19 +1114,19 @@
     // Fragment and dependency management methods.
     //
 
-    public synchronized IModule[] getFragments()
+    public synchronized List<Module> getFragments()
     {
         return m_fragments;
     }
 
-    public synchronized void attachFragments(IModule[] fragments) throws Exception
+    public synchronized void attachFragments(List<Module> fragments) throws Exception
     {
         // Remove module from old fragment dependencies.
         // We will generally only remove module fragment
         // dependencies when we are uninstalling the module.
-        for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+        for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++)
         {
-            ((ModuleImpl) m_fragments[i]).removeDependentHost(this);
+            ((ModuleImpl) m_fragments.get(i)).removeDependentHost(this);
         }
 
         // Remove cached capabilities and requirements.
@@ -1185,12 +1142,12 @@
         // to attach to our content loader.
         if (m_fragments != null)
         {
-            IContent[] fragmentContents = new IContent[m_fragments.length];
-            for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+            Content[] fragmentContents = new Content[m_fragments.size()];
+            for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++)
             {
-                ((ModuleImpl) m_fragments[i]).addDependentHost(this);
+                ((ModuleImpl) m_fragments.get(i)).addDependentHost(this);
                 fragmentContents[i] =
-                    m_fragments[i].getContent()
+                    m_fragments.get(i).getContent()
                         .getEntryAsContent(FelixConstants.CLASS_PATH_DOT);
             }
             // Now attach the fragment contents to our content loader.
@@ -1199,7 +1156,7 @@
     }
 
     // This must be called holding the object lock.
-    private void attachFragmentContents(IContent[] fragmentContents)
+    private void attachFragmentContents(Content[] fragmentContents)
         throws Exception
     {
         // Close existing fragment contents.
@@ -1222,121 +1179,68 @@
         m_contentPath = initializeContentPath();
     }
 
-    public synchronized IModule[] getDependentHosts()
+    public synchronized List<Module> getDependentHosts()
     {
         return m_dependentHosts;
     }
 
-    public synchronized void addDependentHost(IModule module)
+    public synchronized void addDependentHost(Module module)
     {
-        m_dependentHosts = addDependent(m_dependentHosts, module);
+        if (!m_dependentHosts.contains(module))
+        {
+            m_dependentHosts.add(module);
+        }
     }
 
-    public synchronized void removeDependentHost(IModule module)
+    public synchronized void removeDependentHost(Module module)
     {
-        m_dependentHosts = removeDependent(m_dependentHosts, module);
+        m_dependentHosts.remove(module);
     }
 
-    public synchronized IModule[] getDependentImporters()
+    public synchronized List<Module> getDependentImporters()
     {
         return m_dependentImporters;
     }
 
-    public synchronized void addDependentImporter(IModule module)
+    public synchronized void addDependentImporter(Module module)
     {
-        m_dependentImporters = addDependent(m_dependentImporters, module);
+        if (!m_dependentImporters.contains(module))
+        {
+            m_dependentImporters.add(module);
+        }
     }
 
-    public synchronized void removeDependentImporter(IModule module)
+    public synchronized void removeDependentImporter(Module module)
     {
-        m_dependentImporters = removeDependent(m_dependentImporters, module);
+        m_dependentImporters.remove(module);
     }
 
-    public synchronized IModule[] getDependentRequirers()
+    public synchronized List<Module> getDependentRequirers()
     {
         return m_dependentRequirers;
     }
 
-    public synchronized void addDependentRequirer(IModule module)
+    public synchronized void addDependentRequirer(Module module)
     {
-        m_dependentRequirers = addDependent(m_dependentRequirers, module);
-    }
-
-    public synchronized void removeDependentRequirer(IModule module)
-    {
-        m_dependentRequirers = removeDependent(m_dependentRequirers, module);
-    }
-
-    public synchronized IModule[] getDependents()
-    {
-        IModule[] dependents = new IModule[
-            m_dependentHosts.length + m_dependentImporters.length + m_dependentRequirers.length];
-        System.arraycopy(
-            m_dependentHosts,
-            0,
-            dependents,
-            0,
-            m_dependentHosts.length);
-        System.arraycopy(
-            m_dependentImporters,
-            0,
-            dependents,
-            m_dependentHosts.length,
-            m_dependentImporters.length);
-        System.arraycopy(
-            m_dependentRequirers,
-            0,
-            dependents,
-            m_dependentHosts.length + m_dependentImporters.length,
-            m_dependentRequirers.length);
-        return dependents;
-    }
-
-    private static IModule[] addDependent(IModule[] modules, IModule module)
-    {
-        // Make sure the dependent module is not already present.
-        for (int i = 0; i < modules.length; i++)
+        if (!m_dependentRequirers.contains(module))
         {
-            if (modules[i].equals(module))
-            {
-                return modules;
-            }
+            m_dependentRequirers.add(module);
         }
-        IModule[] tmp = new IModule[modules.length + 1];
-        System.arraycopy(modules, 0, tmp, 0, modules.length);
-        tmp[modules.length] = module;
-        return tmp;
     }
 
-    private static IModule[] removeDependent(IModule[] modules, IModule module)
+    public synchronized void removeDependentRequirer(Module module)
     {
-        IModule[] tmp = modules;
-
-        // Make sure the dependent module is present.
-        for (int i = 0; i < modules.length; i++)
-        {
-            if (modules[i].equals(module))
-            {
-                // If this is the module, then point to empty list.
-                if ((modules.length - 1) == 0)
-                {
-                    tmp = new IModule[0];
-                }
-                // Otherwise, we need to do some array copying.
-                else
-                {
-                    tmp = new IModule[modules.length - 1];
-                    System.arraycopy(modules, 0, tmp, 0, i);
-                    if (i < tmp.length)
-                    {
-                        System.arraycopy(modules, i + 1, tmp, i, tmp.length - i);
-                    }
-                }
-                break;
-            }
-        }
+        m_dependentRequirers.remove(module);
+    }
 
-        return tmp;
+    public synchronized List<Module> getDependents()
+    {
+        List<Module> dependents = new ArrayList<Module>
+            (m_dependentHosts.size() + m_dependentImporters.size() + m_dependentRequirers.size());
+        dependents.addAll(m_dependentHosts);
+        dependents.addAll(m_dependentImporters);
+        dependents.addAll(m_dependentRequirers);
+        return dependents;
     }
 
     public synchronized void close()
@@ -1433,13 +1337,13 @@
         throws ClassNotFoundException, ResourceNotFoundException
     {
         // We delegate to the module's wires to find the class or resource.
-        IWire[] wires = getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        List<Wire> wires = getWires();
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
             // If we find the class or resource, then return it.
             Object result = (isClass)
-                ? (Object) wires[i].getClass(name)
-                : (Object) wires[i].getResource(name);
+                ? (Object) wires.get(i).getClass(name)
+                : (Object) wires.get(i).getResource(name);
             if (result != null)
             {
                 return result;
@@ -1456,10 +1360,10 @@
         // At this point, the module's imports were searched and so was the
         // the module's content. Now we make an attempt to load the
         // class/resource via a dynamic import, if possible.
-        IWire wire = null;
+        Wire wire = null;
         try
         {
-            wire = m_resolver.resolveDynamicImport(this, pkgName);
+            wire = m_resolver.resolve(this, pkgName);
         }
         catch (ResolveException ex)
         {
@@ -1772,8 +1676,8 @@
                 byte[] bytes = null;
 
                 // Check the module class path.
-                IContent[] contentPath = getContentPath();
-                IContent content = null;
+                Content[] contentPath = getContentPath();
+                Content content = null;
                 for (int i = 0;
                     (bytes == null) &&
                     (i < contentPath.length); i++)
@@ -1799,7 +1703,7 @@
                             int activationPolicy = 
                                 ((BundleImpl) getBundle()).isDeclaredActivationPolicyUsed()
                                 ? ((BundleImpl) getBundle()).getCurrentModule().getDeclaredActivationPolicy()
-                                : IModule.EAGER_ACTIVATION;
+                                : Module.EAGER_ACTIVATION;
 
                             // If the module is using deferred activation, then if
                             // we load this class from this module we need to activate
@@ -1810,7 +1714,7 @@
                                 ? false : isActivationTrigger(pkgName);
                             if (!m_isActivationTriggered
                                 && isTriggerClass
-                                && (activationPolicy == IModule.LAZY_ACTIVATION)
+                                && (activationPolicy == Module.LAZY_ACTIVATION)
                                 && (getBundle().getState() == Bundle.STARTING))
                             {
                                 List deferredList = (List) m_deferredActivation.get();
@@ -2027,14 +1931,14 @@
                 // native library.
                 if (result == null)
                 {
-                    R4Library[] libs = getNativeLibraries();
-                    for (int libIdx = 0; (libs != null) && (libIdx < libs.length); libIdx++)
+                    List<R4Library> libs = getNativeLibraries();
+                    for (int libIdx = 0; (libs != null) && (libIdx < libs.size()); libIdx++)
                     {
-                        if (libs[libIdx].match(m_configMap, name))
+                        if (libs.get(libIdx).match(m_configMap, name))
                         {
                             // Search bundle content first for native library.
                             result = getContent().getEntryAsNativeLibrary(
-                                libs[libIdx].getEntryName());
+                                libs.get(libIdx).getEntryName());
                             // If not found, then search fragments in order.
                             for (int i = 0;
                                 (result == null) && (m_fragmentContents != null)
@@ -2042,7 +1946,7 @@
                                 i++)
                             {
                                 result = m_fragmentContents[i].getEntryAsNativeLibrary(
-                                    libs[libIdx].getEntryName());
+                                    libs.get(libIdx).getEntryName());
                             }
                         }
                     }
@@ -2084,13 +1988,13 @@
         String importer = module.getBundle().toString();
 
         // Next, check to see if the module imports the package.
-        IWire[] wires = module.getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        List<Wire> wires = module.getWires();
+        for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
-            if (wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-                wires[i].getCapability().getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
+            if (wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE) &&
+                wires.get(i).getCapability().getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
             {
-                String exporter = wires[i].getExporter().getBundle().toString();
+                String exporter = wires.get(i).getExporter().getBundle().toString();
 
                 StringBuffer sb = new StringBuffer("*** Package '");
                 sb.append(pkgName);
@@ -2114,7 +2018,7 @@
 
         // Next, check to see if the package was optionally imported and
         // whether or not there is an exporter available.
-        IRequirement[] reqs = module.getRequirements();
+        List<Requirement> reqs = module.getRequirements();
 /*
 * TODO: RB - Fix diagnostic message for optional imports.
         for (int i = 0; (reqs != null) && (i < reqs.length); i++)
@@ -2174,7 +2078,9 @@
         }
 */
         // Next, check to see if the package is dynamically imported by the module.
-        IRequirement pkgReq = Resolver.findAllowedDynamicImport(module, pkgName);
+// TODO: FELIX3 - Add Resolver.findAllowedDynamicImport().
+/*
+        Requirement pkgReq = Resolver.findAllowedDynamicImport(module, pkgName);
         if (pkgReq != null)
         {
             // Try to see if there is an exporter available.
@@ -2228,22 +2134,14 @@
 
             return sb.toString();
         }
-
+*/
         // Next, check to see if there are any exporters for the package at all.
-        pkgReq = null;
-        try
-        {
-            pkgReq = new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
-        }
-        catch (InvalidSyntaxException ex)
-        {
-            // This should never happen.
-        }
-        List exports =
-            resolver.getResolvedCandidates(pkgReq, module);
-        exports = (exports.size() == 0)
-            ? resolver.getUnresolvedCandidates(pkgReq, module)
-            : exports;
+        Requirement pkgReq = null;
+        List<Attribute> attrs = new ArrayList(1);
+        attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
+        pkgReq = new RequirementImpl(
+            Capability.PACKAGE_NAMESPACE, new ArrayList<Directive>(0), attrs);
+        Set<Capability> exports = resolver.getCandidates(module, pkgReq, false);
         if (exports.size() > 0)
         {
             boolean classpath = false;
@@ -2261,7 +2159,7 @@
                 // Ignore
             }
 
-            String exporter = ((ICapability) exports.get(0)).getModule().getBundle().toString();
+            String exporter = exports.iterator().next().getModule().getBundle().toString();
 
             StringBuffer sb = new StringBuffer("*** Class '");
             sb.append(name);
@@ -2345,4 +2243,46 @@
 
         return sb.toString();
     }
-}
+
+    static class FragmentRequirement implements Requirement
+    {
+        private final Requirement m_req;
+        private final Module m_fragment;
+
+        public FragmentRequirement(Requirement req, Module fragment)
+        {
+            m_req = req;
+            m_fragment = fragment;
+        }
+
+        public Module getFragment()
+        {
+            return m_fragment;
+        }
+
+        public String getNamespace()
+        {
+            return m_req.getNamespace();
+        }
+
+        public SimpleFilter getFilter()
+        {
+            return m_req.getFilter();
+        }
+
+        public boolean isOptional()
+        {
+            return m_req.isOptional();
+        }
+
+        public Directive getDirective(String name)
+        {
+            return m_req.getDirective(name);
+        }
+
+        public List<Directive> getDirectives()
+        {
+            return m_req.getDirectives();
+        }
+    }
+}
\ No newline at end of file

Added: felix/trunk/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java?rev=918500&view=auto
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java (added)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java Wed Mar  3 15:04:41 2010
@@ -0,0 +1,499 @@
+/*
+ *  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.capabilityset;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class CapabilitySet
+{
+    private final Map<String, Map<Object, Set<Capability>>> m_indices =
+        new HashMap<String, Map<Object, Set<Capability>>>();
+    private final Set<Capability> m_capList = new HashSet<Capability>();
+
+    public CapabilitySet(List<String> indexProps)
+    {
+        for (int i = 0; (indexProps != null) && (i < indexProps.size()); i++)
+        {
+            m_indices.put(indexProps.get(i), new HashMap<Object, Set<Capability>>());
+        }
+    }
+
+    public void addCapability(Capability cap)
+    {
+        m_capList.add(cap);
+
+        // Index capability.
+        for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+        {
+            Attribute capAttr = cap.getAttribute(entry.getKey());
+            if (capAttr != null)
+            {
+                Object capValue = capAttr.getValue();
+                if (capValue.getClass().isArray())
+                {
+                    capValue = convertArrayToList(capValue);
+                }
+
+                Map<Object, Set<Capability>> index = entry.getValue();
+
+                if (capValue instanceof Collection)
+                {
+                    Collection c = (Collection) capValue;
+                    for (Object o : c)
+                    {
+                        indexCapability(index, cap, o);
+                    }
+                }
+                else
+                {
+                    indexCapability(index, cap, capValue);
+                }
+            }
+        }
+
+//        System.out.println("+++ INDICES " + m_indices);
+    }
+
+    private void indexCapability(
+        Map<Object, Set<Capability>> index, Capability cap, Object capValue)
+    {
+        Set<Capability> caps = index.get(capValue);
+        if (caps == null)
+        {
+            caps = new HashSet<Capability>();
+            index.put(capValue, caps);
+        }
+        caps.add(cap);
+    }
+
+    public void removeCapability(Capability cap)
+    {
+        if (m_capList.remove(cap))
+        {
+            for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+            {
+                Attribute capAttr = cap.getAttribute(entry.getKey());
+                if (capAttr != null)
+                {
+                    Object capValue = capAttr.getValue();
+                    if (capValue.getClass().isArray())
+                    {
+                        capValue = convertArrayToList(capValue);
+                    }
+
+                    Map<Object, Set<Capability>> index = entry.getValue();
+
+                    if (capValue instanceof Collection)
+                    {
+                        Collection c = (Collection) capValue;
+                        for (Object o : c)
+                        {
+                            deindexCapability(index, cap, o);
+                        }
+                    }
+                    else
+                    {
+                        deindexCapability(index, cap, capValue);
+                    }
+                }
+            }
+
+//            System.out.println("+++ INDICES " + m_indices);
+        }
+    }
+
+    private void deindexCapability(
+        Map<Object, Set<Capability>> index, Capability cap, Object capValue)
+    {
+        Set<Capability> caps = index.get(capValue);
+        caps.remove(cap);
+        if (caps.size() == 0)
+        {
+            index.remove(capValue);
+        }
+    }
+
+    public Set<Capability> match(SimpleFilter sf, boolean obeyMandatory)
+    {
+        Set<Capability> matches = match(m_capList, sf);
+        return (obeyMandatory)
+            ? matchMandatory(matches, sf)
+            : matches;
+    }
+
+    private Set<Capability> match(Set<Capability> caps, SimpleFilter sf)
+    {
+//System.out.println("+++ SF " + sf);
+        Set<Capability> matches = new HashSet<Capability>();
+
+        if (sf.getOperation() == SimpleFilter.AND)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For AND we calculate the intersection of each subfilter.
+            // We can short-circuit the AND operation if there are no
+            // remaining capabilities.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; (caps.size() > 0) && (i < sfs.size()); i++)
+            {
+//System.out.println("+++ REMAINING " + caps);
+                matches = match(caps, sfs.get(i));
+//System.out.println("+++ CURRENT " + matches);
+                caps = matches;
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.OR)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.addAll(match(caps, sfs.get(i)));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.NOT)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            matches.addAll(caps);
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.removeAll(match(caps, sfs.get(i)));
+            }
+        }
+        else
+        {
+            Map<Object, Set<Capability>> index = m_indices.get(sf.getName());
+            if ((sf.getOperation() == SimpleFilter.EQ) && (index != null))
+            {
+                Set<Capability> existingCaps = index.get(sf.getValue());
+                if (existingCaps != null)
+                {
+                    matches.addAll(existingCaps);
+//System.out.println("NARROWED " + caps.size() + " TO " + existingCaps.size());
+                    matches.retainAll(caps);
+                }
+            }
+            else
+            {
+//                System.out.println("+++ SEARCHING " + caps.size() + " CAPABILITIES");
+                for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+                {
+                    Capability cap = it.next();
+                    Attribute attr = cap.getAttribute(sf.getName());
+                    if (attr != null)
+                    {
+                        Object lhs = attr.getValue();
+                        if (compare(lhs, sf.getValue(), sf.getOperation()))
+                        {
+                            matches.add(cap);
+                        }
+                    }
+                }
+            }
+        }
+
+        return matches;
+    }
+
+    public static boolean matches(Capability cap, SimpleFilter sf)
+    {
+        return matchesInternal(cap, sf) && matchMandatory(cap, sf);
+    }
+
+    private static boolean matchesInternal(Capability cap, SimpleFilter sf)
+    {
+        boolean matched = true;
+
+        if (sf.getOperation() == SimpleFilter.AND)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For AND we calculate the intersection of each subfilter.
+            // We can short-circuit the AND operation if there are no
+            // remaining capabilities.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; matched && (i < sfs.size()); i++)
+            {
+                matched = matchesInternal(cap, sfs.get(i));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.OR)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            matched = false;
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; !matched && (i < sfs.size()); i++)
+            {
+                matched = matchesInternal(cap, sfs.get(i));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.NOT)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matched = !(matchesInternal(cap, sfs.get(i)));
+            }
+        }
+        else
+        {
+            matched = false;
+            Attribute attr = cap.getAttribute(sf.getName());
+            if (attr != null)
+            {
+                Object lhs = attr.getValue();
+                matched = compare(lhs, sf.getValue(), sf.getOperation());
+            }
+        }
+
+        return matched;
+    }
+
+    private static Set<Capability> matchMandatory(Set<Capability> caps, SimpleFilter sf)
+    {
+        for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+        {
+            Capability cap = it.next();
+            if (!matchMandatory(cap, sf))
+            {
+                it.remove();
+            }
+        }
+        return caps;
+    }
+
+    private static boolean matchMandatory(Capability cap, SimpleFilter sf)
+    {
+        List<Attribute> attrs = cap.getAttributes();
+        for (int attrIdx = 0; attrIdx < attrs.size(); attrIdx++)
+        {
+            if (attrs.get(attrIdx).isMandatory()
+                && !matchMandatory(attrs.get(attrIdx), sf))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean matchMandatory(Attribute attr, SimpleFilter sf)
+    {
+        if ((sf.getName() != null) && sf.getName().equals(attr.getName()))
+        {
+            return true;
+        }
+        else if (sf.getOperation() == SimpleFilter.AND)
+        {
+            List list = (List) sf.getValue();
+            for (int i = 0; i < list.size(); i++)
+            {
+                SimpleFilter sf2 = (SimpleFilter) list.get(i);
+                if ((sf2.getName() != null)
+                    && sf2.getName().equals(attr.getName()))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static final Class[] STRING_CLASS = new Class[] { String.class };
+
+    private static boolean compare(Object lhs, Object rhsUnknown, int op)
+    {
+        // If the type is comparable, then we can just return the
+        // result immediately.
+        if (lhs instanceof Comparable)
+        {
+            // The substring operator only works on string values, so if the
+            // lhs is not a string, then do an equality comparison using the
+            // original string containing wildcards.
+            if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
+            {
+                op = SimpleFilter.EQ;
+                rhsUnknown = SimpleFilter.unparseSubstring((List<String>) rhsUnknown);
+            }
+
+            Object rhs;
+            if (op == SimpleFilter.SUBSTRING)
+            {
+                rhs = rhsUnknown;
+            }
+            else
+            {
+                try
+                {
+                    rhs = coerceType(lhs, (String) rhsUnknown);
+                }
+                catch (Exception ex)
+                {
+                    return false;
+                }
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                    return (((Comparable) lhs).compareTo(rhs) == 0);
+                case SimpleFilter.GTE :
+                    return (((Comparable) lhs).compareTo(rhs) >= 0);
+                case SimpleFilter.LTE :
+                    return (((Comparable) lhs).compareTo(rhs) <= 0);
+//                case SimpleFilter.APPROX :
+//                    return compareToApprox(((Comparable) lhs), rhs);
+                case SimpleFilter.SUBSTRING :
+                    return SimpleFilter.compareSubstring((String) lhs, (List<String>) rhs);
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+        // Booleans do not implement comparable, so special case them.
+        else if (lhs instanceof Boolean)
+        {
+            Object rhs;
+            try
+            {
+                rhs = coerceType(lhs, (String) rhsUnknown);
+            }
+            catch (Exception ex)
+            {
+                return false;
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                case SimpleFilter.GTE :
+                case SimpleFilter.LTE :
+//                case SimpleFilter.APPROX:
+                    return (lhs.equals(rhs));
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+
+        // If the LHS is not a comparable or boolean, check if it is an
+        // array. If so, convert it to a list so we can treat it as a
+        // collection.
+        if (lhs.getClass().isArray())
+        {
+            lhs = convertArrayToList(lhs);
+        }
+
+        // If LHS is a collection, then call compare() on each element
+        // of the collection until a match is found.
+        if (lhs instanceof Collection)
+        {
+            for (Iterator iter = ((Collection) lhs).iterator(); iter.hasNext(); )
+            {
+                if (compare(iter.next(), rhsUnknown, op))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        // Since we cannot identify the LHS type, then we can only perform
+        // equality comparison.
+        try
+        {
+            return lhs.equals(coerceType(lhs, (String) rhsUnknown));
+        }
+        catch (Exception ex)
+        {
+            return false;
+        }
+    }
+
+    private static Object coerceType(Object lhs, String rhsString) throws Exception
+    {
+        // If the LHS expects a string, then we can just return
+        // the RHS since it is a string.
+        if (lhs.getClass() == rhsString.getClass())
+        {
+            return rhsString;
+        }
+
+        // Try to convert the RHS type to the LHS type by using
+        // the string constructor of the LHS class, if it has one.
+        Object rhs = null;
+        try
+        {
+            // The Character class is a special case, since its constructor
+            // does not take a string, so handle it separately.
+            if (lhs instanceof Character)
+            {
+                rhs = new Character(rhsString.charAt(0));
+            }
+            else
+            {
+                rhs = lhs.getClass()
+                    .getConstructor(STRING_CLASS)
+                        .newInstance(new Object[] { rhsString });
+            }
+        }
+        catch (Exception ex)
+        {
+            throw new Exception(
+                "Could not instantiate class "
+                    + lhs.getClass().getName()
+                    + " from string constructor with argument '"
+                    + rhsString + "' because " + ex);
+        }
+
+        return rhs;
+    }
+
+    /**
+     * This is an ugly utility method to convert an array of primitives
+     * to an array of primitive wrapper objects. This method simplifies
+     * processing LDAP filters since the special case of primitive arrays
+     * can be ignored.
+     * @param array An array of primitive types.
+     * @return An corresponding array using pritive wrapper objects.
+    **/
+    private static List convertArrayToList(Object array)
+    {
+        int len = Array.getLength(array);
+        List list = new ArrayList(len);
+        for (int i = 0; i < len; i++)
+        {
+            list.add(Array.get(array, i));
+        }
+        return list;
+    }
+}
\ No newline at end of file

Added: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java?rev=918500&view=auto
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java (added)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java Wed Mar  3 15:04:41 2010
@@ -0,0 +1,103 @@
+/*
+ *  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.Comparator;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+public class CandidateComparator implements Comparator
+{
+    public int compare(Object arg1, Object arg2)
+    {
+        Capability cap1 = (Capability) arg1;
+        Capability cap2 = (Capability) arg2;
+
+        // First check resolved state, since resolved capabilities have priority
+        // over unresolved ones. Compare in reverse order since we want to sort
+        // in descending order.
+        int c = 0;
+        if (cap1.getModule().isResolved() && !cap2.getModule().isResolved())
+        {
+            c = -1;
+        }
+        else if (!cap1.getModule().isResolved() && cap2.getModule().isResolved())
+        {
+            c = 1;
+        }
+
+        // Next compare version numbers.
+        if ((c == 0) && cap1.getNamespace().equals(Capability.MODULE_NAMESPACE))
+        {
+            c = ((Comparable) cap1.getAttribute(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
+                .getValue()).compareTo(cap2.getAttribute(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
+                    .getValue());
+            if (c == 0)
+            {
+                Version v1 = (cap1.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE) == null)
+                    ? Version.emptyVersion
+                    : (Version) cap1.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE).getValue();
+                Version v2 = (cap2.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE) == null)
+                    ? Version.emptyVersion
+                    : (Version) cap2.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE).getValue();
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = v2.compareTo(v1);
+            }
+        }
+// TODO: PROTO3 RESOLVER - Need to change this to handle arbitrary capabilities
+//       that may not have a natural ordering.
+        // Assume everything else is a package capability.
+        else if (c == 0)
+        {
+            c = ((Comparable) cap1.getAttribute(Capability.PACKAGE_ATTR).getValue())
+                .compareTo(cap2.getAttribute(Capability.PACKAGE_ATTR).getValue());
+            if (c == 0)
+            {
+                Version v1 = (cap1.getAttribute(Capability.VERSION_ATTR) == null)
+                    ? Version.emptyVersion
+                    : (Version) cap1.getAttribute(Capability.VERSION_ATTR).getValue();
+                Version v2 = (cap2.getAttribute(Capability.VERSION_ATTR) == null)
+                    ? Version.emptyVersion
+                    : (Version) cap2.getAttribute(Capability.VERSION_ATTR).getValue();
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = v2.compareTo(v1);
+            }
+        }
+
+        // Finally, compare module identity.
+        if (c == 0)
+        {
+            if (cap1.getModule().getBundle().getBundleId() <
+                cap2.getModule().getBundle().getBundleId())
+            {
+                c = -1;
+            }
+            else if (cap1.getModule().getBundle().getBundleId() >
+                cap2.getModule().getBundle().getBundleId())
+            {
+                c = 1;
+            }
+        }
+
+        return c;
+    }
+}
\ No newline at end of file

Copied: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Content.java (from r915677, felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IContent.java)
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Content.java?p2=felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Content.java&p1=felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IContent.java&r1=915677&r2=918500&rev=918500&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IContent.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Content.java Wed Mar  3 15:04:41 2010
@@ -16,13 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.moduleloader;
+package org.apache.felix.framework.resolver;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Enumeration;
 
-public interface IContent
+public interface Content
 {
     /**
      * <p>
@@ -93,7 +93,7 @@
      * @return An <tt>IContent</tt> instance if a corresponding entry was found,
      *         <tt>null</tt> otherwise.
     **/
-    IContent getEntryAsContent(String name);
+    Content getEntryAsContent(String name);
 
     /**
      * <p>

Copied: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Module.java (from r915677, felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IModule.java)
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Module.java?p2=felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Module.java&p1=felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IModule.java&r1=915677&r2=918500&rev=918500&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IModule.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Module.java Wed Mar  3 15:04:41 2010
@@ -1,59 +1,62 @@
 /*
- * 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.
+ *  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.moduleloader;
+package org.apache.felix.framework.resolver;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.Enumeration;
+import java.util.List;
 import java.util.Map;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Requirement;
 import org.apache.felix.framework.util.manifestparser.R4Library;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Version;
 
-public interface IModule
+public interface Module
 {
     final static int EAGER_ACTIVATION = 0;
     final static int LAZY_ACTIVATION = 1;
 
-    void setSecurityContext(Object securityContext);
-    Object getSecurityContext();
-
     // Metadata access methods.
     Map getHeaders();
     boolean isExtension();
     String getSymbolicName();
     Version getVersion();
-    ICapability[] getCapabilities();
-    IRequirement[] getRequirements();
-    IRequirement[] getDynamicRequirements();
-    R4Library[] getNativeLibraries();
+    List<Capability> getCapabilities();
+    List<Requirement> getRequirements();
+    List<Requirement> getDynamicRequirements();
+    List<R4Library> getNativeLibraries();
     int getDeclaredActivationPolicy();
 
     // Run-time data access methods.
     Bundle getBundle();
     String getId();
-    IWire[] getWires();
+    List<Wire> getWires();
     boolean isResolved();
+    // TODO: FELIX3 - Shouldn't have mutable method on Module.
+    void setSecurityContext(Object securityContext);
+    Object getSecurityContext();
 
     // Content access methods.
-    IContent getContent();
+    Content getContent();
     Class getClassByDelegation(String name) throws ClassNotFoundException;
     URL getResourceByDelegation(String name);
     Enumeration getResourcesByDelegation(String name);

Copied: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java (from r915677, felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java)
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java?p2=felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java&p1=felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java&r1=915677&r2=918500&rev=918500&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java Wed Mar  3 15:04:41 2010
@@ -1,61 +1,47 @@
-/* 
- * 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.
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
  */
-package org.apache.felix.framework.searchpolicy;
+package org.apache.felix.framework.resolver;
 
-import org.apache.felix.moduleloader.IModule;
-import org.apache.felix.moduleloader.IRequirement;
+import org.apache.felix.framework.capabilityset.Requirement;
 
-/**
- * <p>
- * This exception is thrown if a module cannot be resolved. The module
- * that failed to be resolved is recorded, along with the failed import target
- * identifier and version number. If the error was a result of a propagation
- * conflict, then the propagation error flag is set.
- * </p>
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy#validate(org.apache.felix.moduleloader.Module)
-**/
-public class ResolveException extends Exception
+public class ResolveException extends RuntimeException
 {
-    private IModule m_module = null;
-    private IRequirement m_req = null;
+    private final Module m_module;
+    private final Requirement m_req;
 
     /**
-     * Constructs an exception with the specified message, module,
-     * import identifier, import version number, and propagation flag.
-    **/
-    public ResolveException(String msg, IModule module, IRequirement req)
+     * Constructs an instance of <code>ResolveException</code> with the specified detail message.
+     * @param msg the detail message.
+     */
+    public ResolveException(String msg, Module module, Requirement req)
     {
         super(msg);
         m_module = module;
         m_req = req;
     }
 
-    /**
-     * Returns the module that was being resolved.
-     * @return the module that was being resolved.
-    **/
-    public IModule getModule()
+    public Module getModule()
     {
         return m_module;
     }
 
-    public IRequirement getRequirement()
+    public Requirement getRequirement()
     {
         return m_req;
     }

Added: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java?rev=918500&view=auto
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java (added)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java Wed Mar  3 15:04:41 2010
@@ -0,0 +1,36 @@
+/*
+ *  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.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Requirement;
+
+public interface Resolver
+{
+    Map<Module, List<Wire>> resolve(ResolverState state, Module module);
+    Map<Module, List<Wire>> resolve(ResolverState state, Module module, String pkgName);
+
+    public static interface ResolverState
+    {
+        Set<Capability> getCandidates(Module module, Requirement req, boolean obeyMandatory);
+    }
+}
\ No newline at end of file