diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java
new file mode 100644
index 00000000000..f53108cec24
--- /dev/null
+++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed 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.springframework.scheduling.commonj;
+
+import javax.naming.NamingException;
+
+import commonj.timers.TimerManager;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.Lifecycle;
+import org.springframework.jndi.JndiLocatorSupport;
+
+/**
+ * Base class for classes that are accessing a CommonJ {@link commonj.timers.TimerManager}
+ * Defines common configuration settings and common lifecycle handling.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see commonj.timers.TimerManager
+ */
+public abstract class TimerManagerAccessor extends JndiLocatorSupport
+ implements InitializingBean, DisposableBean, Lifecycle {
+
+ private TimerManager timerManager;
+
+ private String timerManagerName;
+
+ private boolean shared = false;
+
+
+ /**
+ * Specify the CommonJ TimerManager to delegate to.
+ *
Note that the given TimerManager's lifecycle will be managed
+ * by this FactoryBean.
+ *
Alternatively (and typically), you can specify the JNDI name
+ * of the target TimerManager.
+ * @see #setTimerManagerName
+ */
+ public void setTimerManager(TimerManager timerManager) {
+ this.timerManager = timerManager;
+ }
+
+ /**
+ * Set the JNDI name of the CommonJ TimerManager.
+ *
This can either be a fully qualified JNDI name, or the JNDI name relative
+ * to the current environment naming context if "resourceRef" is set to "true".
+ * @see #setTimerManager
+ * @see #setResourceRef
+ */
+ public void setTimerManagerName(String timerManagerName) {
+ this.timerManagerName = timerManagerName;
+ }
+
+ /**
+ * Specify whether the TimerManager obtained by this FactoryBean
+ * is a shared instance ("true") or an independent instance ("false").
+ * The lifecycle of the former is supposed to be managed by the application
+ * server, while the lifecycle of the latter is up to the application.
+ *
Default is "false", i.e. managing an independent TimerManager instance.
+ * This is what the CommonJ specification suggests that application servers
+ * are supposed to offer via JNDI lookups, typically declared as a
+ * resource-ref of type commonj.timers.TimerManager
+ * in web.xml, with res-sharing-scope set to 'Unshareable'.
+ *
Switch this flag to "true" if you are obtaining a shared TimerManager,
+ * typically through specifying the JNDI location of a TimerManager that
+ * has been explicitly declared as 'Shareable'. Note that WebLogic's
+ * cluster-aware Job Scheduler is a shared TimerManager too.
+ *
The sole difference between this FactoryBean being in shared or
+ * non-shared mode is that it will only attempt to suspend / resume / stop
+ * the underlying TimerManager in case of an independent (non-shared) instance.
+ * This only affects the {@link org.springframework.context.Lifecycle} support
+ * as well as application context shutdown.
+ * @see #stop()
+ * @see #start()
+ * @see #destroy()
+ * @see commonj.timers.TimerManager
+ */
+ public void setShared(boolean shared) {
+ this.shared = shared;
+ }
+
+
+ public void afterPropertiesSet() throws NamingException {
+ if (this.timerManager == null) {
+ if (this.timerManagerName == null) {
+ throw new IllegalArgumentException("Either 'timerManager' or 'timerManagerName' must be specified");
+ }
+ this.timerManager = lookup(this.timerManagerName, TimerManager.class);
+ }
+ }
+
+ protected final TimerManager getTimerManager() {
+ return this.timerManager;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Implementation of Lifecycle interface
+ //---------------------------------------------------------------------
+
+ /**
+ * Resumes the underlying TimerManager (if not shared).
+ * @see commonj.timers.TimerManager#resume()
+ */
+ public void start() {
+ if (!this.shared) {
+ this.timerManager.resume();
+ }
+ }
+
+ /**
+ * Suspends the underlying TimerManager (if not shared).
+ * @see commonj.timers.TimerManager#suspend()
+ */
+ public void stop() {
+ if (!this.shared) {
+ this.timerManager.suspend();
+ }
+ }
+
+ /**
+ * Considers the underlying TimerManager as running if it is
+ * neither suspending nor stopping.
+ * @see commonj.timers.TimerManager#isSuspending()
+ * @see commonj.timers.TimerManager#isStopping()
+ */
+ public boolean isRunning() {
+ return (!this.timerManager.isSuspending() && !this.timerManager.isStopping());
+ }
+
+
+ //---------------------------------------------------------------------
+ // Implementation of DisposableBean interface
+ //---------------------------------------------------------------------
+
+ /**
+ * Stops the underlying TimerManager (if not shared).
+ * @see commonj.timers.TimerManager#stop()
+ */
+ public void destroy() {
+ // Stop the entire TimerManager, if necessary.
+ if (!this.shared) {
+ // May return early, but at least we already cancelled all known Timers.
+ this.timerManager.stop();
+ }
+ }
+
+}
diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java
index e39193f4cc6..e46cbdba701 100644
--- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java
+++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java
@@ -27,7 +27,6 @@ import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.Lifecycle;
-import org.springframework.jndi.JndiLocatorSupport;
/**
* {@link org.springframework.beans.factory.FactoryBean} that retrieves a
@@ -52,71 +51,14 @@ import org.springframework.jndi.JndiLocatorSupport;
* @see commonj.timers.TimerManager
* @see commonj.timers.TimerListener
*/
-public class TimerManagerFactoryBean extends JndiLocatorSupport
+public class TimerManagerFactoryBean extends TimerManagerAccessor
implements FactoryBean, InitializingBean, DisposableBean, Lifecycle {
- private TimerManager timerManager;
-
- private String timerManagerName;
-
- private boolean shared = false;
-
private ScheduledTimerListener[] scheduledTimerListeners;
private final List timers = new LinkedList();
- /**
- * Specify the CommonJ TimerManager to delegate to.
- *
Note that the given TimerManager's lifecycle will be managed
- * by this FactoryBean.
- *
Alternatively (and typically), you can specify the JNDI name
- * of the target TimerManager.
- * @see #setTimerManagerName
- */
- public void setTimerManager(TimerManager timerManager) {
- this.timerManager = timerManager;
- }
-
- /**
- * Set the JNDI name of the CommonJ TimerManager.
- *
This can either be a fully qualified JNDI name, or the JNDI name relative
- * to the current environment naming context if "resourceRef" is set to "true".
- * @see #setTimerManager
- * @see #setResourceRef
- */
- public void setTimerManagerName(String timerManagerName) {
- this.timerManagerName = timerManagerName;
- }
-
- /**
- * Specify whether the TimerManager obtained by this FactoryBean
- * is a shared instance ("true") or an independent instance ("false").
- * The lifecycle of the former is supposed to be managed by the application
- * server, while the lifecycle of the latter is up to the application.
- *
Default is "false", i.e. managing an independent TimerManager instance.
- * This is what the CommonJ specification suggests that application servers
- * are supposed to offer via JNDI lookups, typically declared as a
- * resource-ref of type commonj.timers.TimerManager
- * in web.xml, with res-sharing-scope set to 'Unshareable'.
- *
Switch this flag to "true" if you are obtaining a shared TimerManager,
- * typically through specifying the JNDI location of a TimerManager that
- * has been explicitly declared as 'Shareable'. Note that WebLogic's
- * cluster-aware Job Scheduler is a shared TimerManager too.
- *
The sole difference between this FactoryBean being in shared or
- * non-shared mode is that it will only attempt to suspend / resume / stop
- * the underlying TimerManager in case of an independent (non-shared) instance.
- * This only affects the {@link org.springframework.context.Lifecycle} support
- * as well as application context shutdown.
- * @see #stop()
- * @see #start()
- * @see #destroy()
- * @see commonj.timers.TimerManager
- */
- public void setShared(boolean shared) {
- this.shared = shared;
- }
-
/**
* Register a list of ScheduledTimerListener objects with the TimerManager
* that this FactoryBean creates. Depending on each ScheduledTimerListener's settings,
@@ -135,28 +77,22 @@ public class TimerManagerFactoryBean extends JndiLocatorSupport
//---------------------------------------------------------------------
public void afterPropertiesSet() throws NamingException {
- if (this.timerManager == null) {
- if (this.timerManagerName == null) {
- throw new IllegalArgumentException("Either 'timerManager' or 'timerManagerName' must be specified");
- }
- this.timerManager = lookup(this.timerManagerName, TimerManager.class);
- }
-
+ super.afterPropertiesSet();
if (this.scheduledTimerListeners != null) {
+ TimerManager timerManager = getTimerManager();
for (ScheduledTimerListener scheduledTask : this.scheduledTimerListeners) {
- Timer timer = null;
+ Timer timer;
if (scheduledTask.isOneTimeTask()) {
- timer = this.timerManager.schedule(scheduledTask.getTimerListener(), scheduledTask.getDelay());
+ timer = timerManager.schedule(scheduledTask.getTimerListener(), scheduledTask.getDelay());
}
else {
if (scheduledTask.isFixedRate()) {
- timer = this.timerManager
- .scheduleAtFixedRate(scheduledTask.getTimerListener(), scheduledTask.getDelay(),
- scheduledTask.getPeriod());
+ timer = timerManager.scheduleAtFixedRate(
+ scheduledTask.getTimerListener(), scheduledTask.getDelay(), scheduledTask.getPeriod());
}
else {
- timer = this.timerManager.schedule(scheduledTask.getTimerListener(), scheduledTask.getDelay(),
- scheduledTask.getPeriod());
+ timer = timerManager.schedule(
+ scheduledTask.getTimerListener(), scheduledTask.getDelay(), scheduledTask.getPeriod());
}
}
this.timers.add(timer);
@@ -170,11 +106,12 @@ public class TimerManagerFactoryBean extends JndiLocatorSupport
//---------------------------------------------------------------------
public TimerManager getObject() {
- return this.timerManager;
+ return getTimerManager();
}
public Class extends TimerManager> getObjectType() {
- return (this.timerManager != null ? this.timerManager.getClass() : TimerManager.class);
+ TimerManager timerManager = getTimerManager();
+ return (timerManager != null ? timerManager.getClass() : TimerManager.class);
}
public boolean isSingleton() {
@@ -182,41 +119,6 @@ public class TimerManagerFactoryBean extends JndiLocatorSupport
}
- //---------------------------------------------------------------------
- // Implementation of Lifecycle interface
- //---------------------------------------------------------------------
-
- /**
- * Resumes the underlying TimerManager (if not shared).
- * @see commonj.timers.TimerManager#resume()
- */
- public void start() {
- if (!this.shared) {
- this.timerManager.resume();
- }
- }
-
- /**
- * Suspends the underlying TimerManager (if not shared).
- * @see commonj.timers.TimerManager#suspend()
- */
- public void stop() {
- if (!this.shared) {
- this.timerManager.suspend();
- }
- }
-
- /**
- * Considers the underlying TimerManager as running if it is
- * neither suspending nor stopping.
- * @see commonj.timers.TimerManager#isSuspending()
- * @see commonj.timers.TimerManager#isStopping()
- */
- public boolean isRunning() {
- return (!this.timerManager.isSuspending() && !this.timerManager.isStopping());
- }
-
-
//---------------------------------------------------------------------
// Implementation of DisposableBean interface
//---------------------------------------------------------------------
@@ -227,6 +129,7 @@ public class TimerManagerFactoryBean extends JndiLocatorSupport
* @see commonj.timers.Timer#cancel()
* @see commonj.timers.TimerManager#stop()
*/
+ @Override
public void destroy() {
// Cancel all registered timers.
for (Timer timer : this.timers) {
@@ -239,11 +142,8 @@ public class TimerManagerFactoryBean extends JndiLocatorSupport
}
this.timers.clear();
- // Stop the entire TimerManager, if necessary.
- if (!this.shared) {
- // May return early, but at least we already cancelled all known Timers.
- this.timerManager.stop();
- }
+ // Stop the TimerManager itself.
+ super.destroy();
}
}
diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java
new file mode 100644
index 00000000000..05f77c0d7aa
--- /dev/null
+++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed 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.springframework.scheduling.commonj;
+
+import java.util.Date;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import commonj.timers.Timer;
+import commonj.timers.TimerListener;
+
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.Trigger;
+import org.springframework.scheduling.support.SimpleTriggerContext;
+
+/**
+ * Implementation of Spring's {@link TaskScheduler} interface, wrapping
+ * a CommonJ {@link commonj.timers.TimerManager}.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler {
+
+ public ScheduledFuture schedule(Runnable task, Trigger trigger) {
+ return new ReschedulingTimerListener(task, trigger).schedule();
+ }
+
+ public ScheduledFuture schedule(Runnable task, Date startTime) {
+ TimerScheduledFuture futureTask = new TimerScheduledFuture(task);
+ Timer timer = getTimerManager().schedule(futureTask, startTime);
+ futureTask.setTimer(timer);
+ return futureTask;
+ }
+
+ public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) {
+ TimerScheduledFuture futureTask = new TimerScheduledFuture(task);
+ Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, startTime, period);
+ futureTask.setTimer(timer);
+ return futureTask;
+ }
+
+ public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) {
+ TimerScheduledFuture futureTask = new TimerScheduledFuture(task);
+ Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, 0, period);
+ futureTask.setTimer(timer);
+ return futureTask;
+ }
+
+ public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
+ TimerScheduledFuture futureTask = new TimerScheduledFuture(task);
+ Timer timer = getTimerManager().schedule(futureTask, startTime, delay);
+ futureTask.setTimer(timer);
+ return futureTask;
+ }
+
+ public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) {
+ TimerScheduledFuture futureTask = new TimerScheduledFuture(task);
+ Timer timer = getTimerManager().schedule(futureTask, 0, delay);
+ futureTask.setTimer(timer);
+ return futureTask;
+ }
+
+
+ /**
+ * ScheduledFuture adapter that wraps a CommonJ Timer.
+ */
+ private static class TimerScheduledFuture extends FutureTask