001 package com.croftsoft.core.util.loop;
002
003 import com.croftsoft.core.lang.NullArgumentException;
004 import com.croftsoft.core.lang.ex.ExceptionHandler;
005 import com.croftsoft.core.lang.lifecycle.Lifecycle;
006
007 /*********************************************************************
008 * Periodically runs a task in a loop using a separate thread.
009 *
010 * @version
011 * $Id: Looper.java,v 1.3 2008/09/20 05:01:27 croft Exp $
012 * @since
013 * 2000-04-27
014 * @author
015 * <a href="https://www.croftsoft.com/">David Wallace Croft</a>
016 *********************************************************************/
017
018 public final class Looper
019 implements Lifecycle
020 //////////////////////////////////////////////////////////////////////
021 //////////////////////////////////////////////////////////////////////
022 {
023
024 private final Loopable loopable;
025
026 private final ExceptionHandler exceptionHandler;
027
028 private final String threadName;
029
030 private final int threadPriority;
031
032 private final boolean useDaemonThread;
033
034 //
035
036 private LoopGovernor loopGovernor;
037
038 private Thread thread;
039
040 private boolean stopRequested;
041
042 //////////////////////////////////////////////////////////////////////
043 //////////////////////////////////////////////////////////////////////
044
045 /*********************************************************************
046 * Main constructor.
047 *
048 * <p>
049 * Call the start() method after construction to begin looping.
050 * </p>
051 *
052 * @param loopable
053 *
054 * The loop() method of this object will be called periodically.
055 * Looping will stop if this method returns false.
056 *
057 * @param exceptionHandler
058 *
059 * Handles all Exceptions generated by runnable.run().
060 * The handleException() Object argument passed will be the loopable.
061 * If null, the default behavior of printing any Exception to the
062 * standard error output and stopping looping will be used.
063 *********************************************************************/
064 public Looper (
065 Loopable loopable,
066 LoopGovernor loopGovernor,
067 ExceptionHandler exceptionHandler,
068 String threadName,
069 int threadPriority,
070 boolean useDaemonThread )
071 //////////////////////////////////////////////////////////////////////
072 {
073 NullArgumentException.check ( this.loopable = loopable );
074
075 setLoopGovernor ( loopGovernor );
076
077 this.exceptionHandler = exceptionHandler;
078
079 this.threadName = threadName;
080
081 this.threadPriority = threadPriority;
082
083 this.useDaemonThread = useDaemonThread;
084 }
085
086 public Looper ( Loopable loopable )
087 //////////////////////////////////////////////////////////////////////
088 {
089 this (
090 loopable,
091 new FixedDelayLoopGovernor ( 0L, 0 ),
092 ( ExceptionHandler ) null,
093 ( String ) null,
094 Thread.MIN_PRIORITY,
095 true );
096 }
097
098 //////////////////////////////////////////////////////////////////////
099 //////////////////////////////////////////////////////////////////////
100
101 public void setLoopGovernor ( LoopGovernor loopGovernor )
102 //////////////////////////////////////////////////////////////////////
103 {
104 NullArgumentException.check ( this.loopGovernor = loopGovernor );
105 }
106
107 //////////////////////////////////////////////////////////////////////
108 //////////////////////////////////////////////////////////////////////
109
110 public void init ( )
111 //////////////////////////////////////////////////////////////////////
112 {
113 // empty
114 }
115
116 public synchronized void start ( )
117 //////////////////////////////////////////////////////////////////////
118 {
119 stopRequested = false;
120
121 if ( thread == null )
122 {
123 Runnable runnable =
124 new Runnable ( )
125 {
126 public void run ( )
127 {
128 loop ( );
129 }
130 };
131
132 if ( threadName == null )
133 {
134 thread = new Thread ( runnable );
135 }
136 else
137 {
138 thread = new Thread ( runnable, threadName );
139 }
140
141 thread.setPriority ( threadPriority );
142
143 thread.setDaemon ( useDaemonThread );
144
145 thread.start ( );
146 }
147 else
148 {
149 notify ( );
150 }
151 }
152
153 public synchronized void stop ( )
154 //////////////////////////////////////////////////////////////////////
155 {
156 stopRequested = true;
157
158 thread.interrupt ( );
159 }
160
161 public synchronized void destroy ( )
162 //////////////////////////////////////////////////////////////////////
163 {
164 thread = null;
165
166 stopRequested = false;
167
168 notify ( );
169 }
170
171 //////////////////////////////////////////////////////////////////////
172 //////////////////////////////////////////////////////////////////////
173
174 private void loop ( )
175 //////////////////////////////////////////////////////////////////////
176 {
177 while ( thread != null )
178 {
179 try
180 {
181 if ( loopable.loop ( ) )
182 {
183 loopGovernor.govern ( );
184 }
185 else
186 {
187 stopRequested = true;
188 }
189 }
190 catch ( InterruptedException ex )
191 {
192 // ignore
193 }
194 catch ( Exception ex )
195 {
196 if ( ( exceptionHandler == null )
197 || !exceptionHandler.handleException ( ex, loopable ) )
198 {
199 stopRequested = true;
200
201 ex.printStackTrace ( );
202 }
203 }
204
205 if ( stopRequested )
206 {
207 synchronized ( this )
208 {
209 while ( stopRequested )
210 {
211 try
212 {
213 wait ( );
214 }
215 catch ( InterruptedException ex )
216 {
217 // ignore
218 }
219 }
220 }
221 }
222 }
223 }
224
225 //////////////////////////////////////////////////////////////////////
226 //////////////////////////////////////////////////////////////////////
227 }