1 /************************************************************
2 * Copyright *
3 * Portions of this software are Copyright (c) 1993 - 2002, *
4 * Chad Z. Hower (Kudzu) and the Indy Pit Crew *
5 * - http://www.nevrona.com/Indy/ *
6 ************************************************************/
7
8 /************************************************************
9 * Copyright *
10 * Portions of this software are Copyright (c) 1993 - 2002, *
11 * Chad Z. Hower (Kudzu) and the Indy Pit Crew *
12 * - http://www.nevrona.com/Indy/ *
13 ************************************************************/
14 package org.indy;
15
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.Iterator;
20
21
22 /***
23 * Provides the basis for Indy threading as used by {@link PeerThread} in {@link TCPServer}.
24 *
25 *
26 *@author OTG
27 *@version 1.0
28 *@see StopMode
29 *@see Priority
30 */
31 public abstract class IndyThread implements Runnable {
32 /***
33 *
34 */
35 private Priority priority = Priority.NORMAL;
36
37 /***
38 *
39 */
40 private StopMode stopMode = StopMode.TERMINATE;
41
42 /***
43 *
44 */
45 private volatile Exception terminatingException;
46
47 /***
48 *
49 */
50 private volatile boolean stopped = true;
51
52 /***
53 *
54 */
55 private volatile boolean terminated = false;
56
57 /***
58 *
59 */
60 private final Object suspendLock = new Object();
61
62 /***
63 *
64 */
65 protected final Thread threadImpl = new IndyThreadImpl();
66
67 /***
68 *
69 */
70 private final ArrayList threadListeners = new ArrayList();
71
72 /***
73 * Description of the Field
74 */
75 protected volatile boolean stopRequested;
76
77 /***
78 * Constructor for the IdThread object
79 */
80 public IndyThread() {
81 }
82
83 /***
84 * Gets the stopped attribute of the IdThread object
85 *
86 *@return The stopped value
87 */
88 public boolean isStopped() {
89 return stopped;
90 }
91
92 /***
93 *
94 * @return
95 */
96 protected Thread getThreadImpl() {
97 return threadImpl;
98 }
99
100 /***
101 * Description of the Method
102 */
103 public final void start() {
104 if (terminated) {
105 throw new IllegalStateException();
106 }
107
108 if (!threadImpl.isAlive()) {
109 threadImpl.start();
110 }
111 else if (stopped) {
112 resume();
113 }
114
115 stopped = false;
116 }
117
118 /***
119 * Description of the Method
120 */
121 public final void stop() {
122 if (!stopped) {
123 if (stopMode == StopMode.TERMINATE) {
124 terminate();
125 }
126
127 stopped = true;
128 }
129 }
130
131 /***
132 *
133 */
134 public void terminate() {
135 stopped = true;
136 terminated = true;
137 resume();
138 }
139
140 /***
141 *
142 */
143 private void resume() {
144 synchronized (suspendLock) {
145 suspendLock.notifyAll();
146 }
147 }
148
149 /***
150 *
151 * @throws InterruptedException
152 */
153 private void suspend() throws InterruptedException {
154 synchronized (suspendLock) {
155 suspendLock.wait();
156 }
157 }
158
159 /***
160 * Description of the Method
161 *
162 *@throws InterruptedException Description of the Exception
163 */
164 public void join() throws InterruptedException {
165 threadImpl.join();
166 }
167
168 /***
169 * Description of the Method
170 *
171 *@throws InterruptedException Description of the Exception
172 */
173 public void terminateAndWait() throws InterruptedException {
174 terminate();
175 join();
176 }
177
178 /***
179 *
180 * @return
181 */
182 public StopMode getStopMode() {
183 return stopMode;
184 }
185
186 /***
187 *
188 * @param mode
189 */
190 public void setStopMode(StopMode mode) {
191 stopMode = mode;
192 }
193
194 /***
195 *
196 * @return
197 */
198 public Priority getPriority() {
199 //return priority;
200 return Priority.parse(threadImpl.getPriority());
201 }
202
203 /***
204 *
205 * @param p
206 */
207 public void setPriority(Priority p) {
208 priority = p;
209
210 if (!terminated) {
211 threadImpl.setPriority(p.num);
212 }
213 }
214
215 /***
216 *
217 */
218 protected void cleanup() throws InterruptedException {
219 }
220
221 /***
222 * Description of the Method
223 */
224 protected void beforeRun() throws InterruptedException {
225 }
226
227 /***
228 * Description of the Method
229 */
230 protected void afterRun() throws InterruptedException {
231 }
232
233 /***
234 * Description of the Method
235 */
236 protected void beforeExecute() throws InterruptedException {
237 }
238
239 /***
240 * Description of the Method
241 */
242 protected void afterExecute() throws InterruptedException {
243 }
244
245 /***
246 * Adds a feature to the ThreadListener attribute of the IdThread object
247 *
248 *@param l The feature to be added to the ThreadListener attribute
249 */
250 public void addThreadListener(IndyThreadListener l) {
251 synchronized (threadListeners) {
252 if (!threadListeners.contains(l)) {
253 threadListeners.add(l);
254 }
255 }
256 }
257
258 /***
259 *
260 * @param l
261 */
262 public void removeThreadListener(IndyThreadListener l) {
263 threadListeners.remove(l);
264 }
265
266 /***
267 *
268 */
269 private void doStopped() {
270 Collection l = null;
271
272 //don't want to block the list for the entire iteration (which could take any amount of time)
273 synchronized (threadListeners) {
274 l = Collections.unmodifiableCollection(threadListeners);
275 }
276
277 IndyThreadEvent evt = new IndyThreadEvent(this);
278
279 Iterator i = l.iterator();
280
281 while (i.hasNext()) {
282 ((IndyThreadListener) i.next()).onStopped(evt);
283 }
284 }
285
286 /***
287 *
288 */
289 private void doException() {
290 Collection l = null;
291
292 //don't want to block the list for the entire iteration (which could take any amount of time)
293 synchronized (threadListeners) {
294 l = Collections.unmodifiableCollection(threadListeners);
295 }
296
297 IndyThreadEvent evt = new IndyThreadEvent(this);
298
299 Iterator i = l.iterator();
300
301 while (i.hasNext()) {
302 ((IndyThreadListener) i.next()).onException(evt);
303 }
304 }
305
306 /***
307 * An enumertaed class describing the possible stopping modes for an IndyThread.
308 *
309 * <code>TERMINATE</code> means that any call to stop will terminate the thread, and the IndyThread instance will be unuseable.
310 * <code>SUSPEND</code> means that the thread will pause and can be restarted.
311 *
312 * @author OTG
313 * @version 1.0
314 * @see IndyThread
315 */
316 public static class StopMode {
317 /***
318 * Used to signal that the enclosing <code>IndyThread</code> should terminate when stop is called.
319 *
320 * @see IndyThread#stop()
321 */
322 public static final StopMode TERMINATE = new StopMode("Terminate");
323
324 /***
325 * Used to signal that the enclosing <code>IndyThread</code> should suspend when stop is called.
326 *
327 * @see IndyThread#stop()
328 */
329 public static final StopMode SUSPEND = new StopMode("Suspend");
330
331 /***
332 * A string representation of this <code>StopMode</code>
333 */
334 private final String friendlyName;
335
336 /***
337 * Constructs a new <code>StopMode</code>; private to prevent inheritence.
338 *
339 * @param friendlyName The string representation of this <code>StopMode</code>
340 */
341 private StopMode(String friendlyName) {
342 this.friendlyName = friendlyName;
343 }
344
345 /***
346 * Returns a string representation of this <code>StopMode</code> as a friendly name.
347 *
348 * @return A user friendly string for this <code>StopMode</code>
349 */
350 public String toString() {
351 return friendlyName;
352 }
353 }
354
355 /***
356 * Represents IndyThread priority.
357 *
358 *
359 */
360 public static class Priority {
361 /***
362 *
363 */
364 public static final Priority MIN = new Priority(Thread.MIN_PRIORITY);
365
366 /***
367 *
368 */
369 public static final Priority NORMAL = new Priority(Thread.NORM_PRIORITY);
370
371 /***
372 *
373 */
374 public static final Priority MAX = new Priority(Thread.MAX_PRIORITY);
375
376 /***
377 *
378 */
379 private final int num;
380
381 /***
382 *
383 * @param num
384 */
385 private Priority(int num) {
386 this.num = num;
387 }
388
389 public static Priority parse(int value) {
390 System.err.println(value);
391
392 switch (value) {
393 case 1:
394 case 2:
395 case 3:
396 return MIN;
397
398 case 4:
399 case 5:
400 case 6:
401 return NORMAL;
402
403 case 7:
404 case 8:
405 case 9:
406 case 10:
407 return MAX;
408
409 default:
410 throw new IllegalArgumentException(
411 "Not a valid thread priority value (1..10)");
412 }
413 }
414 }
415
416 /***
417 *
418 * <p>Title: </p>
419 * <p>Description: </p>
420 * <p>Copyright: Copyright (c) 2002</p>
421 * <p>Company: </p>
422 * @author unascribed
423 * @version 1.0
424 */
425 private class IndyThreadImpl extends Thread {
426 public void run() {
427 try {
428 try {
429 beforeExecute();
430
431 while (!terminated) {
432 if (stopped) {
433 doStopped();
434
435 if (stopped) {
436 if (terminated) {
437 break;
438 }
439
440 IndyThread.this.suspend();
441
442 if (terminated) {
443 break;
444 }
445 }
446
447 //if stopped inner
448 }
449
450 //if stopped outer
451 try {
452 beforeRun();
453
454 try {
455 while (!stopped) {
456 IndyThread.this.run();
457 }
458 }
459 finally {
460 afterRun();
461 }
462 }
463 finally {
464 cleanup();
465 }
466 }
467
468 //while !terminated
469 }
470
471 //tryf
472 finally {
473 afterExecute();
474 }
475 }
476
477 //tryc
478 catch (Exception e) {
479 terminatingException = e;
480 doException();
481 terminate();
482 }
483 }
484 }
485
486 //inner class
487 }
This page was automatically generated by Maven