From 1b5239f1a2d0b5a0ad254c22fc0fe1929e06d425 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fa=CC=81bio=20Madeira?= Date: Fri, 2 Jun 2017 15:00:56 +0100 Subject: [PATCH] JWS-121 Added new scheduler utility classes so that usage statistics and service status can be monitored in a cronjob-like manner. RefreshIterator implements a ScheduleIterator that runs a new task every X minutes. --- .../compbio/stat/servlet/util/RefreshIterator.java | 36 +++++++ .../stat/servlet/util/ScheduleIterator.java | 18 ++++ .../compbio/stat/servlet/util/Scheduler.java | 108 ++++++++++++++++++++ .../compbio/stat/servlet/util/SchedulerTask.java | 68 ++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 webservices/compbio/stat/servlet/util/RefreshIterator.java create mode 100644 webservices/compbio/stat/servlet/util/ScheduleIterator.java create mode 100644 webservices/compbio/stat/servlet/util/Scheduler.java create mode 100644 webservices/compbio/stat/servlet/util/SchedulerTask.java diff --git a/webservices/compbio/stat/servlet/util/RefreshIterator.java b/webservices/compbio/stat/servlet/util/RefreshIterator.java new file mode 100644 index 0000000..37cd569 --- /dev/null +++ b/webservices/compbio/stat/servlet/util/RefreshIterator.java @@ -0,0 +1,36 @@ +package compbio.stat.servlet.util; + + +import java.util.Calendar; +import java.util.Date; + +/** + * A RefreshIterator returns a sequence of dates on subsequent days + * representing the same time each day. + */ +public class RefreshIterator implements ScheduleIterator { + private final int hourOfDay, minute, second, freq_time; + private final Calendar calendar = Calendar.getInstance(); + + public RefreshIterator(int hourOfDay, int minute, int second, int freq_time) { + this(hourOfDay, minute, second, freq_time, new Date()); + } + + public RefreshIterator(int hourOfDay, int minute, int second, int freq_time, Date date) { + this.hourOfDay = hourOfDay; + this.minute = minute; + this.second = second; + this.freq_time = freq_time; + calendar.setTime(date); + calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, second); + calendar.set(Calendar.MILLISECOND, 0); + } + + public Date next() { + calendar.add(Calendar.MINUTE, this.freq_time); + return calendar.getTime(); + } + +} diff --git a/webservices/compbio/stat/servlet/util/ScheduleIterator.java b/webservices/compbio/stat/servlet/util/ScheduleIterator.java new file mode 100644 index 0000000..7016520 --- /dev/null +++ b/webservices/compbio/stat/servlet/util/ScheduleIterator.java @@ -0,0 +1,18 @@ +package compbio.stat.servlet.util; + +import java.util.Date; + +/** + * Implementations of ScheduleIterator specify a schedule as + * a series of java.util.Date objects. + */ + +public interface ScheduleIterator { + + /** + * Returns the next time that the related {@link SchedulerTask} should be run. + * + * @return the next time of execution + */ + public Date next(); +} diff --git a/webservices/compbio/stat/servlet/util/Scheduler.java b/webservices/compbio/stat/servlet/util/Scheduler.java new file mode 100644 index 0000000..3594179 --- /dev/null +++ b/webservices/compbio/stat/servlet/util/Scheduler.java @@ -0,0 +1,108 @@ +package compbio.stat.servlet.util; + +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; + + +/** + * A facility for threads to schedule recurring tasks for future + * execution in a background thread. + *

+ * This class is thread-safe: multiple threads can share a single + * Scheduler object without the need for external synchronization. + *

+ * Implementation note: internally Scheduler uses a + * java.util.Timer to schedule tasks. + */ +public class Scheduler { + + class SchedulerTimerTask extends TimerTask { + private SchedulerTask schedulerTask; + private ScheduleIterator iterator; + + public SchedulerTimerTask(SchedulerTask schedulerTask, + ScheduleIterator iterator) { + this.schedulerTask = schedulerTask; + this.iterator = iterator; + } + + public void run() { + schedulerTask.run(); + reschedule(schedulerTask, iterator); + } + } + + private final Timer timer = new Timer(); + + public Scheduler() { + } + + /** + * Terminates this Scheduler, discarding any currently scheduled tasks. + * Does not interfere with a currently executing task (if it exists). Once a scheduler + * has been terminated, its execution thread terminates gracefully, and no more tasks + * may be scheduled on it. + *

+ * Note that calling this method from within the run method of a scheduler task that was + * invoked by this scheduler absolutely guarantees that the ongoing task execution is the + * last task execution that will ever be performed by this scheduler. + *

+ * This method may be called repeatedly; the second and subsequent calls have no effect. + */ + + public void cancel() { + timer.cancel(); + } + + /** + * Schedules the specified task for execution according to the specified schedule. If times + * specified by the ScheduleIterator are in the past they are scheduled for + * immediate execution. + *

+ * + * @param schedulerTask task to be scheduled + * @param iterator iterator that describes the schedule + * @throws IllegalStateException if task was already scheduled or cancelled, scheduler was + * cancelled, or scheduler thread terminated. + */ + + public void schedule(SchedulerTask schedulerTask, + ScheduleIterator iterator) { + + Date time = iterator.next(); + if (time == null) { + schedulerTask.cancel(); + } else { + synchronized (schedulerTask.lock) { + if (schedulerTask.state != SchedulerTask.VIRGIN) { + throw new IllegalStateException("Task already scheduled " + + "or cancelled"); + } + schedulerTask.state = SchedulerTask.SCHEDULED; + schedulerTask.timerTask = + new SchedulerTimerTask(schedulerTask, iterator); + timer.schedule(schedulerTask.timerTask, time); + } + } + } + + private void reschedule(SchedulerTask schedulerTask, + ScheduleIterator iterator) { + + Date time = iterator.next(); + if (time == null) { + schedulerTask.cancel(); + } else { + synchronized (schedulerTask.lock) { + if (schedulerTask.state != SchedulerTask.CANCELLED) { + schedulerTask.timerTask = + new SchedulerTimerTask(schedulerTask, iterator); + timer.schedule(schedulerTask.timerTask, time); + } + } + } + } + +} + diff --git a/webservices/compbio/stat/servlet/util/SchedulerTask.java b/webservices/compbio/stat/servlet/util/SchedulerTask.java new file mode 100644 index 0000000..fa079ab --- /dev/null +++ b/webservices/compbio/stat/servlet/util/SchedulerTask.java @@ -0,0 +1,68 @@ +package compbio.stat.servlet.util; + +import java.util.TimerTask; + + +/** + * A task that can be scheduled for recurring execution by a {@link Scheduler}. + */ +public abstract class SchedulerTask implements Runnable { + + final Object lock = new Object(); + + int state = VIRGIN; + static final int VIRGIN = 0; + static final int SCHEDULED = 1; + static final int CANCELLED = 2; + + TimerTask timerTask; + + /** + * Creates a new scheduler task. + */ + + protected SchedulerTask() { + } + + /** + * The action to be performed by this scheduler task. + */ + + public abstract void run(); + + /** + * Cancels this scheduler task. + *

+ * This method may be called repeatedly; the second and subsequent calls have no effect. + * + * @return true if this task was already scheduled to run + */ + + public boolean cancel() { + synchronized (lock) { + if (timerTask != null) { + timerTask.cancel(); + } + boolean result = (state == SCHEDULED); + state = CANCELLED; + return result; + } + } + + /** + * Returns the scheduled execution time of the most recent actual execution of + * this task. (If this method is invoked while task execution is in progress, + * the return value is the scheduled execution time of the ongoing task execution.) + * + * @return the time at which the most recent execution of this task was scheduled + * to occur, in the format returned by Date.getTime(). The return value + * is undefined if the task has yet to commence its first execution. + */ + + public long scheduledExecutionTime() { + synchronized (lock) { + return timerTask == null ? 0 : timerTask.scheduledExecutionTime(); + } + } + +} -- 1.7.10.2