incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fmesc...@apache.org
Subject svn commit: r708590 - in /incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi: OsgiResourceProcessor.java impl/BundleResourceProcessor.java impl/ConfigResourceProcessor.java impl/OsgiControllerImpl.java
Date Tue, 28 Oct 2008 14:56:05 GMT
Author: fmeschbe
Date: Tue Oct 28 07:56:04 2008
New Revision: 708590

URL: http://svn.apache.org/viewvc?rev=708590&view=rev
Log:
SLING-709 simplify BundleResourceProcessor tasks:
  * stop bundles before update (start them later again)
  * only refreshPackages if bundles have been updated
    or removed
  * record active bundles before refreshPackages
  * start stopped/installed/updated bundles after
    refreshPackages
  * if refreshPackages is not called, directly start
    installed/updated bundles

Modified:
    incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiResourceProcessor.java
    incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessor.java
    incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/ConfigResourceProcessor.java
    incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java

Modified: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiResourceProcessor.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiResourceProcessor.java?rev=708590&r1=708589&r2=708590&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiResourceProcessor.java
(original)
+++ incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiResourceProcessor.java
Tue Oct 28 07:56:04 2008
@@ -50,4 +50,9 @@
      *  to start outstanding bundles.
      */
     void processResourceQueue() throws Exception;
+    
+    /**
+     * Called to cleanup the resource processor when it is not needed anymore.
+     */
+    void dispose();
 }

Modified: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessor.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessor.java?rev=708590&r1=708589&r2=708590&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessor.java
(original)
+++ incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessor.java
Tue Oct 28 07:56:04 2008
@@ -26,10 +26,14 @@
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
 
