Author: cziegeler Date: Thu Oct 16 02:58:57 2008 New Revision: 705191 URL: http://svn.apache.org/viewvc?rev=705191&view=rev Log: SLING-699 : Synchronized bundle install/update/start/refresh, and only update bundles if the version number is higher. Fixed some log messages.
Modified: 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/OsgiControllerImpl.java 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=705191&r1=705190&r2=705191&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 Thu Oct 16 02:58:57 2008 @@ -18,6 +18,7 @@ */ package org.apache.sling.jcr.jcrinstall.osgi.impl; +import static org.apache.sling.jcr.jcrinstall.osgi.InstallResultCode.IGNORED; import static org.apache.sling.jcr.jcrinstall.osgi.InstallResultCode.INSTALLED; import static org.apache.sling.jcr.jcrinstall.osgi.InstallResultCode.UPDATED; @@ -37,6 +38,7 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; +import org.osgi.framework.Version; import org.osgi.service.packageadmin.PackageAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,7 +55,6 @@ private final PackageAdmin packageAdmin; private final Map<Long, Bundle> pendingBundles; private final Logger log = LoggerFactory.getLogger(this.getClass()); - private final Object refreshLock = new Object(); BundleResourceProcessor(BundleContext ctx, PackageAdmin packageAdmin) { this.ctx = ctx; @@ -61,56 +62,80 @@ pendingBundles = new HashMap<Long, Bundle>(); } - public int installOrUpdate(String uri, Map<String, Object> attributes, InputStream data) throws Exception { + /** + * @throws BundleException + * @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 { // Update if we already have a bundle id, else install Bundle b = null; boolean updated = false; - // 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); - } + 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); + } - // 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); + // 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; + } + } } - b = getMatchingBundle(data); - } - if (b != null) { - b.update(data); - updated = true; - } else { - uri = OsgiControllerImpl.getResourceLocation(uri); - log.debug("No matching Bundle for uri {}, installing", uri); - b = ctx.installBundle(uri, data); - } + if (b != null) { + b.update(data); + updated = true; + // wait a little bit after an update + try { + Thread.sleep(1500); + } catch (InterruptedException e) { + // ignore + } + } 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()); - synchronized(pendingBundles) { pendingBundles.put(b.getBundleId(), b); } return updated ? UPDATED : INSTALLED; } + /** + * @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); - if(longId == null) { - log.debug("No {} in metadata, bundle cannot be uninstalled"); + if (longId == null) { + 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"); + if (b == null) { + log.debug("Bundle having id {} not found, cannot uninstall", longId); } else { synchronized(pendingBundles) { pendingBundles.remove(b.getBundleId()); @@ -120,69 +145,76 @@ } } + /** + * @see org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor#canProcess(java.lang.String) + */ public boolean canProcess(String uri) { return uri.endsWith(BUNDLE_EXTENSION); } + /** + * @see org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor#processResourceQueue() + */ public void processResourceQueue() { - - if(pendingBundles.isEmpty()) { - return; - } - - final List<Long> toRemove = new LinkedList<Long>(); - final List<Long> idList = new LinkedList<Long>(); synchronized(pendingBundles) { + if (pendingBundles.isEmpty()) { + return; + } + final List<Long> toRemove = new LinkedList<Long>(); + final List<Long> idList = new LinkedList<Long>(); + idList.addAll(pendingBundles.keySet()); - } - 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"); - 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()); + 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); - 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()); + 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; - } - // 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); - } - 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; + } } - } - synchronized(refreshLock) { - packageAdmin.refreshPackages(null); - } + if ( doRefresh ) { + packageAdmin.refreshPackages(null); + } - synchronized(pendingBundles) { pendingBundles.keySet().removeAll(toRemove); } } @@ -210,7 +242,7 @@ * with a symbolic name. * @throws IOException If an error occurrs reading from the input stream. */ - private Bundle getMatchingBundle(InputStream data) throws IOException { + private BundleInfo getMatchingBundle(InputStream data) throws IOException { // allow 2KB, this should be enough for the manifest data.mark(2048); @@ -237,7 +269,10 @@ Bundle[] bundles = ctx.getBundles(); for (Bundle bundle : bundles) { if (symbolicName.equals(bundle.getSymbolicName())) { - return bundle; + final BundleInfo info = new BundleInfo(); + info.bundle = bundle; + info.newVersion = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION); + return info; } } @@ -260,4 +295,9 @@ // fall back to no bundle found for update return null; } + + protected static final class BundleInfo { + public Bundle bundle; + public String newVersion; + } } \ No newline at end of file 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=705191&r1=705190&r2=705191&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 Thu Oct 16 02:58:57 2008 @@ -39,16 +39,16 @@ import org.slf4j.LoggerFactory; /** OsgiController service - * + * * @scr.service - * @scr.component + * @scr.component * immediate="true" * metatype="no" - * @scr.property - * name="service.description" + * @scr.property + * name="service.description" * value="Sling jcrinstall OsgiController Service" - * @scr.property - * name="service.vendor" + * @scr.property + * name="service.vendor" * value="The Apache Software Foundation" */ public class OsgiControllerImpl implements OsgiController, Runnable, SynchronousBundleListener { @@ -58,38 +58,38 @@ private final Logger log = LoggerFactory.getLogger(this.getClass()); private boolean running; private long loopDelay; - + public static final String STORAGE_FILENAME = "controller.storage"; - + /** @scr.reference */ private ConfigurationAdmin configAdmin; - + /** @scr.reference */ private PackageAdmin packageAdmin; - + /** Storage key: last modified as a Long */ public static final String KEY_LAST_MODIFIED = "last.modified"; - + /** Default value for getLastModified() */ public static final long LAST_MODIFIED_NOT_FOUND = -1; - + protected void activate(ComponentContext context) throws IOException { processors = new LinkedList<OsgiResourceProcessor>(); processors.add(new BundleResourceProcessor(context.getBundleContext(), packageAdmin)); 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()); t.setDaemon(true); t.start(); } - + protected void deactivate(ComponentContext oldContext) { running = false; - + if(storage != null) { try { storage.saveToFile(); @@ -100,15 +100,15 @@ storage = null; processors = null; } - + public int installOrUpdate(String uri, long lastModified, InputStream data) throws IOException, JcrInstallException { int result = IGNORED; final OsgiResourceProcessor p = getProcessor(uri); - if(p != null) { + if (p != null) { try { final Map<String, Object> map = storage.getMap(uri); result = p.installOrUpdate(uri, map, data); - if(result != IGNORED) { + if (result != IGNORED) { map.put(KEY_LAST_MODIFIED, new Long(lastModified)); } storage.saveToFile(); @@ -120,7 +120,7 @@ } return result; } - + public void uninstall(String uri) throws JcrInstallException { final OsgiResourceProcessor p = getProcessor(uri); if(p != null) { @@ -133,7 +133,7 @@ } } } - + public Set<String> getInstalledUris() { return storage.getKeys(); } @@ -143,46 +143,46 @@ */ public long getLastModified(String uri) { long result = LAST_MODIFIED_NOT_FOUND; - + if(storage.contains(uri)) { final Map<String, Object> uriData = storage.getMap(uri); - final Long lastMod = (Long)uriData.get(KEY_LAST_MODIFIED); + final Long lastMod = (Long)uriData.get(KEY_LAST_MODIFIED); if(lastMod != null) { result = lastMod.longValue(); } } return result; } - + static String getResourceLocation(String uri) { return "jcrinstall://" + uri; } - + /** Return the first processor that accepts given uri, null if not found */ OsgiResourceProcessor getProcessor(String uri) { OsgiResourceProcessor result = null; - + if(processors == null) { throw new IllegalStateException("Processors are not set"); } - + for(OsgiResourceProcessor p : processors) { if(p.canProcess(uri)) { result = p; break; } } - + if(result == null) { log.debug("No processor found for resource {}", uri); } - + return result; } - + /** Schedule our next scan sooner if anything happens to bundles */ public void bundleChanged(BundleEvent e) { - loopDelay = 0; + //loopDelay = 0; } /** Process our resource queues at regular intervals, more often if @@ -198,7 +198,7 @@ for(OsgiResourceProcessor p : processors) { p.processResourceQueue(); } - + } catch (Exception e) { log.warn("Exception in run()", e); } finally {