You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2008/08/25 14:01:10 UTC

svn commit: r688702 - in /incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles: BundleNodeProcessor.java JcrBundlesManager.java

Author: bdelacretaz
Date: Mon Aug 25 05:01:09 2008
New Revision: 688702

URL: http://svn.apache.org/viewvc?rev=688702&view=rev
Log:
SLING-587 - take BundleEvents into account for processing the list of pending bundles

Modified:
    incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundleNodeProcessor.java
    incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java

Modified: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundleNodeProcessor.java
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundleNodeProcessor.java?rev=688702&r1=688701&r2=688702&view=diff
==============================================================================
--- incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundleNodeProcessor.java (original)
+++ incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundleNodeProcessor.java Mon Aug 25 05:01:09 2008
@@ -74,13 +74,7 @@
                 changed = true;
                 newBundle = getBundleContext().installBundle(location, is);
                 if (!isFragment(newBundle)) {
-                    if ((newBundle.getState() & Bundle.RESOLVED) > 0) {
-                        newBundle.start();
-                        log.info("Bundle {} successfully installed and started", location);
-                    } else {
-                        mgr.addPendingBundle(location, newBundle);
-                        log.info("Bundle {} not resolved. delay start", location);
-                    }
+                    mgr.addPendingBundle(location, newBundle);
                 } else {
                     log.info("Fragment bundle {} successfully installed", location);
                 }
