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 2011/06/15 20:57:20 UTC

svn commit: r1136150 [1/2] - in /felix/trunk/framework/src/main/java/org/apache/felix/framework: ./ resolver/ util/ util/manifestparser/ wiring/

Author: rickhall
Date: Wed Jun 15 18:57:20 2011
New Revision: 1136150

URL: http://svn.apache.org/viewvc?rev=1136150&view=rev
Log:
Implement most of the functionality for resolver hooks (FELIX-2986) along
with some other changes for R4.3 API (FELIX-2950).

Removed:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ResolverStateImpl.java
Modified:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ShrinkableCollection.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java Wed Jun 15 18:57:20 2011
@@ -162,17 +162,22 @@ class BundleImpl implements Bundle
         }
         else
         {
-            // Dispose of the current revisions.
+            // Get current revision, since we can reuse it.
+            BundleRevisionImpl current = (BundleRevisionImpl) adapt(BundleRevision.class);
+            // Close all existing revisions.
             closeRevisions();
+            // Clear all revisions.
+            m_revisions.clear();
 
-            // Now we will purge all old revisions, only keeping the newest one.
+            // Purge all old archive revisions, only keeping the newest one.
             m_archive.purge();
 
-            // Lastly, we want to reset our bundle be reinitializing our state
-            // and recreating a revision object for the newest revision.
-            m_revisions.clear();
-            final BundleRevision br = createRevision();
-            addRevision(br);
+            // Reset the content of the current bundle revision.
+            current.resetContent(m_archive.getCurrentRevision().getContent());
+            // Re-add the revision to the bundle.
+            addRevision(current);
+
+            // Reset the bundle state.
             m_state = Bundle.INSTALLED;
             m_stale = false;
             m_cachedHeaders.clear();

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java Wed Jun 15 18:57:20 2011
@@ -157,7 +157,7 @@ class BundleRevisionDependencies
 
         // Get exported package name.
         String pkgName = (String)
-            exportCap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+            exportCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
 
         // Get all importers and requirers for all revisions of the bundle.
         // The spec says that require-bundle should be returned with importers.
@@ -171,7 +171,7 @@ class BundleRevisionDependencies
                 {
                     BundleCapability cap = entry.getKey();
                     if ((cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
-                        && cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR)
+                        && cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
                             .equals(pkgName))
                         || cap.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
                     {

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java Wed Jun 15 18:57:20 2011
@@ -51,7 +51,6 @@ public class BundleRevisionImpl implemen
     private final Logger m_logger;
     private final Map m_configMap;
     private final String m_id;
-    private final Content m_content;
     private final Map m_headerMap;
     private final URLStreamHandler m_streamHandler;
 
@@ -69,6 +68,7 @@ public class BundleRevisionImpl implemen
 
     private final Bundle m_bundle;
 
+    private Content m_content;
     private List<Content> m_contentPath;
     private ProtectionDomain m_protectionDomain = null;
     private final static SecureAction m_secureAction = new SecureAction();
@@ -362,11 +362,16 @@ public class BundleRevisionImpl implemen
     // Content access methods.
     //
 
-    public Content getContent()
+    public synchronized Content getContent()
     {
         return m_content;
     }
 
+    synchronized void resetContent(Content content)
+    {
+        m_content = content;
+    }
+
     synchronized List<Content> getContentPath()
     {
         if (m_contentPath == null)
@@ -607,7 +612,7 @@ public class BundleRevisionImpl implemen
         }
         if (index == 0)
         {
-            return m_content.hasEntry(urlPath);
+            return getContent().hasEntry(urlPath);
         }
         return getContentPath().get(index - 1).hasEntry(urlPath);
     }
@@ -621,7 +626,7 @@ public class BundleRevisionImpl implemen
         }
         if (index == 0)
         {
-            return m_content.getEntryAsStream(urlPath);
+            return getContent().getEntryAsStream(urlPath);
         }
         return getContentPath().get(index - 1).getEntryAsStream(urlPath);
     }
@@ -634,7 +639,7 @@ public class BundleRevisionImpl implemen
         }
         if (index == 0)
         {
-            return m_content.getEntryAsURL(urlPath);
+            return getContent().getEntryAsURL(urlPath);
         }
         return getContentPath().get(index - 1).getEntryAsURL(urlPath);
     }
@@ -676,6 +681,7 @@ public class BundleRevisionImpl implemen
             m_logger.log(Logger.LOG_ERROR, "Error releasing revision: " + ex.getMessage(), ex);
         }
         m_content.close();
+        m_content = null;
         for (int i = 0; (m_contentPath != null) && (i < m_contentPath.size()); i++)
         {
             m_contentPath.get(i).close();

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java Wed Jun 15 18:57:20 2011
@@ -403,7 +403,7 @@ public class BundleWiringImpl implements
     {
         m_wires.add(wire);
         m_importedPkgs.put(
-            (String) wire.getCapability().getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR),
+            (String) wire.getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
             wire.getProviderWiring().getRevision());
     }
 
@@ -537,7 +537,7 @@ public class BundleWiringImpl implements
         {
             m_resolver.resolve(m_revision);
         }
-        catch (ResolveException ex)
+        catch (Exception ex)
         {
             // The spec states that if the bundle cannot be resolved, then
             // only the local bundle's resources should be searched. So we
@@ -639,6 +639,10 @@ public class BundleWiringImpl implements
             {
                 // Ignore this since it is likely normal.
             }
+            catch (BundleException ex)
+            {
+                // Ignore this since it is likely the result of a resolver hook.
+            }
             if (provider != null)
             {
                 // Delegate to the provider revision.
@@ -886,20 +890,11 @@ public class BundleWiringImpl implements
                     }
                 }
             }
