Author: pauls
Date: Mon Mar 12 14:07:18 2018
New Revision: 1826549

URL: http://svn.apache.org/viewvc?rev=1826549&view=rev
Log:
FELIX-5803: Auto refresh uninstalled bundle graph if possible

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

Modified: 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java?rev=1826549&r1=1826548&r2=1826549&view=diff
==============================================================================
--- 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
 (original)
+++ 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
 Mon Mar 12 14:07:18 2018
@@ -18,15 +18,7 @@
  */
 package org.apache.felix.framework;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.wiring.BundleWireImpl;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.namespace.HostNamespace;
 import org.osgi.framework.wiring.BundleCapability;
@@ -35,6 +27,14 @@ import org.osgi.framework.wiring.BundleR
 import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.BundleWiring;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 class BundleRevisionDependencies
 {
     private final Map<BundleRevision, Map<BundleCapability, Set<BundleWire>>>
@@ -99,10 +99,15 @@ class BundleRevisionDependencies
         // are actually reversed (i.e., they require a host, but then
         // the host ends up dependent on them at run time).
         if (Util.isFragment(revision)
-            && (revision.getWiring() != null)
-            && !revision.getWiring().getRequiredWires(null).isEmpty())
+            && (revision.getWiring() != null))
         {
-            return true;
+            for (BundleWire bw : revision.getWiring().getRequiredWires(null))
+            {
+                if 
(HostNamespace.HOST_NAMESPACE.equals(bw.getCapability().getNamespace()))
+                {
+                    return true;
+                }
+            }
         }
         else if (m_dependentsMap.containsKey(revision))
         {

Modified: 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=1826549&r1=1826548&r2=1826549&view=diff
==============================================================================
--- 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/Felix.java
 (original)
+++ 
felix/trunk/osgi-r7/framework/src/main/java/org/apache/felix/framework/Felix.java
 Mon Mar 12 14:07:18 2018
@@ -18,39 +18,6 @@
  */
 package org.apache.felix.framework;
 
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLStreamHandler;
-import java.security.AccessControlException;
-import java.security.Permission;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.WeakHashMap;
-
 import org.apache.felix.framework.BundleWiringImpl.BundleClassLoader;
 import org.apache.felix.framework.ServiceRegistry.ServiceRegistryCallbacks;
 import org.apache.felix.framework.cache.BundleArchive;
@@ -103,6 +70,39 @@ import org.osgi.resource.Requirement;
 import org.osgi.service.packageadmin.ExportedPackage;
 import org.osgi.service.resolver.ResolutionException;
 
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLStreamHandler;
+import java.security.AccessControlException;
+import java.security.Permission;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+
 public class Felix extends BundleImpl implements Framework
 {
     // The secure action used to do privileged calls
@@ -354,6 +354,12 @@ public class Felix extends BundleImpl im
                 m_configMutableMap.put(entry.getKey().toString(), 
entry.getValue());
             }
         }
+
+
+        // Get any system bundle activators.
+        m_activatorList = (List) 
m_configMutableMap.remove(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP);
+        m_activatorList = (m_activatorList == null) ? new ArrayList() : new 
ArrayList(m_activatorList);
+
         m_configMap = createUnmodifiableMap(m_configMutableMap);
 
         // Create logger with appropriate log level. Even though the
@@ -674,10 +680,6 @@ public class Felix extends BundleImpl im
                     FelixConstants.FRAMEWORK_UUID,
                     Util.randomUUID());
 
-                // Get any system bundle activators.
-                m_activatorList = (List) 
m_configMutableMap.get(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP);
-                m_activatorList = (m_activatorList == null) ? new ArrayList() 
: new ArrayList(m_activatorList);
-
                 // Initialize event dispatcher.
                 m_dispatcher.startDispatching();
 
