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="https://www.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         }