-            catch (ResolveException ex)
+// TODO: OSGi R4.3 - If we eliminate resolving from this method, then we can
+//       simplify this catch, since resolve throws resolve and bundle exceptions.
+            catch (Exception ex)
             {
-                if (isClass)
-                {
-                    // We do not use the resolve exception as the
-                    // cause of the exception, since this would
-                    // potentially leak internal module information.
-                    throw new ClassNotFoundException(
-                        name + " not found because "
-                        + getBundle()
-                        + " cannot resolve: "
-                        + ex.getRequirement());
-                }
-                else
+                if (!isClass && (ex instanceof ResolveException))
                 {
                     // The spec states that if the bundle cannot be resolved, then
                     // only the local bundle's resources should be searched. So we
@@ -909,13 +904,38 @@ public class BundleWiringImpl implements
                     {
                         return url;
                     }
+                }
 
-                    // We need to throw a resource not found exception.
-                    throw new ResourceNotFoundException(
-                        name + " not found because "
-                        + getBundle()
-                        + " cannot resolve: "
-                        + ex.getRequirement());
+                if (isClass)
+                {
+                    if (!(ex instanceof ClassNotFoundException))
+                    {
+                        ClassNotFoundException cnfe = new ClassNotFoundException(
+                            name
+                            + " not found in "
+                            + getBundle()
+                            + " : "
+                            + ex.getMessage());
+ex.printStackTrace();
+                        cnfe.initCause(ex);
+                        throw cnfe;
+                    }
+                    throw (ClassNotFoundException) ex;
+                }
+                else
+                {
+                    if (!(ex instanceof ResourceNotFoundException))
+                    {
+                        ResourceNotFoundException rnfe = new ResourceNotFoundException(
+                            name
+                            + " not found in "
+                            + getBundle()
+                            + " : "
+                            + ex.getMessage());
+                        rnfe.initCause(ex);
+                        throw rnfe;
+                    }
+                    throw (ResourceNotFoundException) ex;
                 }
             }
             finally
@@ -965,10 +985,14 @@ public class BundleWiringImpl implements
                 return result;
             }
 
-            // If no class was found, then we must throw an exception
+            // If no class or resource was found, then we must throw an exception
             // since the provider of this package did not contain the
             // requested class and imported packages are atomic.
-            throw new ClassNotFoundException(name);
+            if (isClass)
+            {
+                throw new ClassNotFoundException(name);
+            }
+            throw new ResourceNotFoundException(name);
         }
 
         // Check if the package is required.
@@ -1017,6 +1041,10 @@ public class BundleWiringImpl implements
         {
             // Ignore this since it is likely normal.
         }
+        catch (BundleException ex)
+        {
+            // Ignore this since it is likely the result of a resolver hook.
+        }
 
         // If the dynamic import was successful, then this initial
         // time we must directly return the result from dynamically
