Jumpi v1.2.0

org.jumpi.impl.timer
Class TimerImpl

java.lang.Object
  |
  +--org.jumpi.impl.timer.TimerImpl
All Implemented Interfaces:
Component, Configurable, Manageable, java.lang.Runnable, Task, Timer

public class TimerImpl
extends java.lang.Object
implements Timer, Task

Simple timer implementation.

A general-purpose time-based daemon, vaguely similar in functionality to common system-level utilities such as at (and the associated crond) in Unix. Objects of this class maintain a single thread and a task queue that may be used to execute Runnable commands in any of three modes , absolute (run at a given time), relative (run after a given delay), and periodic (cyclically run with a given delay).

All commands are executed by the single background thread. The thread is not actually started until the first request is encountered. Also, if the thread is stopped for any reason, one is started upon encountering the next request, or restart() is invoked.

If you would instead like commands run in their own threads, you can use as arguments Runnable commands that start their own threads (or perhaps wrap within ThreadedExecutors).

You can also use multiple daemon objects, each using a different background thread. However, one of the reasons for using a time daemon is to pool together processing of infrequent tasks using a single background thread.

Background threads are created using a ThreadFactory. The default factory does not automatically setDaemon status.

The class uses Java timed waits for scheduling. These can vary in precision across platforms, and provide no real-time guarantees about meeting deadlines.

[ Introduction to this package. ]


Constructor Summary
TimerImpl()
           
 
Method Summary
 void cancel(java.lang.Object taskID)
          Cancel a scheduled task that has not yet been run.
 void configure(java.lang.String name, Properties props)
          Configure the TimerImpl.
 java.lang.String getName()
          Get the fully qualified name of the instance.
 java.lang.String getTaskId()
          The taskId is set to the TimerImpl's name, since there is only one timer in the Jumpi component tree, and the Component name is unique.
 java.lang.Object interruptAfterDelay(long millisecondsToDelay, TimerListener listener)
          Excecute the given command after waiting for the given delay.
 java.lang.Object interruptAt(long time, TimerListener listener)
          Execute the given command at the given time.
 java.lang.Object interruptPeriodically(long period, TimerListener listener, boolean startNow)
          Execute the given command every period milliseconds.
 boolean isLongRunning()
          The TimerImpl task is long running, since the task runs in an infinite loop waiting to notify the registered TimerListeners when timers have triggered.
 boolean isSchedulable()
          Whether the task is schedulable, i.e. run() should be called because there is work to do.
 void manage(Component root, Component parent, java.lang.String operation, java.util.Hashtable parameters)
          Perform a recursive management operation through the Jumpi component tree, using the parameters provided.
 void run()
          Loop indefinitely getting tasks to interrupt, and interrupting them until stopped.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

TimerImpl

public TimerImpl()
Method Detail

configure

public void configure(java.lang.String name,
                      Properties props)
               throws java.lang.Exception
Configure the TimerImpl.

The following configuration attributes are defined:

Specified by:
configure in interface Configurable
Parameters:
name - the fully qualified instance name.
props - the read-only properties to configure the instance with.
Throws:
java.lang.Exception - when configuration is unsuccessful.
java.lang.IllegalArgumentException - if name or props are missing.

manage

public void manage(Component root,
                   Component parent,
                   java.lang.String operation,
                   java.util.Hashtable parameters)
            throws java.lang.Exception
Perform a recursive management operation through the Jumpi component tree, using the parameters provided.

The following management actions are handled:

Specified by:
manage in interface Manageable
Parameters:
root - the Jumpi instance at the root of the component tree.
parent - the immediate parent of the component.
operation - the operation.
parameters - the operation parameters.
Throws:
java.lang.Exception - if any failure to perform management occurs.
java.lang.IllegalArgumentException - when parameters are missing.

getName

public java.lang.String getName()
Get the fully qualified name of the instance. Identical to the name used in configure.

Specified by:
getName in interface Configurable
Returns:
the fully qualified name of the instance.
See Also:
configure(java.lang.String, org.jumpi.spi.Properties)

getTaskId

public java.lang.String getTaskId()
The taskId is set to the TimerImpl's name, since there is only one timer in the Jumpi component tree, and the Component name is unique.

Specified by:
getTaskId in interface Task
Returns:
the TimerImpl's name.
See Also:
getName()

isSchedulable

public boolean isSchedulable()
Whether the task is schedulable, i.e. run() should be called because there is work to do.

Specified by:
isSchedulable in interface Task
Returns:
true if the component has started, else false.

isLongRunning

public boolean isLongRunning()
The TimerImpl task is long running, since the task runs in an infinite loop waiting to notify the registered TimerListeners when timers have triggered.

Specified by:
isLongRunning in interface Task
Returns:
true always.

interruptAt

public java.lang.Object interruptAt(long time,
                                    TimerListener listener)
