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 }