@@ -1858,7 +1886,7 @@ public class BundleWiringImpl implements
         for (int i = 0; (wires != null) && (i < wires.size()); i++)
         {
             if (wires.get(i).getCapability().getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) &&
-                wires.get(i).getCapability().getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).equals(pkgName))
+                wires.get(i).getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName))
             {
                 String exporter = wires.get(i).getProviderWiring().getBundle().toString();
 
@@ -1949,7 +1977,7 @@ public class BundleWiringImpl implements
             // Try to see if there is an exporter available.
             Map<String, String> dirs = Collections.EMPTY_MAP;
             Map<String, Object> attrs = new HashMap<String, Object>(1);
-            attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+            attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
             BundleRequirementImpl req = new BundleRequirementImpl(
                 revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
             Set<BundleCapability> exporters = resolver.getCandidates(req, false);
@@ -1988,7 +2016,7 @@ public class BundleWiringImpl implements
         // Next, check to see if there are any exporters for the package at all.
         Map<String, String> dirs = Collections.EMPTY_MAP;
         Map<String, Object> attrs = new HashMap<String, Object>(1);
-        attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+        attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
         BundleRequirementImpl req = new BundleRequirementImpl(
             revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
         Set<BundleCapability> exports = resolver.getCandidates(req, false);

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java Wed Jun 15 18:57:20 2011
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -42,7 +42,7 @@ class ExportedPackageImpl implements Exp
         m_exportingBundle = exporter;
         m_exportingRevision = revision;
         m_export = export;
-        m_pkgName = (String) m_export.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+        m_pkgName = (String) m_export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
         m_version = (!m_export.getAttributes().containsKey(BundleCapabilityImpl.VERSION_ATTR))
             ? Version.emptyVersion
             : (Version) m_export.getAttributes().get(BundleCapabilityImpl.VERSION_ATTR);

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java Wed Jun 15 18:57:20 2011
@@ -447,7 +447,7 @@ class ExtensionManager extends URLStream
 
                 // Append exported package information.
                 exportSB.append(m_capabilities.get(i)
-                    .getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+                    .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
                 for (Entry<String, String> entry
                     : m_capabilities.get(i).getDirectives().entrySet())
                 {
@@ -460,7 +460,7 @@ class ExtensionManager extends URLStream
                 for (Entry<String, Object> entry
                     : m_capabilities.get(i).getAttributes().entrySet())
                 {
-                    if (!entry.getKey().equals(BundleCapabilityImpl.PACKAGE_ATTR)
+                    if (!entry.getKey().equals(BundleRevision.PACKAGE_NAMESPACE)
                         && !entry.getKey().equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
                         && !entry.getKey().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
                     {
@@ -474,7 +474,7 @@ class ExtensionManager extends URLStream
 
                 // Remember exported packages.
                 exportNames.add(m_capabilities.get(i)
-                    .getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+                    .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
             }
         }
 

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Wed Jun 15 18:57:20 2011
@@ -1531,11 +1531,23 @@ public class Felix extends BundleImpl im
         {
             return null;
         }
-// TODO: OSGi R4.3 - Currently, we try to resolve resource requests in
+// TODO: OSGi R4.3 - Previously, we try to resolve resource requests in
 //       findClassOrResourceByDelegation() and fall back to local resource
-//       searching if it fails. Perhaps we should attempt the resolve here
-//       and do the local searching here. This means we could get rid of
-//       resolve attempts in findClassOrResourceByDelegation().
+//       searching if it fails. Now we must attempt the resolve here since
+//       we cannot search by delegation until we are resolved and do the local
+//       searching here if we fail. This means we could get rid of resolve
+//       attempts in findClassOrResourceByDelegation().
+        try
+        {
+            resolveBundleRevision(bundle.adapt(BundleRevision.class));
+        }
+        catch (Exception ex)
+        {
+            // Ignore.
+        }
+
+        // If the bundle revision isn't resolved, then just search
+        // locally, otherwise delegate.
         if (bundle.adapt(BundleRevision.class).getWiring() == null)
         {
             return ((BundleRevisionImpl) bundle.adapt(BundleRevision.class))
@@ -1561,11 +1573,21 @@ public class Felix extends BundleImpl im
         {
             return null;
         }
-// TODO: OSGi R4.3 - Currently, we try to resolve resource requests in
-//       findResourcesByDelegation() and fall back to local resource
-//       searching if it fails. Perhaps we should attempt the resolve here
-//       and do the local searching here. This means we could get rid of
-//       resolve attempts in findResourcesByDelegation().
+// TODO: OSGi R4.3 - Previously, we try to resolve resource requests in
+//       findClassOrResourceByDelegation() and fall back to local resource
+//       searching if it fails. Now we must attempt the resolve here since
+//       we cannot search by delegation until we are resolved and do the local
+//       searching here if we fail. This means we could get rid of resolve
+//       attempts in findClassOrResourceByDelegation().
+        try
+        {
+            resolveBundleRevision(bundle.adapt(BundleRevision.class));
+        }
+        catch (Exception ex)
+        {
+            // Ignore.
+        }
+
         if (bundle.adapt(BundleRevision.class).getWiring() == null)
         {
             return ((BundleRevisionImpl) bundle.adapt(BundleRevision.class))
@@ -1726,7 +1748,7 @@ public class Felix extends BundleImpl im
         {
             try
             {
-                resolveBundle(bundle);
+                resolveBundleRevision(bundle.adapt(BundleRevision.class));
             }
             catch (BundleException ex)
             {
@@ -1881,7 +1903,7 @@ public class Felix extends BundleImpl im
                 case Bundle.ACTIVE:
                     return;
                 case Bundle.INSTALLED:
-                    resolveBundle(bundle);
+                    resolveBundleRevision(bundle.adapt(BundleRevision.class));
                     // No break.
                 case Bundle.RESOLVED:
                     // Set the bundle's context.
@@ -2037,7 +2059,9 @@ public class Felix extends BundleImpl im
                 }
 
                 // Rethrow all other exceptions as a BundleException.
-                throw new BundleException("Activator start error in bundle " + bundle + ".", th);
+                throw new BundleException(
+                    "Activator start error in bundle " + bundle + ".",
+                    BundleException.ACTIVATOR_ERROR, th);
             }
         }
         finally
@@ -3427,7 +3451,7 @@ public class Felix extends BundleImpl im
     {
         // First, get all exporters of the package.
         Map<String, Object> attrs = new HashMap<String, Object>(1);
-        attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+        attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
         BundleRequirementImpl req = new BundleRequirementImpl(
             null,
             BundleRevision.PACKAGE_NAMESPACE,
@@ -3580,9 +3604,9 @@ public class Felix extends BundleImpl im
 //       BundleWiring.getCapabilities() returns the proper result. We probably
 //       Won't even need this method.
                         String pkgName = (String)
-                            cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+                            cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
                         Map<String, Object> attrs = new HashMap<String, Object>(1);
-                        attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+                        attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
                         BundleRequirementImpl req =
                             new BundleRequirementImpl(
                             null,
@@ -3637,22 +3661,15 @@ public class Felix extends BundleImpl im
 
         try
         {
+            // Remember original targets.
+            Collection<Bundle> originalTargets = targets;
+
             // Determine set of bundles to be resolved, which is either the
             // specified bundles or all bundles if null.
             if (targets == null)
             {
-                targets = new ArrayList<Bundle>();
-
-                // Add all unresolved bundles to the list.
-                Iterator iter = m_installedBundles[LOCATION_MAP_IDX].values().iterator();
-                while (iter.hasNext())
-                {
-                    BundleImpl bundle = (BundleImpl) iter.next();
-                    if (bundle.getState() == Bundle.INSTALLED)
-                    {
-                        targets.add(bundle);
-                    }
-                }
+                // Add all bundles to the list.
+                targets = m_installedBundles[LOCATION_MAP_IDX].values();
             }
 
             // Now resolve each target bundle.
@@ -3661,17 +3678,45 @@ public class Felix extends BundleImpl im
             // If there are targets, then resolve each one.
             if (!targets.isEmpty())
             {
+                // Get bundle revisions for bundles in INSTALLED state.
+                Set<BundleRevision> revisions =
+                    new HashSet<BundleRevision>(targets.size());
                 for (Bundle b : targets)
                 {
-                    try
+                    if (b.getState() != Bundle.UNINSTALLED)
                     {
-                        resolveBundle((BundleImpl) b);
+                        revisions.add(b.adapt(BundleRevision.class));
                     }
-                    catch (BundleException ex)
+                }
+                // If we had to filter any of the original targets, then
+                // the return result will be false regardless.
+                if ((originalTargets != null) && (originalTargets.size() != revisions.size()))
+                {
+                    result = false;
+                }
+                try
+                {
+                    m_resolver.resolve(revisions);
+                    if (result)
                     {
-                        result = false;
+                        for (BundleRevision br : revisions)
+                        {
+                            if (br.getWiring() == null)
+                            {
+                                result = false;
+                                break;
+                            }
+                        }
                     }
                 }
+                catch (ResolveException ex)
+                {
+                    result = false;
+                }
+                catch (BundleException ex)
+                {
+                    result = false;
+                }
             }
 
             return result;
@@ -3683,11 +3728,11 @@ public class Felix extends BundleImpl im
         }
     }
 
-    private void resolveBundle(Bundle bundle) throws BundleException
+    private void resolveBundleRevision(BundleRevision revision) throws BundleException
     {
         try
         {
-            m_resolver.resolve(bundle.adapt(BundleRevision.class));
+            m_resolver.resolve(revision);
         }
         catch (ResolveException ex)
         {
@@ -3696,11 +3741,11 @@ public class Felix extends BundleImpl im
                 Bundle b = ex.getRevision().getBundle();
                 throw new BundleException(
                     "Unresolved constraint in bundle "
-                    + b + ": " + ex.getMessage());
+                    + b + ": " + ex.getMessage(), BundleException.RESOLVE_ERROR);
             }
             else
             {
-                throw new BundleException(ex.getMessage());
+                throw new BundleException(ex.getMessage(), BundleException.RESOLVE_ERROR);
             }
         }
     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java Wed Jun 15 18:57:20 2011
@@ -19,6 +19,7 @@
 package org.apache.felix.framework;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -27,17 +28,30 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+import org.apache.felix.framework.capabilityset.CapabilitySet;
+import org.apache.felix.framework.resolver.CandidateComparator;
 import org.apache.felix.framework.resolver.ResolveException;
 import org.apache.felix.framework.resolver.Resolver;
 import org.apache.felix.framework.resolver.ResolverImpl;
 import org.apache.felix.framework.resolver.ResolverWire;
+import org.apache.felix.framework.util.ShrinkableCollection;
 import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.R4Library;
 import org.apache.felix.framework.wiring.BundleCapabilityImpl;
 import org.apache.felix.framework.wiring.BundleRequirementImpl;
 import org.apache.felix.framework.wiring.BundleWireImpl;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundlePermission;
 import org.osgi.framework.Constants;
+import org.osgi.framework.PackagePermission;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.resolver.ResolverHook;
+import org.osgi.framework.hooks.resolver.ResolverHookFactory;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRequirement;
 import org.osgi.framework.wiring.BundleRevision;
@@ -48,6 +62,9 @@ class StatefulResolver
     private final Felix m_felix;
     private final Resolver m_resolver;
     private final ResolverStateImpl m_resolverState;
+    private final List<ResolverHook> m_hooks = new ArrayList<ResolverHook>();
+    private boolean m_isResolving = false;
+    private Collection<BundleRevision> m_whitelist = null;
 
     StatefulResolver(Felix felix)
     {
@@ -72,15 +89,13 @@ class StatefulResolver
         return m_resolverState.getCandidates(req, obeyMandatory);
     }
 
-    void resolve(BundleRevision rootRevision) throws ResolveException
+    void resolve(BundleRevision rootRevision) throws ResolveException, BundleException
     {
         // Although there is a race condition to check the bundle state
         // then lock it, we do this because we don't want to acquire the
         // a lock just to check if the revision is resolved, which itself
         // is a safe read. If the revision isn't resolved, we end up double
         // check the resolved status later.
-// TODO: OSGi R4.3 - This locking strategy here depends on how we ultimately
-//       implement getWiring(), which may change.
         if (rootRevision.getWiring() == null)
         {
             // Acquire global lock.
@@ -91,26 +106,151 @@ class StatefulResolver
                     "Unable to acquire global lock for resolve.", rootRevision, null);
             }
 
+            // Make sure we are not already resolving, which can be
+            // the case if a resolver hook does something bad.
+            if (m_isResolving)
+            {
+                m_felix.releaseGlobalLock();
+                throw new IllegalStateException("Nested resolve operations not allowed.");
+            }
+            m_isResolving = true;
+
             Map<BundleRevision, List<ResolverWire>> wireMap = null;
             try
             {
-                BundleImpl bundle = (BundleImpl) rootRevision.getBundle();
-
                 // Extensions are resolved differently.
+                BundleImpl bundle = (BundleImpl) rootRevision.getBundle();
                 if (bundle.isExtension())
                 {
                     return;
                 }
 
-                // Resolve the revision.
-                wireMap = m_resolver.resolve(
-                    m_resolverState, rootRevision, m_resolverState.getFragments());
+                // Get resolver hook factories.
+                Set<ServiceReference<ResolverHookFactory>> hookRefs =
+                    m_felix.getHooks(ResolverHookFactory.class);
+                if (!hookRefs.isEmpty())
+                {
+                    // Create triggers list.
+                    List<BundleRevision> triggers = new ArrayList<BundleRevision>(1);
+                    triggers.add(rootRevision);
+                    triggers = Collections.unmodifiableList(triggers);
+
+                    // Create resolver hook objects by calling begin() on factory.
+                    for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+                    {
+                        try
+                        {
+                            ResolverHook hook = m_felix.getService(m_felix, ref).begin(triggers);
+                            if (hook != null)
+                            {
+                                m_hooks.add(hook);
+                            }
+                        }
+                        catch (Throwable ex)
+                        {
+                            throw new BundleException(
+                                "Resolver hook exception: " + ex.getMessage(),
+                                BundleException.REJECTED_BY_HOOK,
+                                ex);
+                        }
+                    }
 
-                // Mark all revisions as resolved.
+                    // Ask hooks to indicate which revisions should not be resolved.
+                    m_whitelist =
+                        new ShrinkableCollection<BundleRevision>(
+                            m_resolverState.getUnresolvedRevisions());
+                    int originalSize = m_whitelist.size();
+                    for (ResolverHook hook : m_hooks)
+                    {
+                        try
+                        {
+                            hook.filterResolvable(m_whitelist);
+                        }
+                        catch (Throwable ex)
+                        {
+                            throw new BundleException(
+                                "Resolver hook exception: " + ex.getMessage(),
+                                BundleException.REJECTED_BY_HOOK,
+                                ex);
+                        }
+                    }
+                    // If nothing was removed, then just null the whitelist
+                    // as an optimization.
+                    if (m_whitelist.size() == originalSize)
+                    {
+                        m_whitelist = null;
+                    }
+
+                    // Check to make sure the target revision is allowed to resolve.
+                    if ((m_whitelist != null) && !m_whitelist.contains(rootRevision))
+                    {
+                        throw new ResolveException(
+                            "Resolver hook prevented resolution.", rootRevision, null);
+                    }
+                }
+
+                // Catch any resolve exception to rethrow later because
+                // we may need to call end() on resolver hooks.
+                ResolveException rethrow = null;
+                try
+                {
+                    // Resolve the revision.
+                    wireMap = m_resolver.resolve(
+                        m_resolverState, rootRevision, m_resolverState.getFragments());
+                }
+                catch (ResolveException ex)
+                {
+                    rethrow = ex;
+                }
+
+                // If we have resolver hooks, we must call end() on them.
+                if (!hookRefs.isEmpty())
+                {
+                    // Verify that all resolver hook service references are still valid
+                    // Call end() on resolver hooks.
+                    for (ResolverHook hook : m_hooks)
+                    {
+// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
+//       to their svc ref since we aren't supposed to call end() on unregistered
+//       but currently we call end() on all.
+                        hook.end();
+                    }
+                    // Verify that all hook service references are still valid
+                    // and unget all resolver hook factories.
+                    boolean invalid = false;
+                    for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+                    {
+                        if (ref.getBundle() == null)
+                        {
+                            invalid = true;
+                        }
+                        m_felix.ungetService(m_felix, ref);
+                    }
+                    if (invalid)
+                    {
+                        throw new BundleException(
+                            "Resolver hook service unregistered during resolve.",
+                            BundleException.REJECTED_BY_HOOK);
+                    }
+                }
+
+                // If the resolve failed, rethrow the exception.
+                if (rethrow != null)
+                {
+                    throw rethrow;
+                }
+
+                // Otherwise, mark all revisions as resolved.
                 markResolvedRevisions(wireMap);
             }
             finally
             {
+                // Clear resolving flag.
+                m_isResolving = false;
+                // Clear whitelist.
+                m_whitelist = null;
+                // Always clear any hooks.
+                m_hooks.clear();
                 // Always release the global lock.
                 m_felix.releaseGlobalLock();
             }
@@ -119,8 +259,186 @@ class StatefulResolver
         }
     }
 
+// TODO: OSGi R4.3 - Isn't this method just a generalization of the above method?
+//       Can't we combine them and perhaps simplify the various resolve() methods
+//       here and in Felix.java too?
+    void resolve(Set<BundleRevision> revisions) throws ResolveException, BundleException
+    {
+        // Acquire global lock.
+        boolean locked = m_felix.acquireGlobalLock();
+        if (!locked)
+        {
+            throw new ResolveException(
+                "Unable to acquire global lock for resolve.", null, null);
+        }
+
+        // Make sure we are not already resolving, which can be
+        // the case if a resolver hook does something bad.
+        if (m_isResolving)
+        {
+            m_felix.releaseGlobalLock();
+            throw new IllegalStateException("Nested resolve operations not allowed.");
+        }
+        m_isResolving = true;
+
+        Map<BundleRevision, List<ResolverWire>> wireMap = null;
+        try
+        {
+            // Make our own copy of revisions.
+            revisions = new HashSet<BundleRevision>(revisions);
+
+            // Extensions are resolved differently.
+            for (Iterator<BundleRevision> it = revisions.iterator(); it.hasNext(); )
+            {
+                BundleImpl bundle = (BundleImpl) it.next().getBundle();
+                if (bundle.isExtension())
+                {
+                    it.remove();
+                }
+            }
+
+            // Get resolver hook factories.
+            Set<ServiceReference<ResolverHookFactory>> hookRefs =
+                m_felix.getHooks(ResolverHookFactory.class);
+            if (!hookRefs.isEmpty())
+            {
+                // Create triggers list.
+                Collection<BundleRevision> triggers = Collections.unmodifiableSet(revisions);
+
+                // Create resolver hook objects by calling begin() on factory.
+                for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+                {
+                    try
+                    {
+                        ResolverHookFactory factory = m_felix.getService(m_felix, ref);
+                        if (factory != null)
+                        {
+                            ResolverHook hook = factory.begin(triggers);
+                            if (hook != null)
+                            {
+                                m_hooks.add(hook);
+                            }
+                        }
+                    }
+                    catch (Throwable ex)
+                    {
+                        throw new BundleException(
+                            "Resolver hook exception: " + ex.getMessage(),
+                            BundleException.REJECTED_BY_HOOK,
+                            ex);
+                    }
+                }
+
+                // Ask hooks to indicate which revisions should not be resolved.
+                m_whitelist =
+                    new ShrinkableCollection<BundleRevision>(
+                        m_resolverState.getUnresolvedRevisions());
+                int originalSize = m_whitelist.size();
+                for (ResolverHook hook : m_hooks)
+                {
+                    try
+                    {
+                        hook.filterResolvable(m_whitelist);
+                    }
+                    catch (Throwable ex)
+                    {
+                        throw new BundleException(
+                            "Resolver hook exception: " + ex.getMessage(),
+                            BundleException.REJECTED_BY_HOOK,
+                            ex);
+                    }
+                }
+                // If nothing was removed, then just null the whitelist
+                // as an optimization.
+                if (m_whitelist.size() == originalSize)
+                {
+                    m_whitelist = null;
+                }
+
+                // Check to make sure the target revision is allowed to resolve.
+                if (m_whitelist != null)
+                {
+                    revisions.retainAll(m_whitelist);
+                    if (revisions.isEmpty())
+                    {
+                        throw new ResolveException(
+                            "Resolver hook prevented resolution.", null, null);
+                    }
+                }
+            }
+
+            // Catch any resolve exception to rethrow later because
+            // we may need to call end() on resolver hooks.
+            ResolveException rethrow = null;
+            try
+            {
+                // Resolve the revision.
+// TODO: OSGi R4.3 - Shouldn't we still be passing in greedy attach fragments here?
+                wireMap = m_resolver.resolve(
+                    m_resolverState, revisions, m_resolverState.getFragments());
+            }
+            catch (ResolveException ex)
+            {
+                rethrow = ex;
+            }
+
+            // If we have resolver hooks, we must call end() on them.
+            if (!hookRefs.isEmpty())
+            {
+                // Verify that all resolver hook service references are still valid
+                // Call end() on resolver hooks.
+                for (ResolverHook hook : m_hooks)
+                {
+// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
+//       to their svc ref since we aren't supposed to call end() on unregistered
+//       but currently we call end() on all.
+                    hook.end();
+                }
+                // Verify that all hook service references are still valid
+                // and unget all resolver hook factories.
+                boolean invalid = false;
+                for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+                {
+                    if (ref.getBundle() == null)
+                    {
+                        invalid = true;
+                    }
+                    m_felix.ungetService(m_felix, ref);
+                }
+                if (invalid)
+                {
+                    throw new BundleException(
+                        "Resolver hook service unregistered during resolve.",
+                        BundleException.REJECTED_BY_HOOK);
+                }
+            }
+
+            // If the resolve failed, rethrow the exception.
+            if (rethrow != null)
+            {
+                throw rethrow;
+            }
+
+            // Otherwise, mark all revisions as resolved.
+            markResolvedRevisions(wireMap);
+        }
+        finally
+        {
+            // Clear resolving flag.
+            m_isResolving = false;
+            // Clear whitelist.
+            m_whitelist = null;
+            // Always clear any hooks.
+            m_hooks.clear();
+            // Always release the global lock.
+            m_felix.releaseGlobalLock();
+        }
+
+        fireResolvedEvents(wireMap);
+    }
+
     BundleRevision resolve(BundleRevision revision, String pkgName)
-        throws ResolveException
+        throws ResolveException, BundleException
     {
         BundleRevision provider = null;
 
@@ -139,6 +457,14 @@ class StatefulResolver
                     "Unable to acquire global lock for resolve.", revision, null);
             }
 
+            // Make sure we are not already resolving, which can be
+            // the case if a resolver hook does something bad.
+            if (m_isResolving)
+            {
+                throw new IllegalStateException("Nested resolve operations not allowed.");
+            }
+            m_isResolving = true;
+
             Map<BundleRevision, List<ResolverWire>> wireMap = null;
             try
             {
@@ -150,9 +476,117 @@ class StatefulResolver
                     .getImportedPackageSource(pkgName);
                 if (provider == null)
                 {
-                    wireMap = m_resolver.resolve(
-                        m_resolverState, revision, pkgName,
-                        m_resolverState.getFragments());
+                    // Get resolver hook factories.
+                    Set<ServiceReference<ResolverHookFactory>> hookRefs =
+                        m_felix.getHooks(ResolverHookFactory.class);
+                    if (!hookRefs.isEmpty())
+                    {
+                        // Create triggers list.
+                        List<BundleRevision> triggers = new ArrayList<BundleRevision>(1);
+                        triggers.add(revision);
+                        triggers = Collections.unmodifiableList(triggers);
+
+                        // Create resolver hook objects by calling begin() on factory.
+                        for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+                        {
+                            try
+                            {
+                                ResolverHook hook = m_felix.getService(m_felix, ref).begin(triggers);
+                                if (hook != null)
+                                {
+                                    m_hooks.add(hook);
+                                }
+                            }
+                            catch (Throwable ex)
+                            {
+                                throw new BundleException(
+                                    "Resolver hook exception: " + ex.getMessage(),
+                                    BundleException.REJECTED_BY_HOOK,
+                                    ex);
+                            }
+                        }
+
+                        // Ask hooks to indicate which revisions should not be resolved.
+                        m_whitelist =
+                            new ShrinkableCollection<BundleRevision>(
+                                m_resolverState.getUnresolvedRevisions());
+                        int originalSize = m_whitelist.size();
+                        for (ResolverHook hook : m_hooks)
+                        {
+                            try
+                            {
+                                hook.filterResolvable(m_whitelist);
+                            }
+                            catch (Throwable ex)
+                            {
+                                throw new BundleException(
+                                    "Resolver hook exception: " + ex.getMessage(),
+                                    BundleException.REJECTED_BY_HOOK,
+                                    ex);
+                            }
+                        }
+                        // If nothing was removed, then just null the whitelist
+                        // as an optimization.
+                        if (m_whitelist.size() == originalSize)
+                        {
+                            m_whitelist = null;
+                        }
+
+                        // Since this is a dynamic import, the root revision is
+                        // already resolved, so we don't need to check it against
+                        // the whitelist as we do in other cases.
+                    }
+
+                    // Catch any resolve exception to rethrow later because
+                    // we may need to call end() on resolver hooks.
+                    ResolveException rethrow = null;
+                    try
+                    {
+                        wireMap = m_resolver.resolve(
+                            m_resolverState, revision, pkgName,
+                            m_resolverState.getFragments());
+                    }
+                    catch (ResolveException ex)
+                    {
+                        rethrow = ex;
+                    }
+
+                    // If we have resolver hooks, we must call end() on them.
+                    if (!hookRefs.isEmpty())
+                    {
+                        // Verify that all resolver hook service references are still valid
+                        // Call end() on resolver hooks.
+                        for (ResolverHook hook : m_hooks)
+                        {
+// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
+//       to their svc ref since we aren't supposed to call end() on unregistered
+//       but currently we call end() on all.
+                            hook.end();
+                        }
+                        // Verify that all hook service references are still valid
+                        // and unget all resolver hook factories.
+                        boolean invalid = false;
+                        for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+                        {
+                            if (ref.getBundle() == null)
+                            {
+                                invalid = true;
+                            }
+                            m_felix.ungetService(m_felix, ref);
+                        }
+                        if (invalid)
+                        {
+                            throw new BundleException(
+                                "Resolver hook service unregistered during resolve.",
+                                BundleException.REJECTED_BY_HOOK);
+                        }
+                    }
+
+                    // If the resolve failed, rethrow the exception.
+                    if (rethrow != null)
+                    {
+                        throw rethrow;
+                    }
 
                     if ((wireMap != null) && wireMap.containsKey(revision))
                     {
@@ -190,6 +624,12 @@ class StatefulResolver
             }
             finally
             {
+                // Clear resolving flag.
+                m_isResolving = false;
+                // Clear whitelist.
+                m_whitelist = null;
+                // Always clear any hooks.
+                m_hooks.clear();
                 // Always release the global lock.
                 m_felix.releaseGlobalLock();
             }
@@ -225,7 +665,7 @@ class StatefulResolver
         for (BundleCapability cap : revision.getWiring().getCapabilities(null))
         {
             if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
-                && cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).equals(pkgName))
+                && cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName))
             {
                 return false;
             }
@@ -242,7 +682,7 @@ class StatefulResolver
         // there is a matching one for the package from which we want to
         // load a class.
         Map<String, Object> attrs = new HashMap(1);
-        attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+        attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
         BundleRequirementImpl req = new BundleRequirementImpl(
             revision,
             BundleRevision.PACKAGE_NAMESPACE,
@@ -342,7 +782,7 @@ class StatefulResolver
                         {
                             importedPkgs.put(
                                 (String) rw.getCapability().getAttributes()
-                                    .get(BundleCapabilityImpl.PACKAGE_ATTR),
+                                    .get(BundleRevision.PACKAGE_NAMESPACE),
                                 rw.getProvider());
                         }
                         else if (rw.getCapability().getNamespace()
@@ -527,7 +967,7 @@ class StatefulResolver
                 if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
                 {
                     pkgs.add((String)
-                        cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+                        cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
                 }
             }
 
@@ -577,4 +1017,351 @@ class StatefulResolver
 
         return pkgs;
     }
+
+    class ResolverStateImpl implements Resolver.ResolverState
+    {
+        private final Logger m_logger;
+        // Set of all revisions.
+        private final Set<BundleRevision> m_revisions;
+        // Set of all fragments.
+        private final Set<BundleRevision> m_fragments;
+        // Capability sets.
+        private final Map<String, CapabilitySet> m_capSets;
+        // Execution environment.
+        private final String m_fwkExecEnvStr;
+        // Parsed framework environments
+        private final Set<String> m_fwkExecEnvSet;
+
+//    void dump()
+//    {
+//        for (Entry<String, CapabilitySet> entry : m_capSets.entrySet())
+//        {
+//            System.out.println("+++ START CAPSET " + entry.getKey());
+//            entry.getValue().dump();
+//            System.out.println("+++ END CAPSET " + entry.getKey());
+//        }
+//    }
+
+        ResolverStateImpl(Logger logger, String fwkExecEnvStr)
+        {
+            m_logger = logger;
+            m_revisions = new HashSet<BundleRevision>();
+            m_fragments = new HashSet<BundleRevision>();
+            m_capSets = new HashMap<String, CapabilitySet>();
+
+            m_fwkExecEnvStr = (fwkExecEnvStr != null) ? fwkExecEnvStr.trim() : null;
+            m_fwkExecEnvSet = parseExecutionEnvironments(fwkExecEnvStr);
+
+            List<String> indices = new ArrayList<String>();
+            indices.add(BundleRevision.BUNDLE_NAMESPACE);
+            m_capSets.put(BundleRevision.BUNDLE_NAMESPACE, new CapabilitySet(indices, true));
+
+            indices = new ArrayList<String>();
+            indices.add(BundleRevision.PACKAGE_NAMESPACE);
+            m_capSets.put(BundleRevision.PACKAGE_NAMESPACE, new CapabilitySet(indices, true));
+
+            indices = new ArrayList<String>();
+            indices.add(BundleRevision.HOST_NAMESPACE);
+            m_capSets.put(BundleRevision.HOST_NAMESPACE,  new CapabilitySet(indices, true));
+        }
+
+// TODO: OSGi R4.3/RESOLVER HOOK - We could maintain a separate list to optimize this.
+        synchronized Set<BundleRevision> getUnresolvedRevisions()
+        {
+            Set<BundleRevision> unresolved = new HashSet<BundleRevision>();
+            for (BundleRevision revision : m_revisions)
+            {
+                if (revision.getWiring() == null)
+                {
+                    unresolved.add(revision);
+                }
+            }
+            return unresolved;
+        }
+
+        synchronized void addRevision(BundleRevision br)
+        {
+            m_revisions.add(br);
+            List<BundleCapability> caps = (br.getWiring() == null)
+                ? br.getDeclaredCapabilities(null)
+                : br.getWiring().getCapabilities(null);
+            if (caps != null)
+            {
+                for (BundleCapability cap : caps)
+                {
+                    CapabilitySet capSet = m_capSets.get(cap.getNamespace());
+                    if (capSet == null)
+                    {
+                        capSet = new CapabilitySet(null, true);
+                        m_capSets.put(cap.getNamespace(), capSet);
+                    }
+                    capSet.addCapability(cap);
+                }
+            }
+
+            if (Util.isFragment(br))
+            {
+                m_fragments.add(br);
+            }
+        }
+
+        synchronized void removeRevision(BundleRevision br)
+        {
+            m_revisions.remove(br);
+            List<BundleCapability> caps = (br.getWiring() == null)
+                ? br.getDeclaredCapabilities(null)
+                : br.getWiring().getCapabilities(null);
+            if (caps != null)
+            {
+                for (BundleCapability cap : caps)
+                {
+                    CapabilitySet capSet = m_capSets.get(cap.getNamespace());
+                    if (capSet != null)
+                    {
+                        capSet.removeCapability(cap);
+                    }
+                }
+            }
+
+            if (Util.isFragment(br))
+            {
+                m_fragments.remove(br);
+            }
+        }
+
+        synchronized Set<BundleRevision> getFragments()
+        {
+            return new HashSet(m_fragments);
+        }
+
+// TODO: OSGi R4.3 - This will need to be changed once BundleWiring.getCapabilities()
+//       is correctly implemented, since it already has to remove substituted caps.
+        synchronized void removeSubstitutedCapabilities(BundleRevision br)
+        {
+            if (br.getWiring() != null)
+            {
+                // Loop through the revision's package wires and determine if any
+                // of them overlap any of the packages exported by the revision.
+                // If so, then the framework must have chosen to have the revision
+                // import rather than export the package, so we need to remove the
+                // corresponding package capability from the package capability set.
+                for (BundleWire w : br.getWiring().getRequiredWires(null))
+                {
+                    if (w.getCapability().getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
+                    {
+                        for (BundleCapability cap : br.getWiring().getCapabilities(null))
+                        {
+                            if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
+                                && w.getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
+                                    .equals(cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)))
+                            {
+                                m_capSets.get(BundleRevision.PACKAGE_NAMESPACE).removeCapability(cap);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //
+        // ResolverState methods.
+        //
+
+        public synchronized SortedSet<BundleCapability> getCandidates(
+            BundleRequirementImpl req, boolean obeyMandatory)
+        {
+            BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
+            SortedSet<BundleCapability> result =
+                new TreeSet<BundleCapability>(new CandidateComparator());
+
+            CapabilitySet capSet = m_capSets.get(req.getNamespace());
+            if (capSet != null)
+            {
+                Set<BundleCapability> matches = capSet.match(req.getFilter(), obeyMandatory);
+                for (BundleCapability cap : matches)
+                {
+                    if (System.getSecurityManager() != null)
+                    {
+                        if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && (
+                            !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+                                new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
+                                PackagePermission.EXPORTONLY)) ||
+                                !((reqRevision == null) ||
+                                    ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+                                        new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
+                                        cap.getRevision().getBundle(),PackagePermission.IMPORT))
+                                )))
+                        {
+                            if (reqRevision != cap.getRevision())
+                            {
+                                continue;
+                            }
+                        }
+                        else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE) && (
+                            !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+                                new BundlePermission(cap.getRevision().getSymbolicName(), BundlePermission.PROVIDE)) ||
+                                !((reqRevision == null) ||
+                                    ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+                                        new BundlePermission(reqRevision.getSymbolicName(), BundlePermission.REQUIRE))
+                                )))
+                        {
+                            continue;
+                        }
+                        else if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE) &&
+                            (!((BundleProtectionDomain) reqRevision.getProtectionDomain())
+                                .impliesDirect(new BundlePermission(
+                                    reqRevision.getSymbolicName(),
+                                    BundlePermission.FRAGMENT))
+                            || !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain())
+                                .impliesDirect(new BundlePermission(
+                                    cap.getRevision().getSymbolicName(),
+                                    BundlePermission.HOST))))
+                        {
+                            continue;
+                        }
+                    }
+
+                    if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE)
+                        && (cap.getRevision().getWiring() != null))
+                    {
+                        continue;
+                    }
+
+                    result.add(cap);
+                }
+            }
+
+            // If we have resolver hooks, then we may need to filter our results
+            // based on a whitelist and/or fine-grained candidate filtering.
+            if (!result.isEmpty() && !m_hooks.isEmpty())
+            {
+                // It we have a whitelist, then first filter out candidates
+                // from disallowed revisions.
+// TODO: OSGi R4.3 - It would be better if we could think of a way to do this
+//       filtering that was less costly. One possibility it to do the check in
+//       ResolverState.checkExecutionEnvironment(), since it will only need to
+//       be done once for any black listed revision. However, as we move toward
+//       OBR-like API, this is a non-standard call, so doing it here is the only
+//       standard way of achieving it.
+                if (m_whitelist != null)
+                {
+                    for (Iterator<BundleCapability> it = result.iterator(); it.hasNext(); )
+                    {
+                        if (!m_whitelist.contains(it.next().getRevision()))
+                        {
+                            it.remove();
+                        }
+                    }
+                }
+
+                // Now give the hooks a chance to do fine-grained filtering.
+                ShrinkableCollection<BundleCapability> shrinkable =
+                    new ShrinkableCollection<BundleCapability>(result);
+                for (ResolverHook hook : m_hooks)
+                {
+                    hook.filterMatches(req, shrinkable);
+                }
+            }
+
+            return result;
+        }
+
+        public void checkExecutionEnvironment(BundleRevision revision) throws ResolveException
+        {
+            String bundleExecEnvStr = (String)
+                ((BundleRevisionImpl) revision).getHeaders().get(
+                    Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
+            if (bundleExecEnvStr != null)
+            {
+                bundleExecEnvStr = bundleExecEnvStr.trim();
+
+                // If the bundle has specified an execution environment and the
+                // framework has an execution environment specified, then we must
+                // check for a match.
+                if (!bundleExecEnvStr.equals("")
+                    && (m_fwkExecEnvStr != null)
+                    && (m_fwkExecEnvStr.length() > 0))
+                {
+                    StringTokenizer tokens = new StringTokenizer(bundleExecEnvStr, ",");
+                    boolean found = false;
+                    while (tokens.hasMoreTokens() && !found)
+                    {
+                        if (m_fwkExecEnvSet.contains(tokens.nextToken().trim()))
+                        {
+                            found = true;
+                        }
+                    }
+                    if (!found)
+                    {
+                        throw new ResolveException(
+                            "Execution environment not supported: "
+                            + bundleExecEnvStr, revision, null);
+                    }
+                }
+            }
+        }
+
+        public void checkNativeLibraries(BundleRevision revision) throws ResolveException
+        {
+            // Next, try to resolve any native code, since the revision is
+            // not resolvable if its native code cannot be loaded.
+// TODO: OSGi R4.3 - Is it sufficient to just check declared native libs here?
+//        List<R4Library> libs = ((BundleWiringImpl) revision.getWiring()).getNativeLibraries();
+            List<R4Library> libs = ((BundleRevisionImpl) revision).getDeclaredNativeLibraries();
+            if (libs != null)
+            {
+                String msg = null;
+                // Verify that all native libraries exist in advance; this will
+                // throw an exception if the native library does not exist.
+                for (int libIdx = 0; (msg == null) && (libIdx < libs.size()); libIdx++)
+                {
+                    String entryName = libs.get(libIdx).getEntryName();
+                    if (entryName != null)
+                    {
+                        if (!((BundleRevisionImpl) revision).getContent().hasEntry(entryName))
+                        {
+                            msg = "Native library does not exist: " + entryName;
+                        }
+                    }
+                }
+                // If we have a zero-length native library array, then
+                // this means no native library class could be selected
+                // so we should fail to resolve.
+                if (libs.isEmpty())
+                {
+                    msg = "No matching native libraries found.";
+                }
+                if (msg != null)
+                {
+                    throw new ResolveException(msg, revision, null);
+                }
+            }
+        }
+    }
+
+    //
+    // Utility methods.
+    //
+
+    /**
+     * Updates the framework wide execution environment string and a cached Set of
+     * execution environment tokens from the comma delimited list specified by the
+     * system variable 'org.osgi.framework.executionenvironment'.
+     * @param fwkExecEnvStr Comma delimited string of provided execution environments
+     * @return the parsed set of execution environments
+    **/
+    private static Set<String> parseExecutionEnvironments(String fwkExecEnvStr)
+    {
+        Set<String> newSet = new HashSet<String>();
+        if (fwkExecEnvStr != null)
+        {
+            StringTokenizer tokens = new StringTokenizer(fwkExecEnvStr, ",");
+            while (tokens.hasMoreTokens())
+            {
+                newSet.add(tokens.nextToken().trim());
+            }
+        }
+        return newSet;
+    }
 }
\ No newline at end of file

Modified: 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=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java Wed Jun 15 18:57:20 2011
@@ -47,8 +47,8 @@ public class CandidateComparator impleme
         // Compare revision capabilities.
         if ((c == 0) && cap1.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
         {
-            c = ((Comparable) cap1.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE))
-                .compareTo(cap2.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE));
+            c = ((Comparable) cap1.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE))
+                .compareTo(cap2.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE));
             if (c == 0)
             {
                 Version v1 = (!cap1.getAttributes().containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE))
@@ -65,8 +65,8 @@ public class CandidateComparator impleme
         // Compare package capabilities.
         else if ((c == 0) && cap1.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
         {
-            c = ((Comparable) cap1.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR))
-                .compareTo(cap2.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+            c = ((Comparable) cap1.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE))
+                .compareTo(cap2.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
             if (c == 0)
             {
                 Version v1 = (!cap1.getAttributes().containsKey(BundleCapabilityImpl.VERSION_ATTR))