Execute the given command at the given time.

Specified by:
interruptAt in interface Timer
Parameters:
time - -- the absolute time to run the command, expressed as a java.util.Date.
listener - -- the listener to interrupt at the given time.
Returns:
taskID -- an opaque reference that can be used to cancel execution request
Throws:
java.lang.IllegalArgumentException - if listener is null.
java.lang.IllegalStateException - if not started.
See Also:
Timer.cancel(java.lang.Object), TimerListener.handleTimerInterrupt()

interruptAfterDelay

public java.lang.Object interruptAfterDelay(long millisecondsToDelay,
                                            TimerListener listener)
Excecute the given command after waiting for the given delay.

Sample Usage. You can use a TimerImpl to arrange timeout callbacks to break out of stuck IO. For example (code sketch):

 class X {   ...
 
   TimerImpl timer = ...
   Thread readerThread;
   FileInputStream datafile;
 
   void startReadThread() {
     datafile = new FileInputStream("data", ...);
 
     readerThread = new Thread(new Runnable() {
      public void run() {
        for(;;) {
          // try to gracefully exit before blocking
         if (Thread.currentThread().isInterrupted()) {
           quietlyWrapUpAndReturn();
         }
         else {
           try {
             int c = datafile.read();
             if (c == -1) break;
             else process(c);
           }
           catch (IOException ex) {
            cleanup();
            return;
          }
       }
     } };
 
    readerThread.start();
 
    // establish callback to cancel after 60 seconds
    timer.executeAfterDelay(60000, new Runnable() {
      readerThread.interrupt();    // try to interrupt thread
      datafile.close(); // force thread to lose its input file 
    });
   } 
 }
 

Specified by:
interruptAfterDelay in interface Timer
Parameters:
millisecondsToDelay - -- the number of milliseconds from now to run the command.
listener - -- the listener to interrupt after the delay.
Returns:
taskID -- an opaque reference that can be used to cancel execution request
Throws:
java.lang.IllegalArgumentException - if listener is null.
java.lang.IllegalStateException - if not started.
See Also:
Timer.cancel(java.lang.Object), TimerListener.handleTimerInterrupt()

interruptPeriodically

public java.lang.Object interruptPeriodically(long period,
                                              TimerListener listener,
                                              boolean startNow)
Execute the given command every period milliseconds. If startNow is true, execution begins immediately, otherwise, it begins after the first period delay.

Sample Usage. Here is one way to update Swing components acting as progress indicators for long-running actions.

 class X {
   JLabel statusLabel = ...;
 
   int percentComplete = 0;
   synchronized int  getPercentComplete() { return percentComplete; }
   synchronized void setPercentComplete(int p) { percentComplete = p; }
 
   TimerImpl cd = ...;
 
   void startWorking() {
     Runnable showPct = new Runnable() {
       public void run() {
          SwingUtilities.invokeLater(new Runnable() {
            public void run() {
              statusLabel.setText(getPercentComplete() + "%");
            } 
          } 
       } 
     };
 
     final Object updater = cd.executePeriodically(500, showPct, true);
 
     Runnable action = new Runnable() {
       public void run() {
         for (int i = 0; i < 100; ++i) {
           work();
           setPercentComplete(i);
         }
         cd.cancel(updater);
       }
     };
 
     new Thread(action).start();
   }
 }  
 

Specified by:
interruptPeriodically in interface Timer
Parameters:
period - -- the period, in milliseconds. Periods are measured from start-of-task to the next start-of-task. It is generally a bad idea to use a period that is shorter than the expected task duration.
listener - -- the listener to interrupt at each cycle
startNow - -- true if the cycle should start with execution of the task now. Otherwise, the cycle starts with a delay of period milliseconds.
Returns:
taskID -- an opaque reference that can be used to cancel execution request
Throws:
java.lang.IllegalArgumentException - if period less than or equal to zero, or listener is null.
java.lang.IllegalStateException - if not started.
See Also:
Timer.cancel(java.lang.Object), TimerListener.handleTimerInterrupt()

cancel

public void cancel(java.lang.Object taskID)
Cancel a scheduled task that has not yet been run. The task will be cancelled upon the next opportunity to run it. This has no effect if this is a one-shot task that has already executed. Also, if an execution is in progress, it will complete normally. (It may however be interrupted via getThread().interrupt()). But if it is a periodic task, future iterations are cancelled.

Specified by:
cancel in interface Timer
Parameters:
taskID - -- a task reference returned by one of the execute commands
Throws:
java.lang.IllegalArgumentException - if the taskID is null

run

public void run()
Loop indefinitely getting tasks to interrupt, and interrupting them until stopped.

Specified by:
run in interface java.lang.Runnable

Jumpi v1.2.0

Copyright 2003, Peter Jonathan Klauser.