Author: pauls
Date: Fri Mar 16 22:18:39 2018
New Revision: 1827050

URL: http://svn.apache.org/viewvc?rev=1827050&view=rev
Log:
FELIX-5797: Improve the check if we need to try to resolve pending extension by 
ignoring failed extensions. Furthermore, make the resolve smarter by using 
alternatives in lower versions (if there are any) if a higher version fails to 
resolve.

Modified:
    
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java

Modified: 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java?rev=1827050&r1=1827049&r2=1827050&view=diff
==============================================================================
--- 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
 (original)
+++ 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
 Fri Mar 16 22:18:39 2018
@@ -175,6 +175,7 @@ class ExtensionManager implements Conten
 
     private final List<BundleRevisionImpl> m_resolvedExtensions = new 
CopyOnWriteArrayList<BundleRevisionImpl>();
     private final List<BundleRevisionImpl> m_unresolvedExtensions = new 
CopyOnWriteArrayList<BundleRevisionImpl>();
+    private final List<BundleRevisionImpl> m_failedExtensions = new 
CopyOnWriteArrayList<BundleRevisionImpl>();
 
     private static class ExtensionTuple
     {
@@ -399,6 +400,9 @@ class ExtensionManager implements Conten
 
         bri.resolve(null);
 
+        // we have to try again for all previously failed extensions because 
maybe they can now resolve.
+        m_unresolvedExtensions.addAll(m_failedExtensions);
+        m_failedExtensions.clear();
         m_unresolvedExtensions.add(bri);
     }
 
@@ -406,6 +410,7 @@ class ExtensionManager implements Conten
     {
         m_resolvedExtensions.clear();
         m_unresolvedExtensions.clear();
+        m_failedExtensions.clear();
         m_headerMap.clear();
         m_headerMap.putAll(m_originalHeaderMap);
         try
@@ -432,33 +437,40 @@ class ExtensionManager implements Conten
             return Collections.emptyList();
         }
 
