More fixes to calculating resolved caps/deps, such as ignoring
unknown effective times and handling fragments as a special case.
Also start to implement adapt(BundleRevisions.class). (FELIX-2950)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1143199 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index 2a28114..701a986 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -40,12 +40,13 @@
 import org.osgi.framework.Version;
 import org.osgi.framework.startlevel.BundleStartLevel;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleRevisions;
 import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.BundleWiring;
 
-class BundleImpl implements Bundle
+class BundleImpl implements Bundle, BundleRevisions
 {
-    // No one should use this field directly, use getFramework() instead.
+    // No one should use this field directlhttp://www.youtube.com/watch?v=zQwxwPDU4bwy, use getFramework() instead.
     private final Felix __m_felix;
 
     private final BundleArchive m_archive;
@@ -871,9 +872,9 @@
 
     synchronized boolean isExtension()
     {
-        for (int i = (m_revisions.size() - 1); i > -1; i--)
+        for (BundleRevision revision : m_revisions)
         {
-            if (((BundleRevisionImpl) m_revisions.get(i)).isExtension())
+            if (((BundleRevisionImpl) revision).isExtension())
             {
                 return true;
             }
@@ -1022,11 +1023,19 @@
         }
         else if (type == BundleRevision.class)
         {
-            return (A) m_revisions.get(m_revisions.size() - 1);
+            if (m_state == Bundle.UNINSTALLED)
+            {
+                return null;
+            }
+            return (A) m_revisions.get(0);
+        }
+        else if (type == BundleRevisions.class)
+        {
+            return (A) this;
         }
         else if (type == BundleWiring.class)
         {
-            return (A) m_revisions.get(m_revisions.size() - 1).getWiring();
+            return (A) m_revisions.get(0).getWiring();
         }
         return null;
     }
@@ -1060,21 +1069,14 @@
     // Revision management.
     //
 
-    /**
-     * Returns an array of all modules associated with the bundle represented by
-     * this <tt>BundleInfo</tt> object. A module in the array corresponds to a
-     * revision of the bundle's JAR file and is ordered from oldest to newest.
-     * Multiple revisions of a bundle JAR file might exist if a bundle is
-     * updated, without refreshing the framework. In this case, exports from
-     * the prior revisions of the bundle JAR file are still offered; the
-     * current revision will be bound to packages from the prior revision,
-     * unless the packages were not offered by the prior revision. There is
-     * no limit on the potential number of bundle JAR file revisions.
-     * @return array of modules corresponding to the bundle JAR file revisions.
-    **/
-    synchronized List<BundleRevision> getRevisions()
+    public Bundle getBundle()
     {
-        return m_revisions;
+        return this;
+    }
+
+    public synchronized List<BundleRevision> getRevisions()
+    {
+        return new ArrayList<BundleRevision>(m_revisions);
     }
 
     /**
@@ -1085,14 +1087,7 @@
     **/
     synchronized boolean hasRevision(BundleRevision revision)
     {
-        for (int i = 0; i < m_revisions.size(); i++)
-        {
-            if (m_revisions.get(i) == revision)
-            {
-                return true;
-            }
-        }
-        return false;
+        return m_revisions.contains(revision);
     }
 
     synchronized void revise(String location, InputStream is)
@@ -1115,7 +1110,7 @@
     synchronized boolean rollbackRevise() throws Exception
     {
         boolean isExtension = isExtension();
-        BundleRevision br = m_revisions.remove(m_revisions.size() - 1);
+        BundleRevision br = m_revisions.remove(0);
         if (!isExtension)
         {
             // Since revising a bundle adds a revision to the global
@@ -1131,7 +1126,7 @@
     // which is the normal case.
     synchronized void addRevision(BundleRevision revision) throws Exception
     {
-        m_revisions.add(revision);
+        m_revisions.add(0, revision);
 
         // Set protection domain after adding the revision to the bundle,
         // since this requires that the bundle has a revision.
@@ -1147,7 +1142,7 @@
             }
             catch (Exception ex)
             {
-                m_revisions.remove(m_revisions.size() - 1);
+                m_revisions.remove(0);
                 throw ex;
             }
         }
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java b/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
index 749ee3a..1611842 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
@@ -30,6 +30,7 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleRevisions;
 import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.BundleWiring;
 
@@ -111,9 +112,9 @@
         return false;
     }
 
-    public synchronized boolean hasDependents(BundleImpl bundle)
+    public synchronized boolean hasDependents(Bundle bundle)
     {
-        List<BundleRevision> revisions = bundle.getRevisions();
+        List<BundleRevision> revisions = bundle.adapt(BundleRevisions.class).getRevisions();
         for (BundleRevision revision : revisions)
         {
             if (hasDependents(revision))
@@ -145,11 +146,11 @@
         return providedWires;
     }
 
-    public synchronized Set<Bundle> getDependentBundles(BundleImpl bundle)
+    public synchronized Set<Bundle> getDependentBundles(Bundle bundle)
     {
         Set<Bundle> result = new HashSet<Bundle>();
 
-        List<BundleRevision> revisions = bundle.getRevisions();
+        List<BundleRevision> revisions = bundle.adapt(BundleRevisions.class).getRevisions();
         for (BundleRevision revision : revisions)
         {
 // TODO: OSGi R4.3 - This is sort of a hack. We need to special case fragments,
@@ -188,7 +189,7 @@
     }
 
     public synchronized Set<Bundle> getImportingBundles(
-        BundleImpl exporter, BundleCapability exportCap)
+        Bundle exporter, BundleCapability exportCap)
     {
         // Create set for storing importing bundles.
         Set<Bundle> result = new HashSet<Bundle>();
@@ -199,7 +200,7 @@
 
         // Get all importers and requirers for all revisions of the bundle.
         // The spec says that require-bundle should be returned with importers.
-        for (BundleRevision revision : exporter.getRevisions())
+        for (BundleRevision revision : exporter.adapt(BundleRevisions.class).getRevisions())
         {
             Map<BundleCapability, Set<BundleWire>>
                 caps = m_dependentsMap.get(revision);
@@ -229,13 +230,13 @@
         return result;
     }
 
-    public synchronized Set<Bundle> getRequiringBundles(BundleImpl bundle)
+    public synchronized Set<Bundle> getRequiringBundles(Bundle bundle)
     {
         // Create set for storing requiring bundles.
         Set<Bundle> result = new HashSet<Bundle>();
 
         // Get all requirers for all revisions of the bundle.
-        for (BundleRevision revision : bundle.getRevisions())
+        for (BundleRevision revision : bundle.adapt(BundleRevisions.class).getRevisions())
         {
             Map<BundleCapability, Set<BundleWire>>
                 caps = m_dependentsMap.get(revision);
@@ -262,9 +263,9 @@
         return result;
     }
 
-    public synchronized void removeDependencies(BundleImpl bundle)
+    public synchronized void removeDependencies(Bundle bundle)
     {
-        List<BundleRevision> revs = bundle.getRevisions();
+        List<BundleRevision> revs = bundle.adapt(BundleRevisions.class).getRevisions();
         for (BundleRevision rev : revs)
         {
             BundleWiring wiring = rev.getWiring();
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index dc496f2..9ee7f28 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -234,39 +234,59 @@
         // Calculate resolved list of capabilities, which includes:
         // 1. All capabilities from host and any fragments except for exported
         //    packages that we have an import (i.e., the export was substituted).
-        // And nothing else at this time.
-        List<BundleCapability> capList = new ArrayList<BundleCapability>();
-        for (BundleCapability cap : m_revision.getDeclaredCapabilities(null))
+        // And nothing else at this time. Fragments currently have no capabilities.
+        boolean isFragment = Util.isFragment(revision);
+        List<BundleCapability> capList = (isFragment)
+            ? Collections.EMPTY_LIST
+            : new ArrayList<BundleCapability>();
+// TODO: OSGi R4.4 - Fragments currently have no capabilities, but they may
+//       have an identity capability in the future.
+        if (!isFragment)
         {
-            if (!cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
-                || (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
-                    && !imports.contains(cap.getAttributes()
-                        .get(BundleRevision.PACKAGE_NAMESPACE).toString())))
+            for (BundleCapability cap : m_revision.getDeclaredCapabilities(null))
             {
-                capList.add(cap);
-            }
-        }
-        if (m_fragments != null)
-        {
-            for (BundleRevision fragment : m_fragments)
-            {
-                for (BundleCapability cap : fragment.getDeclaredCapabilities(null))
+                if (!cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
+                    || (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
+                        && !imports.contains(cap.getAttributes()
+                            .get(BundleRevision.PACKAGE_NAMESPACE).toString())))
                 {
-// TODO: OSGi R4.4 - OSGi R4.4 may introduce an identity capability, if so
-//       that will need to be excluded from here.
-                    capList.add((BundleCapabilityImpl) cap);
-                    if (!cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
-                        || (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
-                            && !imports.contains(cap.getAttributes()
-                                .get(BundleRevision.PACKAGE_NAMESPACE).toString())))
+// TODO: OSGi R4.4 - We may need to make this more flexible since in the future it may
+//       be possible to consider other effective values via OBR's Environment.isEffective().
+                    String effective = cap.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE);
+                    if ((effective == null) || (effective.equals(Constants.EFFECTIVE_RESOLVE)))
                     {
                         capList.add(cap);
                     }
                 }
             }
+            if (m_fragments != null)
+            {
+                for (BundleRevision fragment : m_fragments)
+                {
+                    for (BundleCapability cap : fragment.getDeclaredCapabilities(null))
+                    {
+// TODO: OSGi R4.4 - OSGi R4.4 may introduce an identity capability, if so
+//       that will need to be excluded from here.
+                        if (!cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
+                            || (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
+                                && !imports.contains(cap.getAttributes()
+                                    .get(BundleRevision.PACKAGE_NAMESPACE).toString())))
+                        {
+// TODO: OSGi R4.4 - We may need to make this more flexible since in the future it may
+//       be possible to consider other effective values via OBR's Environment.isEffective().
+                            String effective = cap.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE);
+                            if ((effective == null) || (effective.equals(Constants.EFFECTIVE_RESOLVE)))
+                            {
+                                capList.add(cap);
+                            }
+                        }
+                    }
+                }
+            }
         }
         m_resolvedCaps = Collections.unmodifiableList(capList);
 
+
         List<R4Library> libList = (m_revision.getDeclaredNativeLibraries() == null)
             ? new ArrayList<R4Library>()
             : new ArrayList<R4Library>(m_revision.getDeclaredNativeLibraries());
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 4e5d173..a5e5423 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -23,17 +23,13 @@
 import java.net.*;
 import java.security.*;
 import java.util.*;
-import java.util.Map.Entry;
 import org.apache.felix.framework.ServiceRegistry.ServiceRegistryCallbacks;
 import org.apache.felix.framework.cache.BundleArchive;
 import org.apache.felix.framework.cache.BundleCache;
 import org.apache.felix.framework.capabilityset.CapabilitySet;
 import org.apache.felix.framework.capabilityset.SimpleFilter;
-import org.apache.felix.framework.resolver.ResolverWire;
 import org.apache.felix.framework.ext.SecurityProvider;
 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.util.EventDispatcher;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.ListenerHookInfoImpl;
@@ -44,9 +40,7 @@
 import org.apache.felix.framework.util.ThreadGate;
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.framework.util.manifestparser.R4LibraryClause;
-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.AdminPermission;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
@@ -72,9 +66,8 @@
 import org.osgi.framework.hooks.service.ListenerHook;
 import org.osgi.framework.startlevel.FrameworkStartLevel;
 import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
 import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleRevisions;
 import org.osgi.framework.wiring.FrameworkWiring;
 import org.osgi.service.packageadmin.ExportedPackage;
 import org.osgi.service.startlevel.StartLevel;
@@ -3480,7 +3473,7 @@
             for (Iterator<BundleCapability> it = exports.iterator(); it.hasNext(); )
             {
                 // Get the bundle associated with the current exporting revision.
-                BundleImpl bundle = (BundleImpl) it.next().getRevision().getBundle();
+                Bundle bundle = it.next().getRevision().getBundle();
 
                 // We need to find the version of the exported package, but this
                 // is tricky since there may be multiple versions of the package
@@ -3488,11 +3481,14 @@
                 // bundle JAR file may exist if the bundle was updated without
                 // refreshing the framework. In this case, each revision of the
                 // bundle JAR file is represented as a revision ordered from
-                // oldest to newest. We assume that the first revision found to
+                // newest to oldest. We assume that the first revision found to
                 // be exporting the package is the provider of the package,
                 // which makes sense since it must have been resolved first.
-                for (BundleRevision br : bundle.getRevisions())
+                List<BundleRevision> revisions =
+                    bundle.adapt(BundleRevisions.class).getRevisions();
+                for (int i = revisions.size() - 1; i >= 0; i--)
                 {
+                    BundleRevision br = revisions.get(i);
                     List<BundleCapability> caps = (br.getWiring() == null)
                         ? br.getDeclaredCapabilities(null)
                         : br.getWiring().getCapabilities(null);
@@ -3503,7 +3499,7 @@
                         {
                             pkgs.add(
                                 new ExportedPackageImpl(
-                                    this, bundle, br, cap));
+                                    this, (BundleImpl) bundle, br, cap));
                         }
                     }
                 }
@@ -3587,12 +3583,12 @@
      * @param bundle The bundle from which to retrieve exported packages.
      * @param list The list to which the exported packages are added
     **/
-    private void getExportedPackages(BundleImpl bundle, List list)
+    private void getExportedPackages(Bundle bundle, List list)
     {
         // Since a bundle may have many revisions associated with it,
         // one for each revision in the cache, search each revision
         // to get all exports.
-        for (BundleRevision br : bundle.getRevisions())
+        for (BundleRevision br : bundle.adapt(BundleRevisions.class).getRevisions())
         {
             List<BundleCapability> caps = (br.getWiring() == null)
                 ? br.getDeclaredCapabilities(null)
@@ -3629,7 +3625,8 @@
                                 if ((provider.getRevision().getWiring() != null)
                                     && (provider == cap))
                                 {
-                                    list.add(new ExportedPackageImpl(this, bundle, br, cap));
+                                    list.add(new ExportedPackageImpl(
+                                        this, (BundleImpl) bundle, br, cap));
                                 }
                             }
                         }
diff --git a/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java b/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
index e1f1e70..28a4696 100644
--- a/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
@@ -24,6 +24,7 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleRevisions;
 import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.FrameworkWiring;
 import org.osgi.service.packageadmin.ExportedPackage;
@@ -164,7 +165,7 @@
         {
             List<Bundle> list = new ArrayList<Bundle>();
             // Iterate through revisions
-            for (BundleRevision revision : ((BundleImpl) bundle).getRevisions())
+            for (BundleRevision revision : bundle.adapt(BundleRevisions.class).getRevisions())
             {
                 // Get attached fragments.
                 if (revision.getWiring() != null)
@@ -196,7 +197,7 @@
         {
             List<Bundle> list = new ArrayList<Bundle>();
             // Iterate through revisions
-            for (BundleRevision revision : ((BundleImpl) bundle).getRevisions())
+            for (BundleRevision revision : bundle.adapt(BundleRevisions.class).getRevisions())
             {
                 // Get hosts
                 if (revision.getWiring() != null)
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
index 1be90ea..cdf8e19 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
@@ -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
@@ -23,10 +23,11 @@
 import java.net.URL;
 import java.net.URLConnection;
 import java.security.Permission;
-import java.util.List;
 
 import org.apache.felix.framework.util.Util;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleRevisions;
 
 class URLHandlersBundleURLConnection extends URLConnection
 {
@@ -81,7 +82,7 @@
         //     bundle://<revision-id>:<bundle-classpath-index>/<resource-path>
         // Where <revision-id> = <bundle-id>.<revision>
         long bundleId = Util.getBundleIdFromRevisionId(url.getHost());
-        BundleImpl bundle = (BundleImpl) m_framework.getBundle(bundleId);
+        Bundle bundle = m_framework.getBundle(bundleId);
         if (bundle == null)
         {
             throw new IOException("No bundle associated with resource: " + url);
@@ -89,14 +90,14 @@
         m_contentTime = bundle.getLastModified();
 
         // Get the bundle's revisions to find the target revision.
-        List<BundleRevision> revisions = bundle.getRevisions();
-        if ((revisions == null) || revisions.isEmpty())
+        BundleRevisions revisions = bundle.adapt(BundleRevisions.class);
+        if ((revisions == null) || revisions.getRevisions().isEmpty())
         {
             throw new IOException("Resource does not exist: " + url);
         }
 
         // Search for matching revision name.
-        for (BundleRevision br : revisions)
+        for (BundleRevision br : revisions.getRevisions())
         {
             if (((BundleRevisionImpl) br).getId().equals(url.getHost()))
             {
@@ -108,7 +109,7 @@
         // If not found, assume the current revision.
         if (m_targetRevision == null)
         {
-            m_targetRevision = revisions.get(revisions.size() - 1);
+            m_targetRevision = revisions.getRevisions().get(0);
         }
 
         // If the resource cannot be found at the current class path index,
diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
index 6f267b3..300cd4d 100644
--- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
@@ -64,7 +64,7 @@
         BundleRevision revision, String namespace,
         Map<String, String> dirs, Map<String, Object> attrs)
     {
-        this(revision, namespace, dirs, attrs, convertToFilter(attrs));
+        this(revision, namespace, dirs, Collections.EMPTY_MAP, convertToFilter(attrs));
     }
 
     public String getNamespace()