View Javadoc

    1   /***
    2    * @(#)Task.java
    3    *
    4    * JFoxSOAF, Service-Oriented Application Framework
    5    *
    6    * Copyright(c) JFoxSOAF Team
    7    *
    8    * Licensed under the GNU LGPL, Version 2.1 (the "License");
    9    * you may not use this file except in compliance with the License.
    10   * You may obtain a copy of the License at
    11   *
    12   * http://www.gnu.org/copyleft/lesser.html
    13   *
    14   * Unless required by applicable law or agreed to in writing, software
    15   * distributed under the License is distributed on an "AS IS" BASIS,
    16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17   * See the License for the specific language governing permissions and
    18   * limitations under the License.
    19   *
    20   * For more information, please visit:
    21   * http://www.jfox.cn/confluence/display/JFoxSOAF/Home
    22   * http://www.huihoo.org/jfox/jfoxsoaf
    23   */
    24
    25  package org.huihoo.jfox.soaf.services.timer;
    26
    27  import java.io.Externalizable;
    28  import java.io.ObjectOutput;
    29  import java.io.ObjectInput;
    30  import java.io.IOException;
    31
    32  /***
    33   * <p>
    34   * A task which can be scheduled to run at specified times by the TaskScheduler
    35   * <br>
    36   * </p>
    37   * <p>
    38   * The user should extend this class and override the required methods (e.g.
    39   * run() method).
    40   * </p>
    41   *
    42   * @author <a href="mailto:founder_chen@yahoo.com.cn">Peter Cheng </a>
    43   * @author <a href="mailto:berkovichnyc@hotmail.com">Efraim Berkovich </a>
    44   * @version $Revision: 1.1 $ $Date: 2005/05/22 06:52:07 $
    45   * @version Revision: 1.0
    46   */
    47
    48  public abstract class Task implements Runnable, Externalizable {
    49
    50      // instance variables
    51      /*** has the cancel() method been called? */
    52      protected boolean isCancelled = false;
    53
    54      /*** The name of the task (for display purposes) */
    55      protected String name = null;
    56
    57      private transient long ID;
    58
    59      private boolean hasBeenScheduled = false;
    60
    61      private long scheduledInitialTime = 0;
    62
    63      private long scheduledInterval = 0; // if <=0 -- means one-time execution
    64
    65      private long lastRunTime = 0;
    66
    67      // package view -- the task scheduler sets this when the task is scheduled
    68      // with it
    69      SimpleTimerServiceImpl scheduler = null;
    70
    71      // static variables
    72      private static Boolean mutex = new Boolean(true);
    73
    74      private static long nextID = 0;
    75
    76      /***
    77       * Creates a new task and assigns it a unique ID.
    78       */
    79      protected Task() {
    80          synchronized (mutex) {
    81              this.ID = nextID;
    82              nextID++;
    83              if (nextID == Long.MAX_VALUE)
    84                  nextID = 0;
    85          }
    86
    87      }
    88
    89      /***
    90       * Schedules the specified task for execution at the specified time. If the
    91       * time is in the past, the task is scheduled for immediate execution.
    92       * <p>
    93       * There are two types of scheduling: one time and periodic.
    94       * <p>
    95       * <b>One time </b> <br>
    96       * The task will execute exactly once.
    97       * <p>
    98       * <b>Periodic </b> <br>
    99       * The task is scheduled for repeated periodic execution, beginning at the
    100      * specified time. Once a task starts running, the next occurrence of the
    101      * task will start running <i>interval </i> time later. It is possible for
    102      * one event-firing of the task (if it runs too long) will overlap another
    103      * event-firing of that same task. If this is not desired, then the task
    104      * should synchronize within its run() method.
    105      * <p>
    106      * This method can only be called once. Calling it more than once will cause
    107      * an exception.
    108      * <p>
    109      *
    110      * @param firstTime long system time at which to run the task.
    111      * @param interval long number of millis between executions of the task,
    112      *            passing <=0 will cause the task to be executed once.
    113      * @exception IllegalStateException On calling this method more than once.
    114      */
    115     public synchronized final void setSchedule(long firstTime, long interval)
    116             throws IllegalStateException {
    117         if (hasBeenScheduled)
    118             throw new IllegalStateException(
    119                     "Cannot set schedule for the task more than once.");
    120
    121         hasBeenScheduled = true;
    122         this.scheduledInitialTime = firstTime;
    123         this.scheduledInterval = interval;
    124     }
    125
    126     /***
    127      * Get the task ID.
    128      *
    129      * @return unique Task ID.
    130      */
    131     public long getID() {
    132         return ID;
    133     }
    134
    135     /***
    136      * Get the first scheduled time for the task.
    137      *
    138      * @return the time the task was first scheduled to run (as long, millis)
    139      */
    140     public long getScheduledFirstTime() {
    141         return scheduledInitialTime;
    142     }
    143
    144     /***
    145      * Get the interval scheduled for the task.
    146      *
    147      * @return the interval scheduled for the task. (as long, millis)
    148      */
    149     public long getScheduledInterval() {
    150         return scheduledInterval;
    151     }
    152
    153     /***
    154      * Was the cancel method called for this task?
    155      *
    156      * @return true if cancel was called, false if not
    157      */
    158     public boolean isCancelled() {
    159         return isCancelled;
    160     }
    161
    162     /***
    163      * Get the name for the task
    164      *
    165      * @return the task name
    166      */
    167     public String getName() {
    168         if (name == null)
    169             return this.getClass().toString();
    170
    171         return name;
    172     }
    173
    174     /***
    175      * Calling this method notifies the TaskScheduler (if the task has been
    176      * scheduled) and forces it to persist this task's data.
    177      * <p>
    178      *
    179      * @exception various possible depending on persist strategy of the
    180      *                scheduler
    181      */
    182     public void persist() throws Exception {
    183         if (scheduler != null)
    184             scheduler.persist(this);
    185     }
    186
    187     /***
    188      * Cancels this timer task. If the task has been scheduled for one-time
    189      * execution and has not yet run, or has not yet been scheduled, it will
    190      * never run. If the task has been scheduled for repeated execution, it will
    191      * never run again. (If the task is running when this call occurs, the task
    192      * will run to completion, but will never run again.)
    193      * <p>
    194      * Note that calling this method from within the run method of a repeating
    195      * timer task absolutely guarantees that the timer task will not run again.
    196      * <p>
    197      * This method may be called repeatedly; the second and subsequent calls
    198      * have no effect.
    199      */
    200     public void cancel() {
    201         isCancelled = true;
    202         if (scheduler != null) {
    203             scheduler.cleanup(this);
    204         }
    205     }
    206
    207     /***
    208      * Returns the scheduled execution time of the most recent actual execution
    209      * of this task. (If this method is invoked while task execution is in
    210      * progress, the return value is the scheduled execution time of the ongoing
    211      * task execution.)
    212      * <p>
    213      * This method is typically invoked from within a task's run method, to
    214      * determine whether the current execution of the task is sufficiently
    215      * timely to warrant performing the scheduled activity:
    216      * <p>
    217      *
    218      * <pre>
    219      * public void run() {
    220      *     if (System.currentTimeMillis() - lastExecutionTime() &gt;= MAX_TARDINESS)
    221      *         return; // Too late; skip this execution.
    222      *     // Perform the task
    223      * }
    224      * </pre>
    225      *
    226      * <p>
    227      *
    228      * @return the time at which the most recent execution of this task was
    229      *         scheduled to occur, in the format returned by Date.getTime(). The
    230      *         return value is undefined if the task has yet to commence its
    231      *         first execution.
    232      */
    233     public long lastExecutionTime() {
    234         return lastRunTime;
    235     }
    236
    237     /***
    238      * Set the last run time. This is only called by the TaskScheduler
    239      *
    240      * @param lastRunTime. The last run time
    241      */
    242     void setLastRunTime(long lastRunTime) {
    243         this.lastRunTime = lastRunTime;
    244     }
    245
    246     /***
    247      * This method persists the task. Tasks should override this method if they
    248      * carry instance data. (Make sure to call super.writeExternal() if you
    249      * override).
    250      *
    251      * @param ObjectOutput The stream to write the object to
    252      * @exception IOException On write problems
    253      */
    254     public void writeExternal(ObjectOutput out) throws IOException {
    255         out.writeLong(this.scheduledInitialTime);
    256         out.writeLong(this.scheduledInterval);
    257         out.writeLong(this.lastRunTime);
    258         out.writeObject(this.name);
    259     }
    260
    261     /***
    262      * This method instantiates the task from persistent storage. Tasks should
    263      * override this method if they carry instance data. (Make sure to call
    264      * super.writeExternal() if you override).
    265      * <p>
    266      * When a Task is instantiated from deserialization, the
    267      * scheduledInitialTime is set according to the following rules:
    268      * <ul>
    269      * <li>If the scheduledInitialTime is in the future, that time is kept.
    270      * <li>If the scheduledInitialTime is in the past and the Task is a
    271      * repeating task, then the scheduledInitialTime is set to the next time the
    272      * task would run had the Task not been serialized. For example, if a Task
    273      * runs once a day at 1pm, then the scheduledInitialTime will be set to the
    274      * next 1pm running time. (The logic does not distinguish between fixed-rate
    275      * vs. fixed-delay Tasks).
    276      * </ul>
    277      *
    278      * @param ObjectInput The stream to write the object to
    279      * @exception IOException On write problems
    280      * @exception ClassNotFoundException On the class not being in the stream.
    281      */
    282     public void readExternal(ObjectInput in) throws IOException,
    283             java.lang.ClassNotFoundException {
    284         this.scheduledInitialTime = in.readLong();
    285         this.scheduledInterval = in.readLong();
    286         this.lastRunTime = in.readLong();
    287         this.name = (String) in.readObject();
    288
    289         // set scheduledInitialTime to make it in the future
    290         if (scheduledInitialTime < System.currentTimeMillis()) {
    291             long n = System.currentTimeMillis() - scheduledInitialTime;
    292             n = n % scheduledInterval;
    293             this.scheduledInitialTime = System.currentTimeMillis() + n;
    294         }
    295
    296         // assume all deserialized tasks had setSchedule() called
    297         hasBeenScheduled = true;
    298     }
    299
    300     /***
    301      * This method is the action to be performed. This method should be
    302      * overriden. It will be called once at every time the task runs.
    303      * <p>
    304      * If a task encounters an error during run, it may call the cancel() method
    305      * to prevent the task from running again.
    306      * <p>
    307      * If the task modifies its instance data during execution, then it should
    308      * call the Task persist() method. This will notify the TaskScheduler to
    309      * write the task to persistent storage by calling the writeExternal()
    310      * method.
    311      */
    312     public abstract void run();
    313
    314     /***
    315      * This method should provide a status message regarding the task. Care
    316      * should be taken to make sure the method is thread-safe, as code in the
    317      * run() method and the caller of getStatus() will likely be in different
    318      * threads.
    319      *
    320      * @return a task-specific status message
    321      */
    322     public abstract String getStatus();
    323
    324 }