@@ -2823,46 +2825,57 @@ public class Felix extends BundleImpl im
         {
             // Populate a set of refresh candidates. This also includes any 
bundles that this bundle
             // is wired to but have previously been uninstalled.
-            List<Bundle> refreshCandidates = new ArrayList<Bundle>();
-            refreshCandidates.add(bundle); // Add this bundle first, so that 
it gets refreshed first
-            BundleRevisions bundleRevisions = 
bundle.adapt(BundleRevisions.class);
-            if (bundleRevisions != null)
+            Set<Bundle> refreshCandidates = addUninstalled(bundle, new 
LinkedHashSet<Bundle>());
+
+            try
             {
-                for (BundleRevision br : bundleRevisions.getRevisions())
+                // First see if we can throw away the complete graph
+                Set<Bundle> dependent = new HashSet<Bundle>();
+                for (Bundle b : refreshCandidates)
                 {
-                    BundleWiring bw = br.getWiring();
-                    if (bw != null)
+                    populateDependentGraph(b, dependent);
+                }
+
+                if (refreshCandidates.containsAll(dependent))
+                {
+                    try
                     {
-                        for (BundleWire wire : bw.getRequiredWires(null))
-                        {
-                            Bundle b = wire.getProvider().getBundle();
-                            if (Bundle.UNINSTALLED == b.getState() && 
!refreshCandidates.contains(b))
-                                refreshCandidates.add(b);
-                        }
+                        refreshPackages(refreshCandidates, null);
+                    }
+                    catch (Exception ex)
+                    {
+                        m_logger.log(this, Logger.LOG_ERROR, "Unable to 
immediately garbage collect bundles.", ex);
                     }
                 }
-            }
-
-            try
-            {
-                for (Bundle b : refreshCandidates)
+                // Otherwise, try to remove one candidate at a time
+                else
                 {
-                    // If the bundle is not used by anyone, then garbage
-                    // collect it now.
-                    if (!m_dependencies.hasDependents(b))
+                    boolean progress;
+                    do
                     {
-                        try
+                        // The idea is to keep trying as long as we make 
progress (ie., managed to gc a bundle)
+                        progress = false;
+                        for (Iterator<Bundle> iter = 
refreshCandidates.iterator(); iter.hasNext();)
                         {
-                            List<Bundle> list = Collections.singletonList(b);
-                            refreshPackages(list, null);
-                        }
-                        catch (Exception ex)
-                        {
-                            m_logger.log(b,
-                                Logger.LOG_ERROR,
-                                "Unable to immediately garbage collect the 
bundle.", ex);
+                            Bundle b = iter.next();
+                            // If the bundle is not used by anyone, then 
garbage
+                            // collect it now.
+                            if (!m_dependencies.hasDependents(b))
+                            {
+                                iter.remove();
+                                try
+                                {
+                                    List<Bundle> list = 
Collections.singletonList(b);
+                                    refreshPackages(list, null);
+                                    progress = true;
+                                }
+                                catch (Exception ex)
+                                {
+                                    m_logger.log(b, Logger.LOG_ERROR, "Unable 
to immediately garbage collect the bundle.", ex);
+                                }
+                            }
                         }
-                    }
+                    } while (progress);
                 }
             }
             finally
@@ -2873,6 +2886,37 @@ public class Felix extends BundleImpl im
         }
     }
 
+    private Set<Bundle> addUninstalled(Bundle bundle, Set<Bundle> 
refreshCandidates)
+    {
+        refreshCandidates.add(bundle); // Add this bundle first, so that it 
gets refreshed first
+        BundleRevisions bundleRevisions = bundle.adapt(BundleRevisions.class);
+        if (bundleRevisions != null)
+        {
+            for (BundleRevision br : bundleRevisions.getRevisions())
+            {
+                BundleWiring bw = br.getWiring();
+                if (bw != null)
+                {
+                    for (BundleWire wire : bw.getRequiredWires(null))
+                    {
+                        Bundle b = wire.getProvider().getBundle();
+                        if (b.getState() == Bundle.UNINSTALLED && 
!refreshCandidates.contains(b))
+                            refreshCandidates = addUninstalled(b, 
refreshCandidates);
+                    }
+                }
+            }
+        }
+        Set<Bundle> dependent = populateDependentGraph(bundle, new 
HashSet<Bundle>());
+        for (Bundle b : dependent)
+        {
+            if (b.getState() == Bundle.UNINSTALLED && 
!refreshCandidates.contains(b))
+            {
+                refreshCandidates = addUninstalled(b, refreshCandidates);
+            }
+        }
+        return refreshCandidates;
+    }
+
     //
     // Implementation of BundleContext interface methods.
     //
@@ -2887,9 +2931,9 @@ public class Felix extends BundleImpl im
     String getProperty(String key)
     {
         // First, check the config properties.
-        String val = (String) m_configMap.get(key);
+        Object val = m_configMap.get(key);
         // If not found, then try the system properties.
-        return (val == null) ? System.getProperty(key) : val;
+        return !(val instanceof String) ? System.getProperty(key) : (String) 
val;
     }
 
     private Bundle reloadBundle(BundleArchive ba)
@@ -4375,7 +4419,7 @@ public class Felix extends BundleImpl im
     }
 
     // Calls to this method must have the global lock.
-    private void populateDependentGraph(BundleImpl exporter, Set<Bundle> set)
+    private Set<Bundle> populateDependentGraph(Bundle exporter, Set<Bundle> 
set)
     {
         // Get all dependent bundles of this bundle.
         Set<Bundle> dependents = m_dependencies.getDependentBundles(exporter);
@@ -4390,10 +4434,11 @@ public class Felix extends BundleImpl im
                     // Add each dependent bundle to set.
                     set.add(b);
                     // Now recurse into each bundle to get its dependents.
-                    populateDependentGraph((BundleImpl) b, set);
+                    set = populateDependentGraph((BundleImpl) b, set);
                 }
             }
         }
+        return set;
     }
 
     Collection<Bundle> getRemovalPendingBundles()


Reply via email to