-        // Collect all resolved extensions and the highest version of 
unresolved that are not already resolved bsn
-        List<BundleRevisionImpl> extensions = new 
ArrayList<BundleRevisionImpl>(m_resolvedExtensions);
+        // Collect the highest version of unresolved that are not already 
resolved by bsn
+        List<BundleRevisionImpl> extensions = new 
ArrayList<BundleRevisionImpl>();
+        // Collect the unresolved that where filtered out as alternatives in 
case the highest version doesn't resolve
+        List<BundleRevisionImpl> alt = new ArrayList<BundleRevisionImpl>();
 
         outer : for (BundleRevisionImpl revision : m_unresolvedExtensions)
         {
-            if (revision.getWiring() == null) {
-                for (BundleRevisionImpl existing : extensions)
+            // Already resolved by bsn?
+            for (BundleRevisionImpl existing : m_resolvedExtensions)
+            {
+                if 
(existing.getSymbolicName().equals(revision.getSymbolicName()))
                 {
-                    if 
(existing.getSymbolicName().equals(revision.getSymbolicName()))
-                    {
-                        continue outer;
-                    }
+                    // Then ignore it
+                    continue outer;
                 }
-                for (BundleRevisionImpl other : m_unresolvedExtensions)
+            }
+            // Otherwise, does a higher version exist by bsn?
+            for (BundleRevisionImpl other : m_unresolvedExtensions)
+            {
+                if ((revision != other) && 
(revision.getSymbolicName().equals(other.getSymbolicName())) &&
+                    revision.getVersion().compareTo(other.getVersion()) < 0)
                 {
-                    if ((revision != other) && 
(revision.getSymbolicName().equals(other.getSymbolicName())) &&
-                        revision.getVersion().compareTo(other.getVersion()) < 
0)
-                    {
-                        continue outer;
-                    }
+                    // Add this one to alternatives and filter it
+                    alt.add(revision);
+                    continue outer;
                 }
-
-                extensions.add(revision);
             }
+
+            // no higher version and not resolved yet by bsn - try to resolve 
it
+            extensions.add(revision);
         }
 
-        Map<BundleRevisionImpl, List<BundleWire>> wirings = 
findResolvableExtensions(extensions);
+        // This will return all resolvable revisions with the wires they need
+        Map<BundleRevisionImpl, List<BundleWire>> wirings = 
findResolvableExtensions(extensions, alt);
 
         List<Bundle> result = new ArrayList<Bundle>();
 
@@ -466,6 +478,7 @@ class ExtensionManager implements Conten
         {
             BundleRevisionImpl revision = entry.getKey();
 
+            // move this revision from unresolved to resolved
             m_unresolvedExtensions.remove(revision);
             m_resolvedExtensions.add(revision);
 
@@ -528,6 +541,10 @@ class ExtensionManager implements Conten
             result.add(revision.getBundle());
         }
 
+        // at this point, all revisions left in unresolved are not resolvable
+        m_failedExtensions.addAll(m_unresolvedExtensions);
+        m_unresolvedExtensions.clear();
+
         if (!wirings.isEmpty())
         {
             felix.getResolver().addRevision(getRevision());
@@ -650,80 +667,115 @@ class ExtensionManager implements Conten
         m_extensionTuples.clear();
     }
 
-    private Map<BundleRevisionImpl, List<BundleWire>> 
findResolvableExtensions(List<BundleRevisionImpl> extensions)
+    private Map<BundleRevisionImpl, List<BundleWire>> 
findResolvableExtensions(List<BundleRevisionImpl> extensions, 
List<BundleRevisionImpl> alt)
     {
         // The idea is to loop through the extensions and try to resolve all 
unresolved extension. If we can't resolve
-        // a given extension, we will call the method again with the extension 
in question removed.
+        // a given extension, we will call the method again with the extension 
in question removed or replaced if there
+        // is a replacement for it in alt.
+        // This resolve doesn't take into account that maybe a revision could 
be resolved with a revision from alt but
+        // not with the current extensions. In that case, it will be removed 
(assuming the current extension can be resolved)
+        // in other words, it will prefer to resolve the highest version of 
each extension over install order
         Map<BundleRevisionImpl, List<BundleWire>> wires = new 
LinkedHashMap<BundleRevisionImpl, List<BundleWire>>();
 
         for (BundleRevisionImpl bri : extensions)
         {
-            // Ignore resolved extensions
-            if (bri.getWiring() == null)
+            List<BundleWire> wi = new ArrayList<BundleWire>();
+            boolean resolved = true;
+            outer: for (BundleRequirement req : 
bri.getDeclaredRequirements(null))
             {
-                List<BundleWire> wi = new ArrayList<BundleWire>();
-                boolean resolved = true;
-                outer: for (BundleRequirement req : 
bri.getDeclaredRequirements(null))
+                // first see if we can resolve from the system bundle
+                for (BundleCapability cap : 
getCapabilities(req.getNamespace()))
                 {
-                    // first see if we can resolve from the system bundle
-                    for (BundleCapability cap : 
getCapabilities(req.getNamespace()))
+                    if (req.matches(cap))
+                    {
+                        // we can, create the wire but in the case of an ee 
requirement, make it from the extension
+                        wi.add(new BundleWireImpl(
+                                
req.getNamespace().equals(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE)
 ?
+                                        bri : m_systemBundleRevision, req, 
m_systemBundleRevision, cap));
+
+                        continue outer;
+                    }
+                }
+
+                // now loop through the resolved extensions
+                for (BundleRevisionImpl extension : m_resolvedExtensions)
+                {
+                    // and check the caps that will not be lifted (i.e., 
identity)
+                    for (BundleCapability cap : 
extension.getDeclaredCapabilities(req.getNamespace()))
                     {
                         if (req.matches(cap))
                         {
-                            // we can, create the wire but in the case of an 
ee requirement, make it from the extension
-                            wi.add(new BundleWireImpl(
-                                    
req.getNamespace().equals(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE)
 ?
-                                            bri : m_systemBundleRevision, req, 
m_systemBundleRevision, cap));
-
+                            // it was identity - hence, use the extension 
itself as provider
+                            wi.add(new BundleWireImpl(m_systemBundleRevision, 
req, extension, cap));
                             continue outer;
                         }
                     }
-
-                    // now loop through the other extensions
-                    for (BundleRevisionImpl extension : extensions)
+                }
+                // now loop through the other extensions
+                for (BundleRevisionImpl extension : extensions)
+                {
+                    // check the caps that will be lifted to the system bundle
+                    for (BundleCapability cap : 
extension.getDeclaredExtensionCapabilities(req.getNamespace()))
                     {
-                        // check the caps that will be lifted to the system 
bundle
-                        for (BundleCapability cap : 
extension.getDeclaredExtensionCapabilities(req.getNamespace()))
+                        if (req.matches(cap))
                         {
-                            if (req.matches(cap))
-                            {
-                                // we could use a yet unresolved extension 
(resolved one are implicitly checked by the
-                                // system bundle loop above as they would be 
attached.
-                                wi.add(new 
BundleWireImpl(m_systemBundleRevision, req, m_systemBundleRevision, cap));
-                                continue outer;
-                            }
+                            // we can use a yet unresolved extension (resolved 
one are implicitly checked by the
+                            // system bundle loop above as they would be 
attached.
+                            wi.add(new BundleWireImpl(m_systemBundleRevision, 
req, m_systemBundleRevision, cap));
+                            continue outer;
+                        }
+                    }
+                    // and check the caps that will not be lifted (i.e., 
identity)
+                    for (BundleCapability cap : 
extension.getDeclaredCapabilities(req.getNamespace()))
+                    {
+                        if (req.matches(cap))
+                        {
+                            // it was identity - hence, use the extension 
itself as provider
+                            wi.add(new BundleWireImpl(m_systemBundleRevision, 
req, extension, cap));
+                            continue outer;
                         }
+                    }
+                }
+                // we couldn't find a provider - was it optional?
+                if (!((BundleRequirementImpl)req).isOptional())
+                {
+                    resolved = false;
+                    break;
+                }
+            }
+            if(resolved)
+            {
+                wires.put(bri, wi);
+            }
+            else
+            {
+                // we failed to resolve this extension - try again without it. 
Yes, this throws away the work done
+                // up to this point
+                List<BundleRevisionImpl> next = new 
ArrayList<BundleRevisionImpl>(extensions);
+                List<BundleRevisionImpl> nextAlt = new 
ArrayList<BundleRevisionImpl>();
 
-                        // now check the caps that will not be lifted (i.e., 
identity)
-                        for (BundleCapability cap : 
extension.getDeclaredCapabilities(req.getNamespace()))
+                outer : for (BundleRevisionImpl replacement : alt)
+                {
+                    if 
(bri.getSymbolicName().equals(replacement.getSymbolicName()))
+                    {
+                        for (BundleRevisionImpl other : alt)
                         {
-                            if (req.matches(cap))
+                            if ((replacement != other) && 
(replacement.getSymbolicName().equals(other.getSymbolicName())) &&
+                                    
replacement.getVersion().compareTo(other.getVersion()) < 0)
                             {
-                                // it was identity - hence, use the extension 
itself as provider
-                                wi.add(new 
BundleWireImpl(m_systemBundleRevision, req, extension, cap));
+                                nextAlt.add(replacement);
                                 continue outer;
                             }
                         }
-                    }
-                    // we couldn't find a provider - was it optional?
-                    if (!((BundleRequirementImpl)req).isOptional())
-                    {
-                        resolved = false;
+                        next.set(next.indexOf(bri), replacement);
                         break;
                     }
+                    nextAlt.add(replacement);
                 }
-                if(resolved)
-                {
-                    wires.put(bri, wi);
-                }
-                else
-                {
-                    // we failed to resolve this extension - try again without 
it. Yes, this throws away the work done
-                    // up to this point
-                    List<BundleRevisionImpl> next = new 
ArrayList<BundleRevisionImpl>(extensions);
-                    next.remove(bri);
-                    return next.isEmpty() ? Collections.EMPTY_MAP : 
findResolvableExtensions(next);
-                }
+                
+                next.remove(bri);
+
+                return next.isEmpty() ? Collections.EMPTY_MAP : 
findResolvableExtensions(next, nextAlt);
             }
         }
         return wires;


Reply via email to