001 package com.croftsoft.core.util;
002
003 import java.util.Timer;
004 import java.util.TimerTask;
005
006 import com.croftsoft.core.lang.lifecycle.Lifecycle;
007 import com.croftsoft.core.lang.NullArgumentException;
008
009 /*********************************************************************
010 * Runs tasks periodically.
011 *
012 * @version
013 * 2002-02-27
014 * @since
015 * 2001-03-06
016 * @author
017 * <a href="http://croftsoft.com/">David Wallace Croft</a>
018 *********************************************************************/
019
020 public final class Metronome
021 implements Lifecycle
022 //////////////////////////////////////////////////////////////////////
023 //////////////////////////////////////////////////////////////////////
024 {
025
026 private Runnable runnable;
027
028 private long periodInMilliseconds;
029
030 private final boolean useDaemonThread;
031
032 private boolean isStarted = false;
033
034 private Timer timer;
035
036 private TimerTask timerTask;
037
038 //////////////////////////////////////////////////////////////////////
039 //////////////////////////////////////////////////////////////////////
040
041 public Metronome (
042 Runnable runnable,
043 long periodInMilliseconds,
044 boolean useDaemonThread )
045 //////////////////////////////////////////////////////////////////////
046 {
047 NullArgumentException.check ( this.runnable = runnable );
048
049 this.periodInMilliseconds = periodInMilliseconds;
050
051 this.useDaemonThread = useDaemonThread;
052
053 if ( periodInMilliseconds < 0 )
054 {
055 throw new IllegalArgumentException (
056 "periodInMilliseconds < 0 " );
057 }
058 }
059
060 //////////////////////////////////////////////////////////////////////
061 //////////////////////////////////////////////////////////////////////
062
063 public synchronized void resetPeriodInMilliseconds (
064 long periodInMilliseconds )
065 //////////////////////////////////////////////////////////////////////
066 {
067 if ( periodInMilliseconds < 0 )
068 {
069 throw new IllegalArgumentException (
070 "periodInMilliseconds < 0 " );
071 }
072
073 this.periodInMilliseconds = periodInMilliseconds;
074
075 if ( isStarted )
076 {
077 stop ( );
078
079 start ( );
080 }
081 }
082
083 public synchronized void resetRunnable ( Runnable runnable )
084 //////////////////////////////////////////////////////////////////////
085 {
086 NullArgumentException.check ( this.runnable = runnable );
087
088 if ( isStarted )
089 {
090 stop ( );
091
092 start ( );
093 }
094 }
095
096 //////////////////////////////////////////////////////////////////////
097 //////////////////////////////////////////////////////////////////////
098
099 public synchronized void init ( )
100 //////////////////////////////////////////////////////////////////////
101 {
102 timer = new Timer ( useDaemonThread );
103 }
104
105 public synchronized void start ( )
106 //////////////////////////////////////////////////////////////////////
107 {
108 isStarted = true;
109
110 timerTask = new TimerTask ( ) {
111 public void run ( ) { runnable.run ( ); } };
112
113 // schedule() seems to max out at just under 20 tasks per second.
114 // Possibly due to a 50 ms system clock resolution?
115
116 timer.schedule ( timerTask, 0, periodInMilliseconds );
117 }
118
119 public synchronized void stop ( )
120 //////////////////////////////////////////////////////////////////////
121 {
122 isStarted = false;
123
124 if ( timerTask != null )
125 {
126 timerTask.cancel ( );
127 }
128
129 timerTask = null;
130 }
131
132 public synchronized void destroy ( )
133 //////////////////////////////////////////////////////////////////////
134 {
135 stop ( );
136
137 try
138 {
139 if ( timer != null )
140 {
141 timer.cancel ( );
142 }
143 }
144 catch ( Exception ex )
145 {
146 ex.printStackTrace ( );
147 }
148
149 timer = null;
150
151 runnable = null;
152 }
153
154 //////////////////////////////////////////////////////////////////////
155 //////////////////////////////////////////////////////////////////////
156 }