@@ -104,8 +98,8 @@
                         log.info("Bundle {} successfully updated", location);
                         status.setProperty("status", "updated");
                     } catch (BundleException e) {
-                        log.info("Bundle {} could not be updated. adding to pending list", location, e);
                         mgr.addPendingBundle(location, oldBundle);
+                        log.info("Bundle {} could not be updated. added to list of pending bundles", location, e);
                     }
                 } else {
                     log.debug("Bundle {} unchanged, no update needed", location);

Modified: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java?rev=688702&r1=688701&r2=688702&view=diff
==============================================================================
--- incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java (original)
+++ incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java Mon Aug 25 05:01:09 2008
@@ -18,13 +18,16 @@
  */
 package org.apache.sling.jcr.jcrbundles;
 
+import static org.apache.sling.jcr.jcrbundles.JcrBundlesConstants.BUNDLES_NODENAME;
+import static org.apache.sling.jcr.jcrbundles.JcrBundlesConstants.STATUS_BASE_PATH;
+
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.Iterator;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -32,12 +35,13 @@
 import javax.jcr.observation.Event;
 
 import org.apache.sling.jcr.api.SlingRepository;
-import static org.apache.sling.jcr.jcrbundles.JcrBundlesConstants.BUNDLES_NODENAME;
-import static org.apache.sling.jcr.jcrbundles.JcrBundlesConstants.STATUS_BASE_PATH;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.packageadmin.PackageAdmin;
-import org.osgi.framework.Bundle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,7 +58,7 @@
  * value="The Apache Software Foundation"
  */
 
-public class JcrBundlesManager implements Runnable {
+public class JcrBundlesManager implements Runnable, SynchronousBundleListener {
     /**
      * Ordered list of root paths to observe for bundles and configs
      * TODO should be configurable
@@ -94,6 +98,8 @@
     private Session session;
     protected final Logger log = LoggerFactory.getLogger(this.getClass());
     private boolean running;
+    private boolean processPendingBundles;
+    private long loopDelay;
 
     private final Map<String, Bundle> pendingBundles = new HashMap<String, Bundle>();
 
@@ -103,6 +109,10 @@
      */
     protected void activate(ComponentContext context) throws RepositoryException {
 
+        // Listen to bundle events to find out if our pending bundles list
+        // needs processing
+        context.getBundleContext().addBundleListener(this);
+        
         // setup our processors
         processors = new LinkedList<NodeProcessor>();
         processors.add(new BundleNodeProcessor(this, context, padmin));
@@ -153,6 +163,8 @@
     protected void deactivate(ComponentContext oldContext) {
         running = false;
 
+        oldContext.getBundleContext().removeBundleListener(this);
+        
         for (BundlesFolder bf : folders) {
             try {
                 bf.cleanup();
@@ -181,18 +193,25 @@
 
     protected void addPendingBundle(String path, Bundle bundle) {
         synchronized (pendingBundles) {
+            processPendingBundles = true;
             pendingBundles.put(path, bundle);
+            log.debug("Bundle {} added to list of pending bundles.", path);
         }
     }
     
     protected void removePendingBundle(String path) {
         synchronized (pendingBundles) {
+            processPendingBundles = true;
             if (pendingBundles.remove(path) != null) {
-                log.info("Removed bundle {} from pending list.", path);
+                log.debug("Removed bundle {} from pending list.", path);
             }
         }
     }
     
+    public void bundleChanged(BundleEvent event) {
+        processPendingBundles = true;
+    }
+
     /**
      * Scan paths once their timer expires
      */
@@ -206,7 +225,7 @@
             statusFolder = new BundlesFolder(repository, STATUS_BASE_PATH, processors);
             final Map<String, Boolean> flags = new HashMap<String, Boolean>();
             statusFolder.checkDeletions(flags);
-            refreshPackagesIfNeeded(flags);
+            refreshAndResolve(flags);
         } catch (Exception e) {
             log.error("Exception during initial scanning of " + STATUS_BASE_PATH, e);
         } finally {
@@ -221,6 +240,7 @@
 
         // We could use the scheduler service but that makes things harder to test
         while (running) {
+            loopDelay = 1000L;
             try {
                 s = repository.loginAdministrative(repository.getDefaultWorkspace());
                 runOneCycle(s);
@@ -237,7 +257,7 @@
                     s = null;
                 }
                 try {
-                    Thread.sleep(1000L);
+                    Thread.sleep(loopDelay);
                 } catch (InterruptedException ignore) {
                     // ignore
                 }
@@ -260,9 +280,9 @@
             }
         }
 
-        // Let ouf BundlesFolders do their work
         final Map<String, Boolean> flags = new HashMap<String, Boolean>();
-
+        
+        // Let our BundlesFolders do their work
         for (BundlesFolder bf : folders) {
             if (!running) {
                 break;
@@ -270,54 +290,86 @@
             bf.scanIfNeeded(flags);
         }
 
-        // try to resolve pending bundles
+        // Process bundles that could not be started or resolved, if any
+        processPendingBundles(flags);
+        
+        // Refresh/resolve packages if needed
+        refreshAndResolve(flags);
+    }
+    
+    /** Process pending bundles if needed */ 
+    private void processPendingBundles(Map<String, Boolean> flags) throws BundleException {
         synchronized (pendingBundles) {
-            boolean tryStart = true;
-            while (tryStart) {
-                tryStart = false;
-                Iterator<String> iter = pendingBundles.keySet().iterator();
-                while (iter.hasNext()) {
-                    String location = iter.next();
-                    Bundle bundle = pendingBundles.get(location);
-                    log.info("Checking bundle {} which status is " + bundle.getState(), location);
-                    if ((bundle.getState() & Bundle.ACTIVE) > 0) {
-                        log.info("Bundle {} is active.", location);
-                        flags.put("refresh.packages", Boolean.TRUE);
-                        flags.put("resolve.bundles", Boolean.TRUE);
-                        iter.remove();
-                    } else if ((bundle.getState() & Bundle.STARTING) > 0) {
-                        log.info("Bundle {} is starting.", location);
-                    } else if ((bundle.getState() & Bundle.STOPPING) > 0) {
-                        log.info("Bundle {} is stopping.", location);
-                    } else if ((bundle.getState() & Bundle.UNINSTALLED) > 0) {
-                        log.info("Bundle {} is uninstalled.", location);
-                        iter.remove();
-                    } else if ((bundle.getState() & Bundle.RESOLVED) > 0) {
-                        log.info("Bundle {} is resolved, starting it.", location);
-                        flags.put("resolve.bundles", Boolean.TRUE);
-                        bundle.start();
-                        tryStart = true;
-                    } else if ((bundle.getState() & Bundle.INSTALLED) > 0) {
-                        log.info("Bundle {} is installed but not resolved.", location);
-                        flags.put("resolve.bundles", Boolean.TRUE);
-                    }
+            
+            // Do nothing if list is empty or if no interesting events happened
+            // since last processed
+            if(!processPendingBundles || pendingBundles.isEmpty()) {
+                return;
+            }
+            processPendingBundles = false;
+            
+            log.debug("Processing {} pending bundles", pendingBundles.size());
+            
+            // If we start or resolve any bundles, trigger the next
+            // scanning loop immediately, as that might allow more
+            // bundles to start
+            boolean scanImmediately = false;
+
+            // Walk the list of pending bundles
+            final Iterator<String> iter = pendingBundles.keySet().iterator();
+            while (iter.hasNext()) {
+                String location = iter.next();
+                Bundle bundle = pendingBundles.get(location);
+                log.debug("Checking bundle {}, current state={}", location, bundle.getState());
+                
+                if ((bundle.getState() & Bundle.ACTIVE) > 0) {
+                    log.info("Bundle {} is active.", location);
+                    flags.put("refresh.packages", Boolean.TRUE);
+                    flags.put("resolve.bundles", Boolean.TRUE);
+                    scanImmediately = true;
+                    processPendingBundles = true;
+                    iter.remove();
+                    
+                } else if ((bundle.getState() & Bundle.STARTING) > 0) {
+                    log.info("Bundle {} is starting.", location);
+                    
+                } else if ((bundle.getState() & Bundle.STOPPING) > 0) {
+                    log.info("Bundle {} is stopping.", location);
+                    
+                } else if ((bundle.getState() & Bundle.UNINSTALLED) > 0) {
+                    log.info("Bundle {} is uninstalled.", location);
+                    processPendingBundles = true;
+                    iter.remove();
+                    
+                } else if ((bundle.getState() & Bundle.RESOLVED) > 0) {
+                    log.info("Bundle {} is resolved, trying to start it.", location);
+                    flags.put("resolve.bundles", Boolean.TRUE);
+                    bundle.start();
+                    scanImmediately = true;
+                    
+                } else if ((bundle.getState() & Bundle.INSTALLED) > 0) {
+                    log.info("Bundle {} is installed but not resolved.", location);
+                    flags.put("resolve.bundles", Boolean.TRUE);
+                    scanImmediately = true;
                 }
             }
-            if (!pendingBundles.isEmpty()) {
-                log.info("Could not start all pending bundles. Still {} remaining.", pendingBundles.size());
+            
+            log.debug("Done processing pending bundles, {} bundles left in list", pendingBundles.size());
+            
+            if(scanImmediately) {
+                loopDelay = 0;
             }
         }
-
-        refreshPackagesIfNeeded(flags);
     }
 
-    void refreshPackagesIfNeeded(Map<String, Boolean> flags) {
+    /** If flags say so, refresh/resolve packages */
+    void refreshAndResolve(Map<String, Boolean> flags) {
         if (Boolean.TRUE.equals(flags.get("resolve.bundles"))) {
-            log.info("Resolving bundles");
+            log.debug("Resolving bundles");
             padmin.resolveBundles(null);
         }
         if (Boolean.TRUE.equals(flags.get("refresh.packages"))) {
-            log.info("Refreshing packages");
+            log.debug("Refreshing packages");
             padmin.refreshPackages(null);
         }
     }