You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2010/09/10 09:41:57 UTC
svn commit: r995689 [1/2] - in /sling/trunk/installer:
fileinstall/src/main/java/org/apache/sling/installer/file/impl/
jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/
jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/...
Author: cziegeler
Date: Fri Sep 10 07:41:55 2010
New Revision: 995689
URL: http://svn.apache.org/viewvc?rev=995689&view=rev
Log:
SLING-1737 : Add state management for resources
Added:
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/ChangeStateTask.java (with props)
Modified:
sling/trunk/installer/fileinstall/src/main/java/org/apache/sling/installer/file/impl/Installer.java
sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/PersistentResourceList.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/AbstractConfigTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigInstallTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigRemoveTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigTaskCreator.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleRemoveTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleTaskCreator.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleUpdateTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/SynchronousRefreshPackagesTask.java
sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/SystemBundleUpdateTask.java
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/MockBundleResource.java
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/RegisteredResourceComparatorTest.java
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/TaskOrderingTest.java
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/tasks/BundleTaskCreatorTest.java
sling/trunk/installer/osgi/installer/src/test/java/org/apache/sling/osgi/installer/impl/tasks/MockBundleTaskCreator.java
sling/trunk/installer/osgi/it/pom.xml
sling/trunk/installer/osgi/it/src/test/java/org/apache/sling/osgi/installer/it/BundleInstallStressTest.java
sling/trunk/installer/osgi/it/src/test/java/org/apache/sling/osgi/installer/it/BundleInstallUpgradeDowngradeTest.java
sling/trunk/installer/osgi/it/src/test/java/org/apache/sling/osgi/installer/it/InvalidBundlesTest.java
sling/trunk/installer/osgi/it/src/test/java/org/apache/sling/osgi/installer/it/OsgiInstallerTestBase.java
sling/trunk/installer/osgi/it/src/test/java/org/apache/sling/osgi/installer/it/RegisterResourcesTest.java
sling/trunk/installer/osgi/it/src/test/java/org/apache/sling/osgi/installer/it/RemovedResourceDetectionTest.java
Modified: sling/trunk/installer/fileinstall/src/main/java/org/apache/sling/installer/file/impl/Installer.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/fileinstall/src/main/java/org/apache/sling/installer/file/impl/Installer.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/fileinstall/src/main/java/org/apache/sling/installer/file/impl/Installer.java (original)
+++ sling/trunk/installer/fileinstall/src/main/java/org/apache/sling/installer/file/impl/Installer.java Fri Sep 10 07:41:55 2010
@@ -85,7 +85,7 @@ public class Installer implements FileCh
resources.add(resource);
}
}
- this.installer.registerResources(this.scheme, resources);
+ this.installer.registerResources(this.scheme, resources.toArray(new InstallableResource[resources.size()]));
}
private InstallableResource createResource(final File file) {
Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java Fri Sep 10 07:41:55 2010
@@ -190,7 +190,7 @@ public class JcrInstaller implements Eve
}
log.debug("Registering {} resources with OSGi installer: {}", resources.size(), resources);
- installer.registerResources(URL_SCHEME, resources);
+ installer.registerResources(URL_SCHEME, resources.toArray(new InstallableResource[resources.size()]));
} catch (final RepositoryException re) {
log.error("Repository exception during startup - deactivating installer!", re);
active = false;
Modified: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java Fri Sep 10 07:41:55 2010
@@ -18,7 +18,6 @@
*/
package org.apache.sling.jcr.jcrinstall.impl;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@@ -67,14 +66,16 @@ class MockOsgiInstaller implements OsgiI
}
/**
- * @see org.apache.sling.osgi.installer.OsgiInstaller#registerResources(java.lang.String, java.util.Collection)
+ * @see org.apache.sling.osgi.installer.OsgiInstaller#registerResources(java.lang.String, org.apache.sling.osgi.installer.InstallableResource[])
*/
- public void registerResources(String urlScheme, Collection<InstallableResource> data) {
+ public void registerResources(String urlScheme, final InstallableResource[] data) {
// Sort the data to allow comparing the recorded calls reliably
final List<InstallableResource> sorted = new LinkedList<InstallableResource>();
- sorted.addAll(data);
+ for(final InstallableResource r : data) {
+ sorted.add(r);
+ }
Collections.sort(sorted, new InstallableResourceComparator());
- for(InstallableResource r : data) {
+ for(InstallableResource r : sorted) {
urls.add(urlScheme + ':' + r.getId());
recordCall("register", urlScheme, r);
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/OsgiInstaller.java Fri Sep 10 07:41:55 2010
@@ -18,7 +18,6 @@
*/
package org.apache.sling.osgi.installer;
-import java.util.Collection;
/**
* OSGi Service that installs/updates/removes installable data
@@ -45,9 +44,9 @@ public interface OsgiInstaller {
* Invalid resources are ignored.
*
* @param urlScheme identifies the client.
- * @param data the list of available resources
+ * @param resources the list of available resources
*/
- void registerResources(String urlScheme, Collection<InstallableResource> data);
+ void registerResources(String urlScheme, InstallableResource[] resources);
/**
* Inform the installer that resources are available for installation
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerImpl.java Fri Sep 10 07:41:55 2010
@@ -20,11 +20,16 @@ package org.apache.sling.osgi.installer.
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+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.SortedSet;
import java.util.TreeSet;
@@ -50,40 +55,59 @@ import org.osgi.framework.FrameworkListe
*/
public class OsgiInstallerImpl
extends Thread
- implements BundleListener, FrameworkListener,
- OsgiInstaller {
+ implements BundleListener, FrameworkListener, OsgiInstaller {
+ /** The bundle context. */
private final BundleContext ctx;
+
+ /** New clients are joining through this map. */
+ private final Map<String, List<RegisteredResource>> newResourcesSchemes = new HashMap<String, List<RegisteredResource>>();
+
+ /** New resources added by clients. */
private final List<RegisteredResource> newResources = new LinkedList<RegisteredResource>();
- private final SortedSet<OsgiInstallerTask> tasksForNextCycle = new TreeSet<OsgiInstallerTask>();
- private final List<SortedSet<RegisteredResource>> newResourcesSets = new ArrayList<SortedSet<RegisteredResource>>();
- private final Set<String> newResourcesSchemes = new HashSet<String>();
+
+ /** Removed resources from clients. */
private final Set<String> urlsToRemove = new HashSet<String>();
+
+ /** Tasks to be scheduled in the next iteration. */
+ private final SortedSet<OsgiInstallerTask> tasksForNextCycle = new TreeSet<OsgiInstallerTask>();
+
+ /** Are we still activate? */
private volatile boolean active = true;
- private volatile boolean retriesScheduled;
+ /** The persistent resource list. */
private PersistentResourceList persistentList;
+ private volatile boolean retriesScheduled;
+
+
private BundleTaskCreator bundleTaskCreator;
private ConfigTaskCreator configTaskCreator;
- OsgiInstallerImpl(final BundleContext ctx) {
+ /** Constructor */
+ public OsgiInstallerImpl(final BundleContext ctx) {
this.ctx = ctx;
}
- void deactivate() {
+ /**
+ * Deactivate
+ */
+ public void deactivate() {
this.active = false;
this.configTaskCreator.deactivate();
this.bundleTaskCreator.deactivate();
ctx.removeBundleListener(this);
ctx.removeFrameworkListener(this);
+ // wake up sleeping thread
synchronized (newResources) {
newResources.notify();
}
}
- @Override
- public void run() {
+ /**
+ * Initialize the installer
+ */
+ private void init() {
// listen to framework and bundle events
this.ctx.addFrameworkListener(this);
this.ctx.addBundleListener(this);
@@ -92,47 +116,48 @@ public class OsgiInstallerImpl
setName(getClass().getSimpleName());
final File f = ctx.getDataFile("RegisteredResourceList.ser");
persistentList = new PersistentResourceList(f);
+ }
+
+ @Override
+ public void run() {
+ this.init();
while (active) {
- try {
- mergeNewResources();
- final SortedSet<OsgiInstallerTask> tasks = computeTasks();
+ this.mergeNewResources();
+ final SortedSet<OsgiInstallerTask> tasks = this.computeTasks();
- if (tasks.isEmpty() && !retriesScheduled) {
- // No tasks to execute - wait until new resources are
- // registered
- cleanupInstallableResources();
- Logger.logDebug("No tasks to process, going idle");
-
- synchronized (newResources) {
- try {
- newResources.wait();
- } catch (InterruptedException ignore) {}
- }
- Logger.logDebug("Notified of new resources, back to work");
- continue;
- }
-
- retriesScheduled = false;
- if (executeTasks(tasks) > 0) {
- Logger.logDebug("Tasks have been executed, saving persistentList");
- persistentList.save();
+ if (tasks.isEmpty() && !retriesScheduled) {
+ // No tasks to execute - wait until new resources are
+ // registered
+ this.cleanupInstallableResources();
+ Logger.logDebug("No tasks to process, going idle");
+
+ synchronized (newResources) {
+ try {
+ newResources.wait();
+ } catch (InterruptedException ignore) {}
}
+ Logger.logDebug("Notified of new resources, back to work");
+ continue;
+ }
+
+ retriesScheduled = false;
+ // execute tasks
+ this.executeTasks(tasks);
+ // clean up and save
+ this.cleanupInstallableResources();
- // Some integration tests depend on this delay, make sure to
- // rerun/adapt them if changing this value
+ // Some integration tests depend on this delay, make sure to
+ // rerun/adapt them if changing this value
+ try {
Thread.sleep(250);
- cleanupInstallableResources();
- } catch(Exception e) {
- Logger.logWarn(e.toString(), e);
- try {
- Thread.sleep(1500);
- } catch(InterruptedException ignored) {
- }
- }
+ } catch (final InterruptedException ignore) {}
}
- Logger.logInfo("Deactivated, exiting");
}
+ /**
+ * Check the scheme
+ * @throws IllegalArgumentException
+ */
private void checkScheme(final String scheme) {
if ( scheme == null || scheme.length() == 0 ) {
throw new IllegalArgumentException("Scheme required");
@@ -143,180 +168,263 @@ public class OsgiInstallerImpl
}
/**
- * @see org.apache.sling.osgi.installer.OsgiInstaller#updateResources(java.lang.String, org.apache.sling.osgi.installer.InstallableResource[], java.lang.String[])
+ * Create registered resources for all installable resources.
*/
- public void updateResources(final String scheme,
- final InstallableResource[] resources,
- final String[] ids) {
+ private List<RegisteredResource> createResources(final String scheme,
+ final InstallableResource[] resources) {
checkScheme(scheme);
- List<RegisteredResource> updatedResources = null;
+ List<RegisteredResource> createdResources = null;
if ( resources != null && resources.length > 0 ) {
- updatedResources = new ArrayList<RegisteredResource>();
+ createdResources = new ArrayList<RegisteredResource>();
for(final InstallableResource r : resources ) {
- RegisteredResource rr = null;
try {
- rr = RegisteredResourceImpl.create(ctx, r, scheme);
- } catch(IOException ioe) {
+ final RegisteredResource rr = RegisteredResourceImpl.create(ctx, r, scheme);
+ createdResources.add(rr);
+ Logger.logDebug("Adding new resource " + rr);
+ } catch (final IOException ioe) {
Logger.logWarn("Cannot create RegisteredResource (resource will be ignored):" + r, ioe);
- continue;
}
- updatedResources.add(rr);
}
}
- synchronized (newResources) {
- boolean doNotify = false;
- if ( updatedResources != null ) {
- for(final RegisteredResource rr : updatedResources ) {
- Logger.logDebug("Adding new resource " + rr);
- newResources.add(rr);
- doNotify = true;
+ return createdResources;
+ }
+
+ /**
+ * Try to close all input streams.
+ * This is just a sanity check for input streams which might not have been closed
+ * as either processing threw an exception or the resource type is not supported.
+ */
+ private void closeInputStreams(final InstallableResource[] resources) {
+ if ( resources != null ) {
+ for(final InstallableResource r : resources ) {
+ final InputStream is = r.getInputStream();
+ if ( is != null ) {
+ try {
+ is.close();
+ } catch (final IOException ignore) {
+ // ignore
+ }
}
}
- if ( ids != null ) {
- for(final String id : ids) {
- final String url = scheme + ':' + id;
- // Will mark all resources which have r's URL as uninstallable
- Logger.logDebug("Adding URL " + url + " to urlsToRemove");
+ }
+ }
- urlsToRemove.add(url);
+ /**
+ * @see org.apache.sling.osgi.installer.OsgiInstaller#updateResources(java.lang.String, org.apache.sling.osgi.installer.InstallableResource[], java.lang.String[])
+ */
+ public void updateResources(final String scheme,
+ final InstallableResource[] resources,
+ final String[] ids) {
+ try {
+ final List<RegisteredResource> updatedResources = this.createResources(scheme, resources);
+
+ synchronized (newResources) {
+ boolean doNotify = false;
+ if ( updatedResources != null && updatedResources.size() > 0 ) {
+ newResources.addAll(updatedResources);
doNotify = true;
}
+ if ( ids != null && ids.length > 0 ) {
+ for(final String id : ids) {
+ final String url = scheme + ':' + id;
+ // Will mark all resources which have r's URL as uninstallable
+ Logger.logDebug("Adding URL " + url + " to urlsToRemove");
+
+ urlsToRemove.add(url);
+ }
+ doNotify = true;
+ }
+ if ( doNotify ) {
+ newResources.notify();
+ }
}
- if ( doNotify ) {
- newResources.notify();
- }
+ } finally {
+ // we simply close all input streams now
+ this.closeInputStreams(resources);
}
}
/**
- * @see org.apache.sling.osgi.installer.OsgiInstaller#registerResources(java.lang.String, java.util.Collection)
+ * @see org.apache.sling.osgi.installer.OsgiInstaller#registerResources(java.lang.String, org.apache.sling.osgi.installer.InstallableResource[])
*/
- public void registerResources(final String scheme, final Collection<InstallableResource> data) {
- checkScheme(scheme);
- final SortedSet<RegisteredResource> toAdd = new TreeSet<RegisteredResource>();
- for(InstallableResource r : data) {
- RegisteredResource rr = null;
- try {
- rr = RegisteredResourceImpl.create(ctx, r, scheme);
- } catch(IOException ioe) {
- Logger.logWarn("Cannot create RegisteredResource (resource will be ignored):" + r, ioe);
- continue;
+ public void registerResources(final String scheme, final InstallableResource[] resources) {
+ try {
+ List<RegisteredResource> registeredResources = this.createResources(scheme, resources);
+ if ( registeredResources == null ) {
+ // make sure we have a list, this makes processing later on easier
+ registeredResources = Collections.emptyList();
}
-
- Logger.logDebug("Adding new resource " + r);
- toAdd.add(rr);
- }
-
- synchronized (newResources) {
- if(!toAdd.isEmpty()) {
- newResourcesSets.add(toAdd);
+ synchronized (newResources) {
+ Logger.logDebug("Registered new resource scheme: " + scheme);
+ newResourcesSchemes.put(scheme, registeredResources);
+ newResources.notify();
}
- // Need to manage schemes separately: in case toAdd is empty we
- // want to mark all such resources as non-installable
- Logger.logDebug("Adding to newResourcesSchemes: " + scheme);
- newResourcesSchemes.add(scheme);
- newResources.notify();
+ } finally {
+ // we simply close all input streams now
+ this.closeInputStreams(resources);
}
}
+ /**
+ * This is the heart of the installer - it processes new resources and merges them
+ * with existing resources.
+ * The second part consists of detecting the resources to be processsed.
+ */
private void mergeNewResources() {
synchronized (newResources) {
- // If we have sets of new resources, each of them represents the complete list
- // of available resources for a given scheme. So, before adding them mark
- // all resources with the same scheme in newResources, and existing
- // registeredResources, as not installable
- for(String scheme : newResourcesSchemes) {
- Logger.logDebug("Processing set of new resources with scheme " + scheme);
- for(RegisteredResource r : newResources) {
- if(r.getScheme().equals(scheme)) {
- r.setInstallable(false);
- Logger.logDebug("New resource set to non-installable: " + r);
- }
- }
- for(SortedSet<RegisteredResource> ss : this.persistentList.getData().values()) {
- for(RegisteredResource r : ss) {
- if(r.getScheme().equals(scheme)) {
- r.setInstallable(false);
- Logger.logDebug("Existing resource set to non-installable: " + r);
+ final boolean changed = !this.newResources.isEmpty() || !this.newResourcesSchemes.isEmpty() || !this.urlsToRemove.isEmpty();
+ // check for new resource providers (schemes)
+ // if we have new providers we have to sync them with existing resources
+ for(final Map.Entry<String, List<RegisteredResource>> entry : this.newResourcesSchemes.entrySet()) {
+ Logger.logDebug("Processing set of new resources with scheme " + entry.getKey());
+
+ // set all previously found resources that are not available anymore to uninstall
+ // if they have been installed - remove resources with a different state
+ for(final String entityId : this.persistentList.getEntityIds()) {
+ final Collection<RegisteredResource> group = this.persistentList.getResources(entityId);
+
+ final List<RegisteredResource> toRemove = new ArrayList<RegisteredResource>();
+ boolean first = true;
+ for(final RegisteredResource r : group) {
+ if ( r.getScheme().equals(entry.getKey()) ) {
+ Logger.logDebug("Checking " + r);
+ // search if we have a new entry with the same url
+ boolean found = false;
+ final Iterator<RegisteredResource> m = entry.getValue().iterator();
+ while ( !found && m.hasNext() ) {
+ final RegisteredResource testResource = m.next();
+ found = testResource.getURL().equals(r.getURL());
+ }
+ if ( !found) {
+ Logger.logDebug("Resource " + r + " seems to be removed.");
+ if ( r.getState() == RegisteredResource.State.INSTALLED && first ) {
+ r.setState(RegisteredResource.State.UNINSTALL);
+ } else {
+ toRemove.add(r);
+ }
+ }
}
+ first = false;
+ }
+ for(final RegisteredResource rr : toRemove) {
+ this.persistentList.remove(rr);
}
}
- }
- for(SortedSet<RegisteredResource> s : newResourcesSets) {
- newResources.addAll(s);
- Logger.logDebug("Added set of " + s.size() + " new resources with scheme "
- + s.first().getScheme() + ": " + s);
+ Logger.logDebug("Added set of " + entry.getValue().size() + " new resources with scheme "
+ + entry.getKey() + ": " + entry.getValue());
+ newResources.addAll(entry.getValue());
}
- newResourcesSets.clear();
+
newResourcesSchemes.clear();
for(RegisteredResource r : newResources) {
- SortedSet<RegisteredResource> t = this.persistentList.getData().get(r.getEntityId());
- if(t == null) {
- t = new TreeSet<RegisteredResource>();
- this.persistentList.getData().put(r.getEntityId(), t);
- }
-
- // If an object with same sort key is already present, replace with the
- // new one which might have different attributes
- if(t.contains(r)) {
- for(RegisteredResource rr : t) {
- if(rr.compareTo(r) == 0) {
- Logger.logDebug("Cleanup obsolete " + rr);
- rr.cleanup();
- }
- }
- t.remove(r);
- }
- t.add(r);
+ this.persistentList.addOrUpdate(r);
}
newResources.clear();
// Mark resources for removal according to urlsToRemove
- if(!urlsToRemove.isEmpty()) {
- for(SortedSet<RegisteredResource> group : this.persistentList.getData().values()) {
- for(RegisteredResource r : group) {
- if(urlsToRemove.contains(r.getURL())) {
- Logger.logDebug("Marking " + r + " uninistallable, URL is included in urlsToRemove");
- r.setInstallable(false);
- }
- }
+ if (!urlsToRemove.isEmpty()) {
+ for(final String url : urlsToRemove ) {
+ this.persistentList.remove(url);
}
}
urlsToRemove.clear();
+
+ // if we have changes we have to process the resources per entity to update states
+ if ( changed ) {
+ for(final String entityId : this.persistentList.getEntityIds()) {
+ final Collection<RegisteredResource> group = this.persistentList.getResources(entityId);
+ if ( !group.isEmpty() ) {
+
+ // The first resource in each group defines what should be done within this group.
+ // This is based on the state of the first resource:
+ // INSTALL : Install this resource and ignore all others in the group
+ // UNINSTALL : Uninstall this resource and set the next resource in the group to INSTALL
+ // if it has either state IGNORE or INSTALLED
+ // INSTALLED : Nothing to do
+ // IGNORED : Nothing to do
+ // UNINSTALLED : This can't happen - but we do nothing in this case anyway
+
+ final Iterator<RegisteredResource> i = group.iterator();
+ final RegisteredResource first = i.next();
+
+ RegisteredResource toActivate = null;
+ switch ( first.getState() ) {
+ case UNINSTALL : toActivate = first;
+ break;
+ case INSTALL : toActivate = first;
+ break;
+ }
+ if ( toActivate != null ) {
+ Logger.logDebug("Activating " + toActivate);
+ if ( toActivate.getState() == RegisteredResource.State.UNINSTALL && i.hasNext() ) {
+ final RegisteredResource r = i.next();;
+ if (r.getState() == RegisteredResource.State.IGNORED || r.getState() == RegisteredResource.State.INSTALLED) {
+ Logger.logDebug("Reactivating for next cycle " + r);
+ r.setState(RegisteredResource.State.INSTALL);
+ }
+ }
+ }
+ }
+ }
+ // persist list
+ this.persistentList.save();
+ }
}
}
-
- /** Compute OSGi tasks based on our resources, and add to supplied list of tasks */
- SortedSet<OsgiInstallerTask> computeTasks() throws Exception {
+ /**
+ * Compute OSGi tasks based on our resources, and add to supplied list of tasks.
+ */
+ private SortedSet<OsgiInstallerTask> computeTasks() {
final SortedSet<OsgiInstallerTask> tasks = new TreeSet<OsgiInstallerTask>();
+
// Add tasks that were scheduled for next cycle
synchronized (tasksForNextCycle) {
- for(OsgiInstallerTask t : tasksForNextCycle) {
- tasks.add(t);
- }
+ tasks.addAll(tasksForNextCycle);
tasksForNextCycle.clear();
}
// Walk the list of entities, and create appropriate OSGi tasks for each group
- // TODO do nothing for a group that's "stable" - i.e. one where no tasks were
- // created in the last cycle??
- for(SortedSet<RegisteredResource> group : this.persistentList.getData().values()) {
- if (group.isEmpty()) {
- continue;
- }
- final String rt = group.first().getType();
- if ( InstallableResource.TYPE_BUNDLE.equals(rt) ) {
- bundleTaskCreator.createTasks(group, tasks);
- } else if ( InstallableResource.TYPE_CONFIG.equals(rt) ) {
- configTaskCreator.createTasks(group, tasks);
+ for(final String entityId : this.persistentList.getEntityIds()) {
+ final Collection<RegisteredResource> group = this.persistentList.getResources(entityId);
+ if ( !group.isEmpty() ) {
+
+ // Check the first resource in each group
+ final Iterator<RegisteredResource> i = group.iterator();
+ final RegisteredResource first = i.next();
+
+ RegisteredResource toActivate = null;
+ switch ( first.getState() ) {
+ case UNINSTALL : toActivate = first;
+ break;
+ case INSTALL : toActivate = first;
+ break;
+ }
+ if ( toActivate != null ) {
+ final String rt = toActivate.getType();
+ final OsgiInstallerTask task;
+ if ( InstallableResource.TYPE_BUNDLE.equals(rt) ) {
+ task = bundleTaskCreator.createTask(toActivate);
+ } else if ( InstallableResource.TYPE_CONFIG.equals(rt) ) {
+ task = configTaskCreator.createTask(toActivate);
+ } else {
+ task = null;
+ }
+ if ( task != null ) {
+ tasks.add(task);
+ }
+ }
+
}
}
return tasks;
}
- private int executeTasks(final SortedSet<OsgiInstallerTask> tasks) {
+ /**
+ * Execute all tasks
+ */
+ private void executeTasks(final SortedSet<OsgiInstallerTask> tasks) {
final OsgiInstallerContext ctx = new OsgiInstallerContext() {
public void addTaskToNextCycle(final OsgiInstallerTask t) {
@@ -333,63 +441,39 @@ public class OsgiInstallerImpl
}
}
};
- int counter = 0;
- while (!tasks.isEmpty()) {
+ while (this.active && !tasks.isEmpty()) {
OsgiInstallerTask t = null;
synchronized (tasks) {
t = tasks.first();
tasks.remove(t);
}
+ Logger.logInfo("Executing task " + t);
t.execute(ctx);
- counter++;
}
- return counter;
}
- private void cleanupInstallableResources() throws IOException {
- // Cleanup resources that are not marked installable,
- // they have been processed by now
- int resourceCount = 0;
- final List<RegisteredResource> toDelete = new ArrayList<RegisteredResource>();
- final List<String> groupKeysToRemove = new ArrayList<String>();
- for(SortedSet<RegisteredResource> group : this.persistentList.getData().values()) {
- toDelete.clear();
- String key = null;
- for(RegisteredResource r : group) {
- key = r.getEntityId();
- resourceCount++;
- if(!r.isInstallable()) {
- toDelete.add(r);
- }
- }
- for(RegisteredResource r : toDelete) {
- group.remove(r);
- r.cleanup();
- Logger.logDebug("Removing RegisteredResource from list, not installable and has been processed: " + r);
- }
- if(group.isEmpty() && key != null) {
- groupKeysToRemove.add(key);
- }
- }
-
- for(String key : groupKeysToRemove) {
- this.persistentList.getData().remove(key);
+ /**
+ * Clean up and compact
+ */
+ private void cleanupInstallableResources() {
+ if ( this.persistentList.compact() ) {
+ persistentList.save();
}
-
- // List of resources might have changed
- persistentList.save();
}
/** If we have any tasks waiting to be retried, schedule their execution */
private void scheduleRetries() {
- final int toRetry = tasksForNextCycle.size();
- if(toRetry > 0) {
- Logger.logDebug(toRetry + " tasks scheduled for retrying");
+ final int toRetry;
+ synchronized ( tasksForNextCycle ) {
+ toRetry = tasksForNextCycle.size();
+ }
+ if (toRetry > 0) {
+ Logger.logDebug(toRetry + " tasks scheduled for retrying");
synchronized (newResources) {
- newResources.notify();
retriesScheduled = true;
+ newResources.notify();
}
- }
+ }
}
/**
@@ -399,11 +483,11 @@ public class OsgiInstallerImpl
synchronized (LOCK) {
eventsCount++;
}
- final int t = e.getType();
- if(t == BundleEvent.INSTALLED || t == BundleEvent.RESOLVED || t == BundleEvent.STARTED || t == BundleEvent.UPDATED) {
- Logger.logDebug("Received BundleEvent that might allow installed bundles to start, scheduling retries if any");
- scheduleRetries();
- }
+ final int t = e.getType();
+ if(t == BundleEvent.INSTALLED || t == BundleEvent.RESOLVED || t == BundleEvent.STARTED || t == BundleEvent.UPDATED) {
+ Logger.logDebug("Received BundleEvent that might allow installed bundles to start, scheduling retries if any");
+ scheduleRetries();
+ }
}
private static volatile long eventsCount;
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/OsgiInstallerTask.java Fri Sep 10 07:41:55 2010
@@ -19,14 +19,25 @@
package org.apache.sling.osgi.installer.impl;
-/** Base class for tasks that can be executed by the {@link OsgiInstallerImpl} */
+/**
+ * Base class for tasks that can be executed by the {@link OsgiInstallerImpl}
+ */
public abstract class OsgiInstallerTask implements Comparable<OsgiInstallerTask> {
- public abstract void execute(OsgiInstallerContext ctx);
+ private final RegisteredResource resource;
- protected void logExecution() {
- Logger.logInfo("OsgiInstallerTask: executing " + this);
- }
+ public OsgiInstallerTask(final RegisteredResource r) {
+ this.resource = r;
+ }
+
+ /**
+ * Return the corresponding resource - depending on the task this might be null.
+ */
+ public RegisteredResource getResource() {
+ return this.resource;
+ }
+
+ public abstract void execute(OsgiInstallerContext ctx);
/** Tasks are sorted according to this key */
public abstract String getSortKey();
@@ -36,7 +47,12 @@ public abstract class OsgiInstallerTask
return getSortKey().compareTo(o.getSortKey());
}
- @Override
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": " + resource;
+ }
+
+ @Override
public final boolean equals(Object o) {
if(o instanceof OsgiInstallerTask) {
return getSortKey().equals(((OsgiInstallerTask)o).getSortKey());
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/PersistentResourceList.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/PersistentResourceList.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/PersistentResourceList.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/PersistentResourceList.java Fri Sep 10 07:41:55 2010
@@ -24,19 +24,32 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.SortedSet;
+import java.util.TreeSet;
-/** Persistent list of RegisteredResource, used by installer to
- * keep track of all registered resources
+/**
+ * Persistent list of RegisteredResource, used by installer to
+ * keep track of all registered resources
*/
-class PersistentResourceList {
+public class PersistentResourceList {
+
+ /**
+ * Map of registered resource sets.
+ * The key of the map is the entity id of the registered resource.
+ * The value is a set containing all registered resources for the
+ * same entity. Usually this is just one resource per entity.
+ */
private final Map<String, SortedSet<RegisteredResource>> data;
private final File dataFile;
@SuppressWarnings("unchecked")
- PersistentResourceList(final File dataFile) {
+ public PersistentResourceList(final File dataFile) {
this.dataFile = dataFile;
Map<String, SortedSet<RegisteredResource>> restoredData = null;
@@ -45,13 +58,14 @@ class PersistentResourceList {
try {
ois = new ObjectInputStream(new FileInputStream(dataFile));
restoredData = (Map<String, SortedSet<RegisteredResource>>)ois.readObject();
- } catch(Exception e) {
- Logger.logInfo("Unable to restore data, starting with empty list (" + e.toString());
+ Logger.logDebug("Restored rsource list: " + restoredData);
+ } catch (final Exception e) {
+ Logger.logWarn("Unable to restore data, starting with empty list (" + e.getMessage() + ")", e);
} finally {
- if(ois != null) {
+ if (ois != null) {
try {
ois.close();
- } catch(IOException ignore) {
+ } catch (final IOException ignore) {
// ignore
}
}
@@ -60,16 +74,114 @@ class PersistentResourceList {
data = restoredData != null ? restoredData : new HashMap<String, SortedSet<RegisteredResource>>();
}
+ /** This method is just for testing. */
Map<String, SortedSet<RegisteredResource>> getData() {
return data;
}
- void save() throws IOException {
- ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(dataFile));
+ public void save() {
try {
- oos.writeObject(data);
- } finally {
- oos.close();
+ final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(dataFile));
+ try {
+ oos.writeObject(data);
+ Logger.logDebug("Persisted resource list.");
+ } finally {
+ oos.close();
+ }
+ } catch (final Exception e) {
+ Logger.logWarn("Unable to save persistent list: " + e.getMessage(), e);
+ }
+ }
+
+ public Collection<String> getEntityIds() {
+ return this.data.keySet();
+ }
+
+ public void addOrUpdate(final RegisteredResource r) {
+ Logger.logDebug("Adding " + r);
+ SortedSet<RegisteredResource> t = this.data.get(r.getEntityId());
+ if (t == null) {
+ t = new TreeSet<RegisteredResource>();
+ this.data.put(r.getEntityId(), t);
+ }
+
+ // If an object with same sort key is already present, replace with the
+ // new one which might have different attributes
+ boolean first = true;
+ for(final RegisteredResource rr : t) {
+ if ( rr.getURL().equals(r.getURL()) ) {
+ Logger.logDebug("Cleanup obsolete resource " + rr);
+ rr.cleanup();
+ t.remove(rr);
+ if ( first && rr.equals(r) ) {
+ r.setState(rr.getState());
+ }
+ break;
+ }
+ first = false;
+ }
+ t.add(r);
+ }
+
+ public void remove(final String url) {
+ for(final SortedSet<RegisteredResource> group : this.data.values()) {
+ final Iterator<RegisteredResource> i = group.iterator();
+ boolean first = true;
+ while ( i.hasNext() ) {
+ final RegisteredResource r = i.next();
+ if ( r.getURL().equals(url) ) {
+ if ( first && r.getState() == RegisteredResource.State.INSTALLED ) {
+ Logger.logDebug("Marking " + r + " for uninstalling");
+ r.setState(RegisteredResource.State.UNINSTALL);
+ } else {
+ Logger.logDebug("Removing unused " + r);
+ i.remove();
+ r.cleanup();
+ }
+ }
+ first = false;
+ }
+ }
+ }
+
+ public void remove(final RegisteredResource r) {
+ final SortedSet<RegisteredResource> group = this.data.get(r.getEntityId());
+ if ( group != null ) {
+ Logger.logDebug("Removing unused " + r);
+ group.remove(r);
+ r.cleanup();
}
}
+
+ public Collection<RegisteredResource> getResources(final String entityId) {
+ return this.data.get(entityId);
+ }
+
+ public boolean compact() {
+ boolean changed = false;
+ final Iterator<Map.Entry<String, SortedSet<RegisteredResource>>> i = this.data.entrySet().iterator();
+ while ( i.hasNext() ) {
+ final Map.Entry<String, SortedSet<RegisteredResource>> entry = i.next();
+
+ final List<RegisteredResource> toDelete = new ArrayList<RegisteredResource>();
+ for(final RegisteredResource r : entry.getValue()) {
+ if ( r.getState() == RegisteredResource.State.UNINSTALLED ) {
+ toDelete.add(r);
+ }
+ }
+ for(final RegisteredResource r : toDelete) {
+ changed = true;
+ entry.getValue().remove(r);
+ r.cleanup();
+ Logger.logDebug("Removing from list, uninstalled: " + r);
+ }
+
+ if ( entry.getValue().isEmpty() ) {
+ changed = true;
+ i.remove();
+ }
+ }
+ return changed;
+ }
+
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResource.java Fri Sep 10 07:41:55 2010
@@ -33,6 +33,14 @@ import org.apache.sling.osgi.installer.O
*/
public interface RegisteredResource extends Serializable, Comparable<RegisteredResource> {
+ enum State {
+ INSTALL,
+ UNINSTALL,
+ INSTALLED,
+ UNINSTALLED,
+ IGNORED
+ }
+
/** Attribute key: configuration pid */
String CONFIG_PID_ATTRIBUTE = "config.pid";
@@ -83,9 +91,6 @@ public interface RegisteredResource exte
void cleanup();
String getURL();
- boolean isInstallable();
- void setInstallable(boolean installable);
-
String getScheme();
/** Attributes include the bundle symbolic name, bundle version, etc. */
@@ -98,4 +103,8 @@ public interface RegisteredResource exte
String getEntityId();
long getSerialNumber();
+
+ State getState();
+
+ void setState(final State s);
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/RegisteredResourceImpl.java Fri Sep 10 07:41:55 2010
@@ -58,14 +58,20 @@ public class RegisteredResourceImpl
private static final String ENTITY_BUNDLE_PREFIX = "bundle:";
private static final String ENTITY_CONFIG_PREFIX = "config:";
- private static final long serialVersionUID = 3L;
+ private static final long serialVersionUID = 4L;
+
+ /** The resource id. */
private final String id;
+ /** The installer scheme. */
private final String urlScheme;
+ /** The digest for the resource. */
private final String digest;
+ /** The entity id. */
private final String entity;
+ /** The dictionary for configurations. */
private final Dictionary<String, Object> dictionary;
+ /** Additional attributes. */
private final Map<String, Object> attributes = new HashMap<String, Object>();
- private boolean installable = true;
private final File dataFile;
private final int priority;
private final long serialNumber;
@@ -73,6 +79,8 @@ public class RegisteredResourceImpl
private final String resourceType;
+ private State state = State.INSTALL;
+
/**
* Try to create a registered resource.
*/
@@ -170,7 +178,10 @@ public class RegisteredResourceImpl
@Override
public String toString() {
- return getClass().getSimpleName() + " " + this.getURL() + ", digest=" + this.getDigest() + ", serialNumber=" + this.getSerialNumber();
+ return getClass().getSimpleName() + " " + this.getURL() +
+ ", entity=" + this.getEntityId() +
+ ", state=" + this.state +
+ ", digest=" + this.getDigest() + ", serialNumber=" + this.getSerialNumber();
}
protected File getDataFile(final BundleContext bundleContext) {
@@ -284,20 +295,6 @@ public class RegisteredResourceImpl
return attributes;
}
- /**
- * @see org.apache.sling.osgi.installer.impl.RegisteredResource#isInstallable()
- */
- public boolean isInstallable() {
- return installable;
- }
-
- /**
- * @see org.apache.sling.osgi.installer.impl.RegisteredResource#setInstallable(boolean)
- */
- public void setInstallable(boolean installable) {
- this.installable = installable;
- }
-
/** Read the manifest from supplied input stream, which is closed before return */
private Manifest getManifest(InputStream ins) throws IOException {
Manifest result = null;
@@ -363,85 +360,101 @@ public class RegisteredResourceImpl
}
/**
+ * @see org.apache.sling.osgi.installer.impl.RegisteredResource#getState()
+ */
+ public State getState() {
+ return this.state;
+ }
+
+ /**
+ * @see org.apache.sling.osgi.installer.impl.RegisteredResource#setState(org.apache.sling.osgi.installer.impl.RegisteredResource.State)
+ */
+ public void setState(State s) {
+ this.state = s;
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if ( obj == this ) {
+ return true;
+ }
+ if ( ! (obj instanceof RegisteredResource) ) {
+ return false;
+ }
+ return compareTo((RegisteredResource)obj) == 0;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return this.entity.hashCode();
+ }
+
+ /**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(final RegisteredResource b) {
return compare(this, b);
}
+ /**
+ * Compare resources.
+ * First we compare the entity id - the entity id contains the resource type
+ * together with an entity identifier for the to be installed resource like
+ * the symbolic name of a bundle, the pid for a configuration etc.
+ */
public static int compare(final RegisteredResource a, final RegisteredResource b) {
- final boolean aBundle = a.getType().equals(InstallableResource.TYPE_BUNDLE);
- final boolean bBundle = b.getType().equals(InstallableResource.TYPE_BUNDLE);
+ // check entity id first
+ int result = a.getEntityId().compareTo(b.getEntityId());
+ if ( result == 0 ) {
+ if (a.getType().equals(InstallableResource.TYPE_BUNDLE)) {
+ // we need a special comparison for bundles
+ result = compareBundles(a, b);
+ } else {
+ // all other types: check prio and then digest
+ result = Integer.valueOf(b.getPriority()).compareTo(a.getPriority());
- if (aBundle && bBundle) {
- return compareBundles(a, b);
- } else if (!aBundle && !bBundle){
- return compareConfig(a, b);
- } else if (aBundle) {
- return 1;
- } else {
- return -1;
+ // check digest
+ if ( result == 0 ) {
+ result = a.getDigest().compareTo(b.getDigest());
+ }
+ }
}
+ return result;
}
+ /**
+ * Bundles are compared differently than other resource types:
+ * - higher versions have always priority - regardless of the priority attribute!
+ * - priority matters only if version is same
+ * - if the version is a snapshot version, the serial number and the digest are used
+ * in addition
+ */
private static int compareBundles(final RegisteredResource a, final RegisteredResource b) {
boolean isSnapshot = false;
int result = 0;
- // Order first by symbolic name
- final String nameA = (String)a.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME);
- final String nameB = (String)b.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME);
- if(nameA != null && nameB != null) {
- result = nameA.compareTo(nameB);
- }
-
- // Then by version
- if(result == 0) {
- final Version va = new Version((String)a.getAttributes().get(Constants.BUNDLE_VERSION));
- final Version vb = new Version((String)b.getAttributes().get(Constants.BUNDLE_VERSION));
- isSnapshot = va.toString().contains("SNAPSHOT");
- // higher version has more priority, must come first so invert comparison
- result = vb.compareTo(va);
- }
+ // Order by version
+ final Version va = new Version((String)a.getAttributes().get(Constants.BUNDLE_VERSION));
+ final Version vb = new Version((String)b.getAttributes().get(Constants.BUNDLE_VERSION));
+ isSnapshot = va.toString().contains("SNAPSHOT");
+ // higher version has more priority, must come first so invert comparison
+ result = vb.compareTo(va);
// Then by priority, higher values first
- if(result == 0) {
- if(a.getPriority() < b.getPriority()) {
- result = 1;
- } else if(a.getPriority() > b.getPriority()) {
- result = -1;
- }
+ if (result == 0) {
+ result = Integer.valueOf(b.getPriority()).compareTo(a.getPriority());
}
- if(result == 0 && isSnapshot) {
+ if (result == 0 && isSnapshot) {
+ result = a.getDigest().compareTo(b.getDigest());
// For snapshots, compare serial numbers so that snapshots registered
// later get priority
- if(a.getSerialNumber() < b.getSerialNumber()) {
- result = 1;
- } else if(a.getSerialNumber() > b.getSerialNumber()) {
- result = -1;
- }
- }
-
- return result;
- }
-
- private static int compareConfig(final RegisteredResource a, final RegisteredResource b) {
- int result = 0;
-
- // First compare by pid
- final ConfigurationPid pA = (ConfigurationPid)a.getAttributes().get(RegisteredResource.CONFIG_PID_ATTRIBUTE);
- final ConfigurationPid pB = (ConfigurationPid)b.getAttributes().get(RegisteredResource.CONFIG_PID_ATTRIBUTE);
- if(pA != null && pA.getCompositePid() != null && pB != null && pB.getCompositePid() != null) {
- result = pA.getCompositePid().compareTo(pB.getCompositePid());
- }
-
- // Then by priority, higher values first
- if(result == 0) {
- if(a.getPriority() < b.getPriority()) {
- result = 1;
- } else if( a.getPriority() > b.getPriority()) {
- result = -1;
+ if ( result != 0 ) {
+ result = Long.valueOf(b.getSerialNumber()).compareTo(a.getSerialNumber());
}
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/AbstractConfigTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/AbstractConfigTask.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/AbstractConfigTask.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/AbstractConfigTask.java Fri Sep 10 07:41:55 2010
@@ -31,22 +31,18 @@ import org.osgi.util.tracker.ServiceTrac
abstract class AbstractConfigTask extends OsgiInstallerTask {
protected final ConfigurationPid pid;
- protected final RegisteredResource resource;
/** Tracker for the configuration admin. */
private final ServiceTracker configAdminServiceTracker;
AbstractConfigTask(final RegisteredResource r, final ServiceTracker configAdminServiceTracker) {
+ super(r);
this.configAdminServiceTracker = configAdminServiceTracker;
- this.resource = r;
this.pid = (ConfigurationPid)r.getAttributes().get(RegisteredResource.CONFIG_PID_ATTRIBUTE);
- if (this.pid == null) {
- throw new IllegalArgumentException("RegisteredResource does not have CONFIG_PID_ATTRIBUTE: " + r);
- }
}
/**
- * @see org.apache.sling.osgi.installer.impl.OsgiInstallerContext#getConfigurationAdmin()
+ * Get the configuration admin - if available
*/
protected ConfigurationAdmin getConfigurationAdmin() {
return (ConfigurationAdmin)this.configAdminServiceTracker.getService();
@@ -54,8 +50,8 @@ abstract class AbstractConfigTask extend
protected Configuration getConfiguration(final ConfigurationAdmin ca,
- final ConfigurationPid cp,
- final boolean createIfNeeded)
+ final ConfigurationPid cp,
+ final boolean createIfNeeded)
throws IOException, InvalidSyntaxException {
Configuration result = null;
@@ -78,9 +74,4 @@ abstract class AbstractConfigTask extend
return result;
}
-
- @Override
- public String toString() {
- return getClass().getName() + ": " + resource;
- }
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigInstallTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigInstallTask.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigInstallTask.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigInstallTask.java Fri Sep 10 07:41:55 2010
@@ -66,14 +66,10 @@ public class ConfigInstallTask extends A
}
// Convert data to a configuration Dictionary
- Dictionary<String, Object> dict = resource.getDictionary();
-
- if (dict == null) {
- throw new IllegalArgumentException("Null Dictionary for resource " + resource);
- }
+ final Dictionary<String, Object> dict = getResource().getDictionary();
// Add pseudo-properties
- dict.put(CONFIG_PATH_KEY, resource.getURL());
+ dict.put(CONFIG_PATH_KEY, getResource().getURL());
// Factory?
if (pid.getFactoryPid() != null) {
@@ -89,29 +85,30 @@ public class ConfigInstallTask extends A
created = true;
config = getConfiguration(ca, pid, true);
} else {
- if (isSameData(config.getProperties(), resource.getDictionary())) {
+ if (isSameData(config.getProperties(), getResource().getDictionary())) {
Logger.logDebug("Configuration " + config.getPid()
+ " already installed with same data, update request ignored: "
- + resource);
+ + getResource());
config = null;
}
}
if (config != null) {
- logExecution();
if (config.getBundleLocation() != null) {
config.setBundleLocation(null);
}
config.update(dict);
+ this.getResource().setState(RegisteredResource.State.INSTALLED);
Logger.logInfo("Configuration " + config.getPid()
+ " " + (created ? "created" : "updated")
- + " from " + resource);
- return;
+ + " from " + getResource());
+ } else {
+ this.getResource().setState(RegisteredResource.State.IGNORED);
}
} catch (Exception e) {
+ Logger.logDebug("Exception during installation of config " + this.getResource() + " : " + e.getMessage() + ". Retrying later.", e);
ctx.addTaskToNextCycle(this);
}
- return;
}
private Set<String> collectKeys(final Dictionary<String, Object>a) {
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigRemoveTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigRemoveTask.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigRemoveTask.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigRemoveTask.java Fri Sep 10 07:41:55 2010
@@ -55,19 +55,19 @@ public class ConfigRemoveTask extends Ab
return;
}
- logExecution();
try {
final Configuration cfg = getConfiguration(ca, pid, false);
if (cfg == null) {
- Logger.logDebug("Cannot delete config , pid=" + pid + " not found, ignored (" + resource + ")");
+ Logger.logDebug("Cannot delete config , pid=" + pid + " not found, ignored (" + getResource() + ")");
+ this.getResource().setState(RegisteredResource.State.IGNORED);
} else {
- Logger.logInfo("Deleting config " + pid + " (" + resource + ")");
+ Logger.logInfo("Deleting config " + pid + " (" + getResource() + ")");
cfg.delete();
- return;
+ this.getResource().setState(RegisteredResource.State.UNINSTALLED);
}
} catch (Exception e) {
+ Logger.logDebug("Exception during removal of config " + this.getResource() + " : " + e.getMessage() + ". Retrying later.", e);
ctx.addTaskToNextCycle(this);
}
- return;
}
}
\ No newline at end of file
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigTaskCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigTaskCreator.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigTaskCreator.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/config/ConfigTaskCreator.java Fri Sep 10 07:41:55 2010
@@ -18,75 +18,50 @@
*/
package org.apache.sling.osgi.installer.impl.config;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.SortedSet;
-
-import org.apache.sling.osgi.installer.impl.Logger;
import org.apache.sling.osgi.installer.impl.OsgiInstallerTask;
import org.apache.sling.osgi.installer.impl.RegisteredResource;
import org.osgi.framework.BundleContext;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.util.tracker.ServiceTracker;
-/** TaskCreator that processes a list of config RegisteredResources */
+/**
+ * Task creator for configurations.
+ */
public class ConfigTaskCreator {
/** Interface of the config admin */
private static String CONFIG_ADMIN_SERVICE_NAME = ConfigurationAdmin.class.getName();
- /** Store digests of the installed configs, keyed by config pid */
- private final Map<String, String> digests = new HashMap<String, String>();
-
+ /** Service tracker for the configuration admin. */
private final ServiceTracker configAdminServiceTracker;
+ /**
+ * Constructor
+ */
public ConfigTaskCreator(final BundleContext bc) {
this.configAdminServiceTracker = new ServiceTracker(bc, CONFIG_ADMIN_SERVICE_NAME, null);
this.configAdminServiceTracker.open();
}
+ /**
+ * Deactivate this creator.
+ */
public void deactivate() {
this.configAdminServiceTracker.close();
}
- /** Create tasks for a set of RegisteredResource that all represent the same config PID.
+ /**
+ * Create a task to install or uninstall a configuration.
*/
- public void createTasks(SortedSet<RegisteredResource> resources, SortedSet<OsgiInstallerTask> tasks) {
-
- // Find the config that must be active: the resources collection is ordered according
- // to priorities, so we just need to find the first one that is installable
- RegisteredResource toActivate = null;
- for(RegisteredResource r : resources) {
- if (r.isInstallable()) {
- toActivate = r;
- break;
- }
- }
-
- if(toActivate == null) {
+ public OsgiInstallerTask createTask(final RegisteredResource toActivate) {
+ final OsgiInstallerTask result;
+ if (toActivate.getState() == RegisteredResource.State.UNINSTALL) {
// None of our resources are installable, remove corresponding config
// (task simply does nothing if config does not exist)
- final RegisteredResource first = resources.first();
- tasks.add(new ConfigRemoveTask(first, this.configAdminServiceTracker));
- digests.remove(getDigestKey(first));
+ result = new ConfigRemoveTask(toActivate, this.configAdminServiceTracker);
} else {
- final String key = getDigestKey(toActivate);
- final String previousDigest = digests.get(key);
- if(toActivate.getDigest().equals(previousDigest)) {
- Logger.logDebug("Configuration (" + key+ ") already installed, ignored: " + toActivate);
- } else {
- tasks.add(new ConfigInstallTask(toActivate, this.configAdminServiceTracker));
- digests.put(key, toActivate.getDigest());
- Logger.logDebug("Scheduling update/install of config " + toActivate + ", digest has changed or was absent");
- }
+ result = new ConfigInstallTask(toActivate, this.configAdminServiceTracker);
}
- }
-
- private String getDigestKey(RegisteredResource r) {
- final ConfigurationPid cp = (ConfigurationPid)r.getAttributes().get(RegisteredResource.CONFIG_PID_ATTRIBUTE);
- if(cp == null) {
- throw new IllegalArgumentException("Resource does not provide a CONFIG_PID_ATTRIBUTE: " + r);
- }
- return cp.getCompositePid();
+ return result;
}
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallTask.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallTask.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleInstallTask.java Fri Sep 10 07:41:55 2010
@@ -34,19 +34,12 @@ public class BundleInstallTask extends O
private static final String BUNDLE_INSTALL_ORDER = "50-";
- private final RegisteredResource resource;
-
private final BundleTaskCreator creator;
public BundleInstallTask(final RegisteredResource r,
final BundleTaskCreator creator) {
+ super(r);
this.creator = creator;
- this.resource = r;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + ": " + resource;
}
/**
@@ -54,8 +47,8 @@ public class BundleInstallTask extends O
*/
public void execute(final OsgiInstallerContext ctx) {
int startLevel = 0;
- final Object providedLevel = (this.resource.getDictionary() != null
- ? this.resource.getDictionary().get(InstallableResource.BUNDLE_START_LEVEL) : null);
+ final Object providedLevel = (this.getResource().getDictionary() != null
+ ? this.getResource().getDictionary().get(InstallableResource.BUNDLE_START_LEVEL) : null);
if ( providedLevel != null ) {
if ( providedLevel instanceof Number ) {
startLevel = ((Number)providedLevel).intValue();
@@ -66,7 +59,7 @@ public class BundleInstallTask extends O
// get the start level service (if possible) so we can set the initial start level
final StartLevel startLevelService = this.creator.getStartLevel();
try {
- final Bundle b = this.creator.getBundleContext().installBundle(resource.getURL(), resource.getInputStream());
+ final Bundle b = this.creator.getBundleContext().installBundle(getResource().getURL(), getResource().getInputStream());
// optionally set the start level
if ( startLevel > 0 ) {
if (startLevelService != null) {
@@ -75,21 +68,21 @@ public class BundleInstallTask extends O
Logger.logWarn("Ignoring start level " + startLevel + " for bundle " + b + " - start level service not available.");
}
}
- final Version newVersion = new Version((String)resource.getAttributes().get(Constants.BUNDLE_VERSION));
- this.creator.saveInstalledBundleInfo(b.getSymbolicName(), resource.getDigest(), newVersion.toString());
- logExecution();
- ctx.addTaskToCurrentCycle(new BundleStartTask(b.getBundleId(), this.creator));
- return;
+ final Version newVersion = new Version((String)getResource().getAttributes().get(Constants.BUNDLE_VERSION));
+ this.creator.getBundleDigestStorage().putInfo(b.getSymbolicName(), getResource().getDigest(), newVersion.toString());
+
+ // mark this resource as installed and to be started
+ this.getResource().getAttributes().put(BundleTaskCreator.ATTR_START, "true");
+ ctx.addTaskToCurrentCycle(new BundleStartTask(getResource(), b.getBundleId(), this.creator));
} catch (Exception ex) {
// if something goes wrong we simply try it again
+ Logger.logDebug("Exception during install of bundle " + this.getResource() + " : " + ex.getMessage() + ". Retrying later.", ex);
ctx.addTaskToNextCycle(this);
- return;
}
}
@Override
public String getSortKey() {
- return BUNDLE_INSTALL_ORDER + resource.getURL();
+ return BUNDLE_INSTALL_ORDER + getResource().getURL();
}
-
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleRemoveTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleRemoveTask.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleRemoveTask.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleRemoveTask.java Fri Sep 10 07:41:55 2010
@@ -18,6 +18,7 @@
*/
package org.apache.sling.osgi.installer.impl.tasks;
+import org.apache.sling.osgi.installer.impl.Logger;
import org.apache.sling.osgi.installer.impl.OsgiInstallerContext;
import org.apache.sling.osgi.installer.impl.OsgiInstallerTask;
import org.apache.sling.osgi.installer.impl.RegisteredResource;
@@ -33,28 +34,24 @@ public class BundleRemoveTask extends Os
private static final String BUNDLE_REMOVE_ORDER = "30-";
- private final RegisteredResource resource;
-
private final BundleTaskCreator creator;
public BundleRemoveTask(final RegisteredResource r,
- final BundleTaskCreator creator) {
+ final BundleTaskCreator creator) {
+ super(r);
this.creator = creator;
- this.resource = r;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + ": " + resource;
}
- @Override
+ /**
+ * @see org.apache.sling.osgi.installer.impl.OsgiInstallerTask#execute(org.apache.sling.osgi.installer.impl.OsgiInstallerContext)
+ */
public void execute(OsgiInstallerContext ctx) {
- logExecution();
- final String symbolicName = (String)resource.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME);
+ final String symbolicName = (String)getResource().getAttributes().get(Constants.BUNDLE_SYMBOLICNAME);
final Bundle b = this.creator.getMatchingBundle(symbolicName);
- if(b == null) {
- throw new IllegalStateException("Bundle to remove (" + symbolicName + ") not found");
+ if (b == null) {
+ // nothing to do, so just stop
+ this.getResource().setState(RegisteredResource.State.IGNORED);
+ return;
}
final int state = b.getState();
try {
@@ -62,17 +59,17 @@ public class BundleRemoveTask extends Os
b.stop();
}
b.uninstall();
- } catch (BundleException be) {
+ this.getResource().setState(RegisteredResource.State.UNINSTALLED);
+ ctx.addTaskToCurrentCycle(new SynchronousRefreshPackagesTask(this.creator));
+ } catch (final BundleException be) {
+ Logger.logDebug("Exception during removal of bundle " + this.getResource() + " : " + be.getMessage() + ". Retrying later.", be);
ctx.addTaskToNextCycle(this);
- return;
}
- ctx.addTaskToCurrentCycle(new SynchronousRefreshPackagesTask(this.creator));
- return;
}
@Override
public String getSortKey() {
- return BUNDLE_REMOVE_ORDER + resource.getURL();
+ return BUNDLE_REMOVE_ORDER + getResource().getURL();
}
}
Modified: sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java?rev=995689&r1=995688&r2=995689&view=diff
==============================================================================
--- sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java (original)
+++ sling/trunk/installer/osgi/installer/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java Fri Sep 10 07:41:55 2010
@@ -22,8 +22,9 @@ import java.text.DecimalFormat;
import org.apache.sling.osgi.installer.impl.Logger;
import org.apache.sling.osgi.installer.impl.OsgiInstallerContext;
-import org.apache.sling.osgi.installer.impl.OsgiInstallerTask;
import org.apache.sling.osgi.installer.impl.OsgiInstallerImpl;
+import org.apache.sling.osgi.installer.impl.OsgiInstallerTask;
+import org.apache.sling.osgi.installer.impl.RegisteredResource;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
@@ -43,7 +44,8 @@ public class BundleStartTask extends Osg
private final BundleTaskCreator creator;
- public BundleStartTask(final long bundleId, final BundleTaskCreator btc) {
+ public BundleStartTask(final RegisteredResource r, final long bundleId, final BundleTaskCreator btc) {
+ super(r);
this.bundleId = bundleId;
this.creator = btc;
this.sortKey = BUNDLE_START_ORDER + new DecimalFormat("00000").format(bundleId);
@@ -63,6 +65,9 @@ public class BundleStartTask extends Osg
* @see org.apache.sling.osgi.installer.impl.OsgiInstallerTask#execute(org.apache.sling.osgi.installer.impl.OsgiInstallerContext)
*/
public void execute(final OsgiInstallerContext ctx) {
+ if ( this.getResource() != null ) {
+ this.getResource().setState(RegisteredResource.State.INSTALLED);
+ }
// this is just a sanity check which should never be reached
if (bundleId == 0) {
Logger.logDebug("Bundle 0 is the framework bundle, ignoring request to start it");
@@ -88,7 +93,6 @@ public class BundleStartTask extends Osg
return;
}
// Try to start bundle, and if that doesn't work we'll need to retry
- logExecution();
try {
b.start();
Logger.logInfo("Bundle started (retry count=" + retryCount + ", bundle ID=" + bundleId + ") " + b.getSymbolicName());