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 2011/12/13 10:57:46 UTC
svn commit: r1213634 - in /sling/trunk/installer/core: ./
src/main/java/org/apache/sling/installer/api/tasks/
src/main/java/org/apache/sling/installer/core/impl/
src/main/java/org/apache/sling/installer/core/impl/tasks/
src/test/java/org/apache/sling/i...
Author: cziegeler
Date: Tue Dec 13 09:57:45 2011
New Revision: 1213634
URL: http://svn.apache.org/viewvc?rev=1213634&view=rev
Log:
SLING-2289 : Implement generic retry mechanism
Added:
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java (with props)
Modified:
sling/trunk/installer/core/pom.xml
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallTask.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallationContext.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleStartTask.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/InstallerBundleUpdateTask.java
sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/SystemBundleUpdateTask.java
sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java
Modified: sling/trunk/installer/core/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/pom.xml?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/pom.xml (original)
+++ sling/trunk/installer/core/pom.xml Tue Dec 13 09:57:45 2011
@@ -62,7 +62,7 @@
<Export-Package>
org.apache.sling.installer.api;version=3.1.0,
org.apache.sling.installer.api.event;version=1.0.0,
- org.apache.sling.installer.api.tasks;version=1.1.0
+ org.apache.sling.installer.api.tasks;version=1.2.0
</Export-Package>
<Private-Package>
org.apache.sling.installer.core.impl.*
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallTask.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallTask.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallTask.java Tue Dec 13 09:57:45 2011
@@ -21,6 +21,15 @@ package org.apache.sling.installer.api.t
/**
* Base class for tasks that can be executed by the
* {@link org.apache.sling.installer.api.OsgiInstaller}.
+ *
+ * The task is invoked by the installer through the {@link #execute(InstallationContext)}
+ * method. During execution the task should use the {@link #setFinishedState(ResourceState)}
+ * or {@link #setFinishedState(ResourceState, String)} method once the task is
+ * performed or the task decided that the task can never be performed.
+ *
+ * If the task needs to be retried, the implementation should just not alter the
+ * state at all. The installer will invoke the tasks at a later time again for
+ * retrying.
*/
public abstract class InstallTask implements Comparable<InstallTask> {
@@ -95,7 +104,7 @@ public abstract class InstallTask implem
@Override
public final boolean equals(Object o) {
- if(o instanceof InstallTask) {
+ if (o instanceof InstallTask) {
return getSortKey().equals(((InstallTask)o).getSortKey());
}
return false;
@@ -109,7 +118,7 @@ public abstract class InstallTask implem
/**
* All comparisons are based on getSortKey().
*/
- public final int compareTo(InstallTask o) {
+ public final int compareTo(final InstallTask o) {
return getSortKey().compareTo(o.getSortKey());
}
}
\ No newline at end of file
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallationContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallationContext.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallationContext.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/InstallationContext.java Tue Dec 13 09:57:45 2011
@@ -42,12 +42,21 @@ public interface InstallationContext {
* usually to indicate that a task must be retried
* or the current task is finished and another task
* has to be run.
+ * @deprecated
*/
- void addTaskToNextCycle(InstallTask t);
+ @Deprecated
+ void addTaskToNextCycle(InstallTask t);
/**
* Make an entry into the audit log - this should be invoked
* by the tasks whenever something has been installed/uninstalled etc.
*/
void log(String message, Object... args);
+
+ /**
+ * Add an async task.
+ * This adds a task for asynchronous execution.
+ * @since 1.2.0
+ */
+ void addAsyncTask(InstallTask t);
}
Added: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java?rev=1213634&view=auto
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java (added)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java Tue Dec 13 09:57:45 2011
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.installer.api.tasks;
+
+/**
+ * The retry handler should be informed by external services
+ * whenever something in the system changed which might make
+ * it worth to retry a failed installed.
+ *
+ * The installer retries all unprocessed resources whenever this
+ * retry handler is notified to reschedule. For example a bundle
+ * listener listening for updates/installs/removals of bundles
+ * can inform the retry handler.
+ *
+ * @since 1.2
+ */
+public interface RetryHandler {
+
+ /**
+ * Schedule a retry.
+ */
+ void scheduleRetry();
+}
Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/api/tasks/RetryHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/Activator.java Tue Dec 13 09:57:45 2011
@@ -168,7 +168,7 @@ public class Activator implements Bundle
}
if ( serviceInterfaces != null ) {
this.services.add(service);
- service.init(context, this.osgiControllerService);
+ service.init(context, this.osgiControllerService, this.osgiControllerService);
this.registrations.add(context.registerService(
serviceInterfaces, service, props));
}
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/DefaultTransformer.java Tue Dec 13 09:57:45 2011
@@ -25,6 +25,7 @@ import org.apache.sling.installer.api.In
import org.apache.sling.installer.api.ResourceChangeListener;
import org.apache.sling.installer.api.tasks.RegisteredResource;
import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.apache.sling.installer.api.tasks.RetryHandler;
import org.apache.sling.installer.api.tasks.TransformationResult;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
@@ -43,9 +44,9 @@ public class DefaultTransformer
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
- * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext, org.apache.sling.installer.api.ResourceChangeListener)
+ * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext, org.apache.sling.installer.api.ResourceChangeListener, RetryHandler)
*/
- public void init(final BundleContext bctx, final ResourceChangeListener rcl) {
+ public void init(final BundleContext bctx, final ResourceChangeListener rcl, RetryHandler retryHandler) {
// nothing to do
}
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/InternalService.java Tue Dec 13 09:57:45 2011
@@ -19,6 +19,7 @@
package org.apache.sling.installer.core.impl;
import org.apache.sling.installer.api.ResourceChangeListener;
+import org.apache.sling.installer.api.tasks.RetryHandler;
import org.osgi.framework.BundleContext;
/**
@@ -26,7 +27,7 @@ import org.osgi.framework.BundleContext;
*/
public interface InternalService {
- void init(BundleContext bctx, ResourceChangeListener listener);
+ void init(BundleContext bctx, ResourceChangeListener listener, RetryHandler retryHandler);
void deactivate();
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java Tue Dec 13 09:57:45 2011
@@ -46,15 +46,12 @@ import org.apache.sling.installer.api.ta
import org.apache.sling.installer.api.tasks.RegisteredResource;
import org.apache.sling.installer.api.tasks.ResourceState;
import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.apache.sling.installer.api.tasks.RetryHandler;
import org.apache.sling.installer.api.tasks.TaskResource;
import org.apache.sling.installer.api.tasks.TaskResourceGroup;
import org.apache.sling.installer.api.tasks.TransformationResult;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.BundleListener;
import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkEvent;
-import org.osgi.framework.FrameworkListener;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,10 +67,7 @@ import org.slf4j.LoggerFactory;
*/
public class OsgiInstallerImpl
extends Thread
- implements BundleListener, FrameworkListener, OsgiInstaller, ResourceChangeListener {
-
- /** Internal key for tasks to be executed async. */
- public static final String ASYNC_TASK_KEY = "EXECUTE TASK ASYNC";
+ implements OsgiInstaller, ResourceChangeListener, RetryHandler {
/** The logger */
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -93,12 +87,15 @@ public class OsgiInstallerImpl
/** Removed resources from clients. */
private final Set<String> urlsToRemove = new HashSet<String>();
- /** Tasks to be scheduled in the next iteration. */
- private final SortedSet<InstallTask> tasksForNextCycle = new TreeSet<InstallTask>();
-
/** Are we still activate? */
private volatile boolean active = true;
+ /** Are we still running? */
+ private volatile boolean backgroundThreadIsRunning = false;
+
+ /** Flag indicating that a retry event occured during tasks executions. */
+ private volatile boolean retryDuringTaskExecution = false;
+
/** The persistent resource list. */
private PersistentResourceList persistentList;
@@ -116,7 +113,6 @@ public class OsgiInstallerImpl
private final InstallListener listener;
- private volatile boolean running = false;
/** Constructor */
public OsgiInstallerImpl(final BundleContext ctx) {
@@ -142,15 +138,11 @@ public class OsgiInstallerImpl
this.factoryTracker.close();
this.transformerTracker.close();
- // remove as listener
- ctx.removeBundleListener(this);
- ctx.removeFrameworkListener(this);
-
this.listener.dispose();
- if ( this.running ) {
+ if ( this.backgroundThreadIsRunning ) {
this.logger.debug("Waiting for installer thread to stop");
- while ( this.running ) {
+ while ( this.backgroundThreadIsRunning ) {
try {
this.join(50L);
} catch (InterruptedException e) {
@@ -177,68 +169,62 @@ public class OsgiInstallerImpl
this.updateHandlerTracker = new SortingServiceTracker<UpdateHandler>(ctx, UpdateHandler.class.getName(), null);
this.updateHandlerTracker.open();
- // listen to framework and bundle events
- this.ctx.addFrameworkListener(this);
- this.ctx.addBundleListener(this);
setName(getClass().getSimpleName());
this.logger.info("Apache Sling OSGi Installer Service started.");
}
+ private static final InstallationEvent START_EVENT = new InstallationEvent() {
+
+ public TYPE getType() { return TYPE.STARTED; }
+
+ public Object getSource() { return null; }
+ };
+
+ private static final InstallationEvent SUSPENDED_EVENT = new InstallationEvent() {
+
+ public TYPE getType() { return TYPE.SUSPENDED; }
+
+ public Object getSource() { return null; }
+ };
+
@Override
public void run() {
- this.running = true;
+ this.backgroundThreadIsRunning = true;
try {
this.init();
- while (active) {
- listener.onEvent(new InstallationEvent() {
-
- public TYPE getType() {
- return TYPE.STARTED;
- }
+ if ( this.active ) {
+ this.logger.debug("Starting installer");
+ this.listener.onEvent(START_EVENT);
+ }
- public Object getSource() {
- return null;
- }
- });
- logger.debug("Starting new installer cycle");
+ while (this.active) {
+ // merge potential new resources
this.mergeNewlyRegisteredResources();
// invoke transformers
this.transformResources();
- // execute tasks
+ // Compute tasks
final SortedSet<InstallTask> tasks = this.computeTasks();
- final boolean tasksCreated = !tasks.isEmpty();
-
// execute tasks and see if we have to stop processing
+ synchronized ( this.resourcesLock ) {
+ this.retryDuringTaskExecution = false;
+ }
if ( this.executeTasks(tasks) ) {
-
- // clean up and save
- this.cleanupInstallableResources();
-
- // if we don't have any tasks, we go to sleep
- if (!tasksCreated) {
- synchronized ( this.resourcesLock ) {
- // before we go to sleep, check if new resources arrived in the meantime
- if ( !this.hasNewResources() && this.active ) {
- // No tasks to execute - wait until new resources are
- // registered
- logger.debug("No tasks to process, going idle");
- listener.onEvent(new InstallationEvent() {
-
- public TYPE getType() {
- return TYPE.SUSPENDED;
- }
-
- public Object getSource() {
- return null;
- }
- });
- try {
- this.resourcesLock.wait();
- } catch (InterruptedException ignore) {}
- logger.debug("Notified of new resources, back to work");
+ synchronized ( this.resourcesLock ) {
+ // before we go to sleep, check if new resources arrived in the meantime
+ if ( !this.hasNewResources() && this.active && !this.retryDuringTaskExecution) {
+ // No tasks to execute - wait until new resources are
+ // registered
+ logger.debug("No tasks to process, going idle");
+ listener.onEvent(SUSPENDED_EVENT);
+ try {
+ this.resourcesLock.wait();
+ } catch (final InterruptedException ignore) {}
+ if ( active ) {
+ listener.onEvent(START_EVENT);
+ this.logger.debug("Running new installer cycle");
}
}
}
@@ -246,9 +232,19 @@ public class OsgiInstallerImpl
// stop processing
this.active = false;
}
+
}
} finally {
- this.running = false;
+ this.backgroundThreadIsRunning = false;
+ }
+ }
+
+ /**
+ * Wake up the run cycle.
+ */
+ private void wakeUp() {
+ synchronized (this.resourcesLock) {
+ this.resourcesLock.notify();
}
}
@@ -430,6 +426,7 @@ public class OsgiInstallerImpl
}
this.newResourcesSchemes.clear();
this.mergeNewResources();
+
printResources("Merged");
// persist list
this.persistentList.save();
@@ -494,12 +491,6 @@ public class OsgiInstallerImpl
private SortedSet<InstallTask> computeTasks() {
final SortedSet<InstallTask> tasks = new TreeSet<InstallTask>();
- // Add tasks that were scheduled for next cycle
- synchronized (tasksForNextCycle) {
- tasks.addAll(tasksForNextCycle);
- tasksForNextCycle.clear();
- }
-
// Walk the list of entities, and create appropriate OSGi tasks for each group
final List<InstallTaskFactory> services = this.factoryTracker.getSortedServices();
if ( services.size() > 0 ) {
@@ -547,26 +538,26 @@ public class OsgiInstallerImpl
final InstallationContext ctx = new InstallationContext() {
public void addTaskToNextCycle(final InstallTask t) {
- if ( t.getSortKey().equals(ASYNC_TASK_KEY) ) {
- logger.debug("Adding async task: {}", t);
- synchronized (asyncTasks) {
- asyncTasks.add(t);
- }
- } else {
- logger.debug("Adding task to next cycle: {}", t);
- synchronized (tasksForNextCycle) {
- tasksForNextCycle.add(t);
- }
+ logger.warn("Deprecated method addTaskToNextCycle is called. Task is executed in this cycle(!): {}", t);
+ synchronized ( tasks ) {
+ tasks.add(t);
}
}
public void addTaskToCurrentCycle(final InstallTask t) {
- logger.debug("adding task to current cycle: {}", t);
+ logger.debug("Adding task to current cycle: {}", t);
synchronized ( tasks ) {
tasks.add(t);
}
}
+ public void addAsyncTask(InstallTask t) {
+ logger.debug("Adding async task: {}", t);
+ synchronized (asyncTasks) {
+ asyncTasks.add(t);
+ }
+ }
+
public void log(String message, Object... args) {
auditLogger.info(message, args);
}
@@ -585,33 +576,26 @@ public class OsgiInstallerImpl
}
}
// save new state
- persistentList.save();
+ this.cleanupInstallableResources();
// let's check if we have async tasks and no other tasks
if ( this.active && !asyncTasks.isEmpty() ) {
- final boolean isEmpty;
- synchronized ( tasksForNextCycle ) {
- isEmpty = tasksForNextCycle.isEmpty();
- }
- if ( isEmpty ) {
- // compact list and save if required
- this.cleanupInstallableResources();
- final InstallTask task = asyncTasks.get(0);
- final Thread t = new Thread() {
+ final InstallTask task = asyncTasks.get(0);
+ logger.debug("Executing async task: {}", task);
+ final Thread t = new Thread() {
- @Override
- public void run() {
- try {
- Thread.sleep(2000L);
- } catch (final InterruptedException ie) {
- // ignore
- }
- task.execute(ctx);
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(2000L);
+ } catch (final InterruptedException ie) {
+ // ignore
}
- };
- t.start();
- return false;
- }
+ task.execute(ctx);
+ }
+ };
+ t.start();
+ return false;
}
}
@@ -622,9 +606,8 @@ public class OsgiInstallerImpl
* Clean up and compact
*/
private void cleanupInstallableResources() {
- if ( this.persistentList.compact() ) {
- persistentList.save();
- }
+ this.persistentList.compact();
+ this.persistentList.save();
printResources("Compacted");
}
@@ -680,64 +663,14 @@ public class OsgiInstallerImpl
}
}
- /** If we have any tasks waiting to be retried, schedule their execution
- private void scheduleRetries() {
- final int toRetry;
- synchronized ( tasksForNextCycle ) {
- toRetry = tasksForNextCycle.size();
- }
- if (toRetry > 0) {
- logger.debug("{} tasks scheduled for retrying", toRetry);
- synchronized (newResources) {
- newResources.notify();
- }
- }
- }
- */
-
/**
- * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
+ * @see org.apache.sling.installer.api.tasks.RetryHandler#scheduleRetry()
*/
- public void bundleChanged(BundleEvent e) {
- synchronized (LOCK) {
- eventsCount++;
- }
- final int t = e.getType();
- if (t == BundleEvent.INSTALLED || t == BundleEvent.RESOLVED || t == BundleEvent.STARTED || t == BundleEvent.UPDATED) {
- logger.debug("Received BundleEvent that might allow installed bundles to start, scheduling retries if any");
- // TODO - for now we always reschedule regardless if we have retries
- // If the config task factory is only registered when config admin is available we can relax this again.
- this.wakeUp();
- }
- }
-
- private static volatile long eventsCount;
-
- private static final Object LOCK = new Object();
-
- /** Used for tasks that wait for a framework or bundle event before retrying their operations */
- public static long getTotalEventsCount() {
- synchronized (LOCK) {
- return eventsCount;
- }
- }
-
- /**
- * @see org.osgi.framework.FrameworkListener#frameworkEvent(org.osgi.framework.FrameworkEvent)
- */
- public void frameworkEvent(final FrameworkEvent event) {
- synchronized (LOCK) {
- eventsCount++;
- }
- }
-
- /**
- * Wake up the run cycle.
- */
- public void wakeUp() {
- synchronized (this.resourcesLock) {
- this.resourcesLock.notify();
+ public void scheduleRetry() {
+ synchronized ( this.resourcesLock ) {
+ this.retryDuringTaskExecution = true;
}
+ this.wakeUp();
}
/**
@@ -880,7 +813,7 @@ public class OsgiInstallerImpl
}
if ( updated || created ) {
this.persistentList.save();
- this.wakeUp();
+ this.scheduleRetry();
}
}
@@ -924,7 +857,7 @@ public class OsgiInstallerImpl
erl.setFinishState(ResourceState.UNINSTALLED);
erl.compact();
this.persistentList.save();
- this.wakeUp();
+ this.scheduleRetry();
} else {
logger.debug("No handler found to handle remove of resource with scheme {}", tr.getScheme());
}
@@ -933,7 +866,7 @@ public class OsgiInstallerImpl
// if it has been ignored before, we activate it now again!
((RegisteredResourceImpl)tr).setState(ResourceState.INSTALL);
this.persistentList.save();
- this.wakeUp();
+ this.scheduleRetry();
}
}
}
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/SortingServiceTracker.java Tue Dec 13 09:57:45 2011
@@ -23,6 +23,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import org.apache.sling.installer.api.tasks.RetryHandler;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
@@ -34,7 +35,7 @@ import org.osgi.util.tracker.ServiceTrac
public class SortingServiceTracker<T>
extends ServiceTracker {
- private final OsgiInstallerImpl listener;
+ private final RetryHandler listener;
private int lastCount = -1;
@@ -49,7 +50,7 @@ public class SortingServiceTracker<T>
*/
public SortingServiceTracker(final BundleContext context,
final String clazz,
- final OsgiInstallerImpl listener) {
+ final RetryHandler listener) {
super(context, clazz, null);
this.listener = listener;
}
@@ -82,7 +83,7 @@ public class SortingServiceTracker<T>
this.sortedReferences = null;
if ( listener != null ) {
// new factory or resource transformer has been added, wake up main thread
- this.listener.wakeUp();
+ this.listener.scheduleRetry();
}
return context.getService(reference);
}
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleStartTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleStartTask.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleStartTask.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleStartTask.java Tue Dec 13 09:57:45 2011
@@ -22,55 +22,44 @@ import java.text.DecimalFormat;
import org.apache.sling.installer.api.tasks.InstallationContext;
import org.apache.sling.installer.api.tasks.ResourceState;
-import org.apache.sling.installer.api.tasks.TaskResource;
import org.apache.sling.installer.api.tasks.TaskResourceGroup;
-import org.apache.sling.installer.core.impl.OsgiInstallerImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
-/** Start a bundle given its bundle ID
- * Restarts if the bundle does not start on the first try,
- * but only after receiving a bundle or framework event,
- * indicating that it's worth retrying
+/**
+ * Start a bundle given its bundle ID
+ * Restarts if the bundle does not start on the first try,
+ * but only after receiving a bundle or framework event,
+ * indicating that it's worth retrying
*/
public class BundleStartTask extends AbstractBundleTask {
private static final String BUNDLE_START_ORDER = "70-";
- private static final String ATTR_RC = "bst:retryCount";
- private static final String ATTR_EC = "bst:eventsCount";
-
private final long bundleId;
- private final String sortKey;
- private long eventsCountForRetrying;
- private int retryCount = 0;
+ private final String sortKey;
- public BundleStartTask(final TaskResourceGroup r, final long bundleId, final BundleTaskCreator btc) {
- super(r, btc);
+ public BundleStartTask(final TaskResourceGroup r, final long bundleId, final BundleTaskCreator btc) {
+ super(r, btc);
this.bundleId = bundleId;
this.sortKey = BUNDLE_START_ORDER + new DecimalFormat("00000").format(bundleId);
- final TaskResource rr = this.getResource();
- if ( rr != null && rr.getTemporaryAttribute(ATTR_RC) != null ) {
- this.retryCount = (Integer)rr.getTemporaryAttribute(ATTR_RC);
- this.eventsCountForRetrying = (Long)rr.getTemporaryAttribute(ATTR_EC);
- }
- }
-
- @Override
- public String getSortKey() {
- return sortKey;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + ": bundle " + bundleId;
- }
-
- /**
- * @see org.apache.sling.installer.api.tasks.InstallTask#execute(org.apache.sling.installer.api.tasks.InstallationContext)
- */
- public void execute(final InstallationContext ctx) {
- // this is just a sanity check which should never be reached
+ }
+
+ @Override
+ public String getSortKey() {
+ return sortKey;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": bundle " + bundleId;
+ }
+
+ /**
+ * @see org.apache.sling.installer.api.tasks.InstallTask#execute(org.apache.sling.installer.api.tasks.InstallationContext)
+ */
+ public void execute(final InstallationContext ctx) {
+ // this is just a sanity check which should never be reached
if (bundleId == 0) {
this.getLogger().debug("Bundle 0 is the framework bundle, ignoring request to start it");
if ( this.getResource() != null ) {
@@ -79,23 +68,12 @@ public class BundleStartTask extends Abs
return;
}
- // Do not execute this task if waiting for events
- final long eventsCount = OsgiInstallerImpl.getTotalEventsCount();
- if (eventsCount < eventsCountForRetrying) {
- this.getLogger().debug("Task is not executable at this time, counters={}/{}",
- eventsCountForRetrying, eventsCount);
- if ( this.getResource() == null ) {
- ctx.addTaskToNextCycle(this);
- }
+ final Bundle b = this.getBundleContext().getBundle(bundleId);
+ if (b == null) {
+ this.getLogger().info("Cannot start bundle, id not found: {}", bundleId);
return;
}
- final Bundle b = this.getBundleContext().getBundle(bundleId);
- if (b == null) {
- this.getLogger().info("Cannot start bundle, id not found: {}", bundleId);
- return;
- }
-
final String fragmentHostHeader = getFragmentHostHeader(b);
if (fragmentHostHeader != null) {
this.getLogger().debug("Need to do a refresh of the bundle's host");
@@ -118,28 +96,12 @@ public class BundleStartTask extends Abs
try {
b.start();
this.setFinishedState(ResourceState.INSTALLED);
- this.getLogger().info("Bundle started (retry count={}, bundle ID={}) : {}",
- new Object[] {retryCount, bundleId, b.getSymbolicName()});
+ this.getLogger().info("Bundle started (bundle ID={}) : {}",
+ new Object[] {bundleId, b.getSymbolicName()});
} catch (final BundleException e) {
- this.getLogger().info("Could not start bundle (retry count={}, bundle ID={}) : {}. Reason: {}. Will retry.",
- new Object[] {retryCount, bundleId, b.getSymbolicName(), e});
-
- // Do the first retry immediately (in case "something" happenened right now
- // that warrants a retry), but for the next ones wait for at least one bundle
- // event or framework event
- if (this.retryCount == 0) {
- this.eventsCountForRetrying = OsgiInstallerImpl.getTotalEventsCount();
- } else {
- this.eventsCountForRetrying = OsgiInstallerImpl.getTotalEventsCount() + 1;
- }
- this.retryCount++;
- if ( this.getResource() == null ) {
- ctx.addTaskToNextCycle(this);
- } else {
- this.getResource().setTemporaryAttribute(ATTR_RC, this.retryCount);
- this.getResource().setTemporaryAttribute(ATTR_EC, this.eventsCountForRetrying);
- }
+ this.getLogger().info("Could not start bundle (bundle ID={}) : {}. Reason: {}. Will retry.",
+ new Object[] {bundleId, b.getSymbolicName(), e});
}
- }
+ }
}
}
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleTaskCreator.java Tue Dec 13 09:57:45 2011
@@ -23,12 +23,17 @@ import org.apache.sling.installer.api.Re
import org.apache.sling.installer.api.tasks.InstallTask;
import org.apache.sling.installer.api.tasks.InstallTaskFactory;
import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.RetryHandler;
import org.apache.sling.installer.api.tasks.TaskResource;
import org.apache.sling.installer.api.tasks.TaskResourceGroup;
import org.apache.sling.installer.core.impl.InternalService;
import org.apache.sling.installer.core.impl.Util;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
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.osgi.service.startlevel.StartLevel;
@@ -39,7 +44,8 @@ import org.slf4j.LoggerFactory;
/**
* Task creator for bundles
*/
-public class BundleTaskCreator implements InternalService, InstallTaskFactory {
+public class BundleTaskCreator
+ implements InternalService, InstallTaskFactory, FrameworkListener, BundleListener {
/** If this property is set, the bundle is installed if the currently installed version
* is the version specified by the property.
@@ -68,11 +74,19 @@ public class BundleTaskCreator implement
/** The bundle context. */
private BundleContext bundleContext;
+ /** The retry handler. */
+ private RetryHandler retryHandler;
+
/**
- * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext, org.apache.sling.installer.api.ResourceChangeListener)
+ * @see org.apache.sling.installer.core.impl.InternalService#init(org.osgi.framework.BundleContext, org.apache.sling.installer.api.ResourceChangeListener, RetryHandler)
*/
- public void init(final BundleContext bc, final ResourceChangeListener listener) {
+ public void init(final BundleContext bc, final ResourceChangeListener listener, final RetryHandler retryHandler) {
this.bundleContext = bc;
+ this.retryHandler = retryHandler;
+
+ this.bundleContext.addBundleListener(this);
+ this.bundleContext.addFrameworkListener(this);
+
// create and start tracker
this.packageAdminTracker = new ServiceTracker(bc, PACKAGE_ADMIN_NAME, null);
this.packageAdminTracker.open();
@@ -84,6 +98,10 @@ public class BundleTaskCreator implement
* @see org.apache.sling.installer.core.impl.InternalService#deactivate()
*/
public void deactivate() {
+ if ( this.bundleContext != null ) {
+ this.bundleContext.removeBundleListener(this);
+ this.bundleContext.removeFrameworkListener(this);
+ }
if ( this.packageAdminTracker != null ) {
this.packageAdminTracker.close();
this.packageAdminTracker = null;
@@ -95,6 +113,27 @@ public class BundleTaskCreator implement
}
/**
+ * @see org.osgi.framework.FrameworkListener#frameworkEvent(org.osgi.framework.FrameworkEvent)
+ */
+ public void frameworkEvent(final FrameworkEvent event) {
+ if ( event.getType() == FrameworkEvent.PACKAGES_REFRESHED ) {
+ logger.debug("Received FrameworkEvent triggering a retry of the installer: {}", event);
+ this.retryHandler.scheduleRetry();
+ }
+ }
+
+ /**
+ * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
+ */
+ public void bundleChanged(final BundleEvent event) {
+ final int t = event.getType();
+ if (t == BundleEvent.INSTALLED || t == BundleEvent.RESOLVED || t == BundleEvent.STARTED || t == BundleEvent.UPDATED) {
+ logger.debug("Received BundleEvent triggering a retry of the installer: {}", event);
+ this.retryHandler.scheduleRetry();
+ }
+ }
+
+ /**
* @see org.apache.sling.installer.core.impl.InternalService#getDescription()
*/
public String getDescription() {
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/InstallerBundleUpdateTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/InstallerBundleUpdateTask.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/InstallerBundleUpdateTask.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/InstallerBundleUpdateTask.java Tue Dec 13 09:57:45 2011
@@ -22,11 +22,8 @@ import org.apache.sling.installer.api.ta
import org.apache.sling.installer.api.tasks.InstallationContext;
import org.apache.sling.installer.api.tasks.TaskResourceGroup;
import org.apache.sling.installer.core.impl.AbstractInstallTask;
-import org.apache.sling.installer.core.impl.OsgiInstallerImpl;
import org.osgi.framework.Bundle;
import org.osgi.service.packageadmin.PackageAdmin;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Update the installer itself
@@ -38,7 +35,7 @@ public class InstallerBundleUpdateTask e
private final BundleTaskCreator creator;
public InstallerBundleUpdateTask(final TaskResourceGroup r,
- final BundleTaskCreator creator) {
+ final BundleTaskCreator creator) {
super(r);
this.creator = creator;
}
@@ -50,13 +47,11 @@ public class InstallerBundleUpdateTask e
final Bundle b = this.creator.getBundleContext().getBundle();
final PackageAdmin pa = this.creator.getPackageAdmin();
- ctx.addTaskToNextCycle(new InstallTask(this.getResourceGroup()) {
-
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ ctx.addAsyncTask(new InstallTask(this.getResourceGroup()) {
@Override
public String getSortKey() {
- return OsgiInstallerImpl.ASYNC_TASK_KEY;
+ return BUNDLE_UPDATE_ORDER + getResource().getEntityId();
}
@Override
@@ -75,9 +70,9 @@ public class InstallerBundleUpdateTask e
pa.refreshPackages( new Bundle[] { b } );
}
- logger.debug("Bundle updated: {}/{}", b.getBundleId(), b.getSymbolicName());
+ getLogger().debug("Bundle updated: {}/{}", b.getBundleId(), b.getSymbolicName());
} catch (final Exception e) {
- logger.warn("Removing failing tasks - unable to retry: " + this, e);
+ getLogger().warn("Removing failing tasks - unable to retry: " + this, e);
}
}
});
Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/SystemBundleUpdateTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/SystemBundleUpdateTask.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/SystemBundleUpdateTask.java (original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/tasks/SystemBundleUpdateTask.java Tue Dec 13 09:57:45 2011
@@ -26,11 +26,8 @@ import org.apache.sling.installer.api.ta
import org.apache.sling.installer.api.tasks.ResourceState;
import org.apache.sling.installer.api.tasks.TaskResourceGroup;
import org.apache.sling.installer.core.impl.AbstractInstallTask;
-import org.apache.sling.installer.core.impl.OsgiInstallerImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Update the system bundle from a RegisteredResource.
@@ -58,13 +55,11 @@ public class SystemBundleUpdateTask exte
// restart system bundle
if ( this.getResource() == null ) {
// do an async update
- ctx.addTaskToNextCycle(new InstallTask(this.getResourceGroup()) {
-
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ ctx.addAsyncTask(new InstallTask(this.getResourceGroup()) {
@Override
public String getSortKey() {
- return OsgiInstallerImpl.ASYNC_TASK_KEY;
+ return BUNDLE_UPDATE_ORDER + getResource().getURL();
}
@Override
@@ -72,7 +67,7 @@ public class SystemBundleUpdateTask exte
try {
systemBundle.update();
} catch (final BundleException e) {
- logger.warn("Updating system bundle failed - unable to retry: " + this, e);
+ getLogger().warn("Updating system bundle failed - unable to retry: " + this, e);
}
}
});
@@ -88,13 +83,11 @@ public class SystemBundleUpdateTask exte
// delayed system bundle update
final InputStream backgroundIS = is;
is = null;
- ctx.addTaskToNextCycle(new InstallTask(this.getResourceGroup()) {
-
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ ctx.addAsyncTask(new InstallTask(this.getResourceGroup()) {
@Override
public String getSortKey() {
- return OsgiInstallerImpl.ASYNC_TASK_KEY;
+ return BUNDLE_UPDATE_ORDER + getResource().getURL();
}
@Override
@@ -102,11 +95,11 @@ public class SystemBundleUpdateTask exte
try {
systemBundle.update(backgroundIS);
} catch (final BundleException e) {
- logger.warn("Updating system bundle failed - unable to retry: " + this, e);
+ getLogger().warn("Updating system bundle failed - unable to retry: " + this, e);
} finally {
try {
backgroundIS.close();
- } catch (IOException ignore) {}
+ } catch (final IOException ignore) {}
}
}
});
@@ -117,7 +110,7 @@ public class SystemBundleUpdateTask exte
if ( is != null ) {
try {
is.close();
- } catch (IOException ignore) {}
+ } catch (final IOException ignore) {}
}
}
}
Modified: sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java?rev=1213634&r1=1213633&r2=1213634&view=diff
==============================================================================
--- sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java (original)
+++ sling/trunk/installer/core/src/test/java/org/apache/sling/installer/core/impl/tasks/MockBundleTaskCreator.java Tue Dec 13 09:57:45 2011
@@ -31,7 +31,7 @@ class MockBundleTaskCreator extends Bund
private final Map<String, BundleInfo> fakeBundleInfo = new HashMap<String, BundleInfo>();
public MockBundleTaskCreator() throws IOException {
- this.init(new MockBundleContext(), null);
+ this.init(new MockBundleContext(), null, null);
}
void addBundleInfo(String symbolicName, String version, int state) {