@@ -38,13 +42,16 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.Version;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /** OsgiResourceProcessor for Bundles */
-public class BundleResourceProcessor implements OsgiResourceProcessor {
+public class BundleResourceProcessor implements OsgiResourceProcessor,
+        FrameworkListener {
 
     public static final String BUNDLE_EXTENSION = ".jar";
 
@@ -52,95 +59,155 @@
     public static final String KEY_BUNDLE_ID = "bundle.id";
 
     private final BundleContext ctx;
+
     private final PackageAdmin packageAdmin;
-    private final Map<Long, Bundle> pendingBundles;
+
+    /**
+     * All bundles which were active before {@link #processResourceQueue()}
+     * refreshes the packages. Bundles which may not be started after refreshing
+     * the packages remain in this set. In addition bundles from the
+     * {@link #installedBundles} bundles list will be added here to try to start
+     * them in the next round.
+     */
+    private final Set<Long> activeBundles;
+    
+    /**
+     * The list of bundles which have been updated or installed and which need
+     * to be started in the next round. Bundles from this list, which fail
+     * to start, are added to the {@link #activeBundles} set for them to be
+     * started in the next round.
+     */
+    private final List<Long> installedBundles;
+    
+    /**
+     * Flag set by {@link #installOrUpdate(String, Map, InputStream)} of a
+     * bundle has been updated and by {@link #uninstall(String, Map)} if a
+     * bundle has been removed. This causes the {@link #processResourceQueue()}
+     * method to refresh the packages.
+     * @see #processResourceQueue()
+     */
+    private boolean needsRefresh;
+    
     private final Logger log = LoggerFactory.getLogger(this.getClass());
 
     BundleResourceProcessor(BundleContext ctx, PackageAdmin packageAdmin) {
         this.ctx = ctx;
         this.packageAdmin = packageAdmin;
-        pendingBundles = new HashMap<Long, Bundle>();
+        this.activeBundles = new HashSet<Long>();
+        this.installedBundles = new ArrayList<Long>();
+
+        // register as a framework listener
+        ctx.addFrameworkListener(this);
+    }
+
+    public void dispose() {
+        // unregister as a framework listener
+        ctx.removeFrameworkListener(this);
     }
 
+    // ---------- FrameworkListener
+
+    /**
+     * Handles the PACKAGES_REFRESHED framework event which is sent after
+     * the PackageAdmin.refreshPackages has finished its work of refreshing
+     * the packages. When packages have been refreshed all bundles which are
+     * expected to be active (those active before refreshing the packages and
+     * newly installed or updated bundles) are started. 
+     */
+    public void frameworkEvent(FrameworkEvent event) {
+        if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
+            startBundles();
+        }
+    }
+
+    // ---------- OsgiResourceProcessor
+
     /**
      * @throws BundleException
-     * @see org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor#installOrUpdate(java.lang.String,
java.util.Map, java.io.InputStream)
+     * @see org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor#installOrUpdate(java.lang.String,
+     *      java.util.Map, java.io.InputStream)
      */
-    public int installOrUpdate(String uri, Map<String, Object> attributes, InputStream
data)
-    throws BundleException, IOException {
+    public int installOrUpdate(String uri, Map<String, Object> attributes,
+            InputStream data) throws BundleException, IOException {
         // Update if we already have a bundle id, else install
         Bundle b = null;
         boolean updated = false;
 
-        synchronized (pendingBundles) {
-            // check whether we know the bundle and it exists
-            final Long longId = (Long)attributes.get(KEY_BUNDLE_ID);
-            if (longId != null) {
-                b = ctx.getBundle(longId);
-            }
+        // check whether we know the bundle and it exists
+        final Long longId = (Long) attributes.get(KEY_BUNDLE_ID);
+        if (longId != null) {
+            b = ctx.getBundle(longId);
+        }
 
-            // either we don't know the bundle yet or it does not exist,
-            // so check whether the bundle can be found by its symbolic name
-            if (b == null) {
-                // ensure we can mark and reset to read the manifest
-                if (!data.markSupported()) {
-                    data = new BufferedInputStream(data);
-                }
-                final BundleInfo info = getMatchingBundle(data);
-                if ( info != null ) {
-                    final Version availableVersion = new Version((String)info.bundle.getHeaders().get(Constants.BUNDLE_VERSION));
-                    final Version newVersion = new Version(info.newVersion);
-                    if ( newVersion.compareTo(availableVersion) > 0 ) {
-                        b = info.bundle;
-                    } else {
-                        log.debug("Ignore update of bundle {} from {} as the installed version
is equal or higher.", info.bundle.getSymbolicName(), uri);
-                        return IGNORED;
-                    }
-                }
+        // either we don't know the bundle yet or it does not exist,
+        // so check whether the bundle can be found by its symbolic name
+        if (b == null) {
+            // ensure we can mark and reset to read the manifest
+            if (!data.markSupported()) {
+                data = new BufferedInputStream(data);
             }
-
-            if (b != null) {
-                b.update(data);
-                updated = true;
-                // wait a little bit after an update
-                try {
-                    Thread.sleep(1500);
-                } catch (InterruptedException e) {
-                    // ignore
+            final BundleInfo info = getMatchingBundle(data);
+            if (info != null) {
+                final Version availableVersion = new Version(
+                    (String) info.bundle.getHeaders().get(
+                        Constants.BUNDLE_VERSION));
+                final Version newVersion = new Version(info.newVersion);
+                if (newVersion.compareTo(availableVersion) > 0) {
+                    b = info.bundle;
+                } else {
+                    log.debug(
+                        "Ignore update of bundle {} from {} as the installed version is equal
or higher.",
+                        info.bundle.getSymbolicName(), uri);
+                    return IGNORED;
                 }
-            } else {
-                uri = OsgiControllerImpl.getResourceLocation(uri);
-                log.debug("No matching Bundle for uri {}, installing", uri);
-                b = ctx.installBundle(uri, data);
             }
+        }
+
+        if (b != null) {
+            b.stop();
+            b.update(data);
+            updated = true;
+            needsRefresh = true;
+        } else {
+            uri = OsgiControllerImpl.getResourceLocation(uri);
+            log.debug("No matching Bundle for uri {}, installing", uri);
+            b = ctx.installBundle(uri, data);
+        }
 
-            // ensure the bundle id in the attributes, this may be overkill
-            // in simple update situations, but is required for installations
-            // and updates where there are no attributes yet
-            attributes.put(KEY_BUNDLE_ID, b.getBundleId());
+        // ensure the bundle id in the attributes, this may be overkill
+        // in simple update situations, but is required for installations
+        // and updates where there are no attributes yet
+        attributes.put(KEY_BUNDLE_ID, b.getBundleId());
 
-            pendingBundles.put(b.getBundleId(), b);
+        synchronized (activeBundles) {
+            installedBundles.add(b.getBundleId());
         }
 
         return updated ? UPDATED : INSTALLED;
     }
 
     /**
-     * @see org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor#uninstall(java.lang.String,
java.util.Map)
+     * @see org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor#uninstall(java.lang.String,
+     *      java.util.Map)
      */
-    public void uninstall(String uri, Map<String, Object> attributes) throws BundleException
{
-        final Long longId = (Long)attributes.get(KEY_BUNDLE_ID);
+    public void uninstall(String uri, Map<String, Object> attributes)
+            throws BundleException {
+        final Long longId = (Long) attributes.get(KEY_BUNDLE_ID);
         if (longId == null) {
-            log.debug("No bundle id in metadata for {}, bundle cannot be uninstalled.", uri);
+            log.debug(
+                "No bundle id in metadata for {}, bundle cannot be uninstalled.",
+                uri);
         } else {
             final Bundle b = ctx.getBundle(longId);
             if (b == null) {
-                log.debug("Bundle having id {} not found, cannot uninstall", longId);
+                log.debug("Bundle having id {} not found, cannot uninstall",
+                    longId);
             } else {
-                synchronized(pendingBundles) {
-                    pendingBundles.remove(b.getBundleId());
+                synchronized (installedBundles) {
+                    installedBundles.remove(b.getBundleId());
                 }
                 b.uninstall();
+                needsRefresh = true;
             }
         }
     }
@@ -153,69 +220,34 @@
     }
 
     /**
-     * @see org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor#processResourceQueue()
+     * Refreshes packages with subsequence bundle start or directly starts
+     * installed bundles. If since the last call to this method a bundle has
+     * been updated or removed, the packages will be refreshed. If no update
+     * or uninstallation has taken place, we still try to start all bundles
+     * which we expect to be started (mostly bundles which have recently been
+     * installed) but without refreshing the packages first.
      */
     public void processResourceQueue() {
-        synchronized(pendingBundles) {
-            if (pendingBundles.isEmpty()) {
-                return;
-            }
-            final List<Long> toRemove = new LinkedList<Long>();
-            final List<Long> idList = new LinkedList<Long>();
-
-            idList.addAll(pendingBundles.keySet());
-
-            boolean doRefresh = false;
-
-            for(Long id : idList) {
-                final Bundle bundle = ctx.getBundle(id);
-                if(bundle == null) {
-                    log.debug("Bundle id {} disappeared (bundle removed from framework?),
removed from pending bundles queue", id);
-                    toRemove.add(id);
-                    continue;
-                }
-                final int state = bundle.getState();
-
-                switch ( state ) {
-                    case Bundle.ACTIVE :
-                        log.info("Bundle {} is active, removed from pending bundles queue",
bundle.getLocation());
-                        toRemove.add(id);
-                        break;
-                    case Bundle.STARTING :
-                        log.info("Bundle {} is starting.", bundle.getLocation());
-                        break;
-                    case Bundle.STOPPING :
-                        log.info("Bundle {} is stopping.", bundle.getLocation());
-                        break;
-                    case Bundle.UNINSTALLED :
-                        log.info("Bundle {} is uninstalled, removed from pending bundles
queue", bundle.getLocation());
-                        toRemove.add(id);
-                        doRefresh = true;
-                        break;
-                    case Bundle.INSTALLED :
-                        log.debug("Bundle {} is installed but not resolved.", bundle.getLocation());
-                        if ( !packageAdmin.resolveBundles(new Bundle[] {bundle}) ) {
-                            log.debug("Bundle {} is installed, failed to resolve.", bundle.getLocation());
-                            break;
-                        }
-                        // fall through to RESOLVED to start the bundle
-                    case Bundle.RESOLVED :
-                        log.info("Bundle {} is resolved, trying to start it.", bundle.getLocation());
-                        try {
-                            bundle.start();
-                        } catch (BundleException e) {
-                            log.error("Exception during bundle start of Bundle " + bundle.getLocation(),
e);
-                        }
-                        doRefresh = true;
-                        break;
+        if (needsRefresh) {
+            
+            // reset the flag
+            needsRefresh = false;
+            
+            // gather bundles currently active
+            for (Bundle bundle : ctx.getBundles()) {
+                if (bundle.getState() == Bundle.ACTIVE) {
+                    synchronized (activeBundles) {
+                        activeBundles.add(bundle.getBundleId());
+                    }
                 }
             }
 
-            if ( doRefresh ) {
-                packageAdmin.refreshPackages(null);
-            }
-
-            pendingBundles.keySet().removeAll(toRemove);
+            // refresh now
+            packageAdmin.refreshPackages(null);
+            
+        } else {
+            
+            startBundles();
         }
     }
 
@@ -232,7 +264,7 @@
      * methods to reset the stream to where it started reading. The caller must
      * make sure, the input stream supports the marking as reported by
      * <code>InputStream.markSupported</code>.
-     *
+     * 
      * @param data The mark supporting <code>InputStream</code> providing the
      *            bundle whose symbolic name is to be matched against installed
      *            bundles.
@@ -271,7 +303,8 @@
                         if (symbolicName.equals(bundle.getSymbolicName())) {
                             final BundleInfo info = new BundleInfo();
                             info.bundle = bundle;
-                            info.newVersion = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+                            info.newVersion = manifest.getMainAttributes().getValue(
+                                Constants.BUNDLE_VERSION);
                             return info;
                         }
                     }
@@ -298,6 +331,54 @@
 
     protected static final class BundleInfo {
         public Bundle bundle;
+
         public String newVersion;
     }
+
+    /**
+     * Starts all bundles which have been stopped during package refresh and
+     * all bundles, which have been freshly installed.
+     */
+    private void startBundles() {
+        startBundles(activeBundles);
+        startBundles(installedBundles);
+    }
+    
+    /**
+     * Starts all bundles whose bundle ID is contained in the
+     * <code>bundleCollection</code>. If a bundle fails to start, its bundle
+     * ID is added to the list of active bundles again for the bundle to
+     * bestarted next time the packages are refreshed or the resource queue is
+     * processed.
+     * 
+     * @param bundleIdCollection The IDs of bundles to be started.
+     */
+    private void startBundles(Collection<Long> bundleIdCollection) {
+        // get the bundle ids and remove them from the collection
+        Long[] bundleIds;
+        synchronized (bundleIdCollection) {
+            bundleIds = bundleIdCollection.toArray(new Long[bundleIdCollection.size()]);
+            bundleIdCollection.clear();
+        }
+
+        for (Long bundleId : bundleIds) {
+            Bundle bundle = ctx.getBundle(bundleId);
+            if (bundle.getState() != Bundle.ACTIVE) {
+                log.info("Starting Bundle {}/{} ", bundle.getSymbolicName(),
+                    bundle.getBundleId());
+                try {
+                    bundle.start();
+                } catch (BundleException be) {
+                    log.error("Failed starting Bundle {}/{}",
+                        bundle.getSymbolicName(), bundle.getBundleId());
+
+                    // add the failed bundle to the activeBundles list
+                    // to start them after the next refresh
+                    synchronized (activeBundles) {
+                        activeBundles.add(bundleId);
+                    }
+                }
+            }
+        }
+    }
 }
\ No newline at end of file

Modified: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/ConfigResourceProcessor.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/ConfigResourceProcessor.java?rev=708590&r1=708589&r2=708590&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/ConfigResourceProcessor.java
(original)
+++ incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/ConfigResourceProcessor.java
Tue Oct 28 07:56:04 2008
@@ -46,6 +46,10 @@
         configurationAdmin = ca;
     }
     
+    public void dispose() {
+        // nothing to do
+    }
+    
     public boolean canProcess(String uri) {
         return uri.endsWith(CONFIG_EXTENSION);
     }

Modified: incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java?rev=708590&r1=708589&r2=708590&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java
(original)
+++ incubator/sling/trunk/extensions/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java
Tue Oct 28 07:56:04 2008
@@ -30,7 +30,12 @@
 import org.apache.sling.jcr.jcrinstall.osgi.JcrInstallException;
 import org.apache.sling.jcr.jcrinstall.osgi.OsgiController;
 import org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.component.ComponentContext;
@@ -79,7 +84,7 @@
         processors.add(new ConfigResourceProcessor(configAdmin));
 
         storage = new Storage(context.getBundleContext().getDataFile(STORAGE_FILENAME));
-
+        
         // start queue processing
         running = true;
         final Thread t = new Thread(this, getClass().getSimpleName() + "_" + System.currentTimeMillis());
@@ -97,10 +102,17 @@
                 log.warn("IOException in Storage.saveToFile()", ioe);
             }
         }
+        
+        if (processors != null) {
+            for (OsgiResourceProcessor processor : processors) {
+                processor.dispose();
+            }
+        }
+        
         storage = null;
         processors = null;
     }
-
+    
     public int installOrUpdate(String uri, long lastModified, InputStream data) throws IOException,
JcrInstallException {
         int result = IGNORED;
         final OsgiResourceProcessor p = getProcessor(uri);
@@ -198,7 +210,6 @@
                 for(OsgiResourceProcessor p : processors) {
                     p.processResourceQueue();
                 }
-
             } catch (Exception e) {
                 log.warn("Exception in run()", e);
             } finally {



Mime
View raw message