001: package abbot.util;
002:
003: import java.util.Timer;
004: import java.lang.reflect.Field;
005: import java.util.TimerTask;
006: import java.util.Date;
007: import abbot.Log;
008:
009: /** Prevents misbehaving TimerTasks from canceling the timer thread by
010: throwing exceptions and/or errors. Also extends the basic Timer to use a
011: name for its thread. Naming the timer thread facilitates discerning
012: different threads in a full stack dump.<p>
013: */
014: public class NamedTimer extends Timer {
015:
016: /** Creates a non-daemon named timer. */
017: public NamedTimer(final String name) {
018: this (name, false);
019: }
020:
021: /** Creates a named timer, optionally running as a daemon thread. */
022: public NamedTimer(final String name, boolean isDaemon) {
023: super (isDaemon);
024: schedule(new TimerTask() {
025: public void run() {
026: Thread.currentThread().setName(name);
027: }
028: }, 0);
029: }
030:
031: /** Handle an exception thrown by a TimerTask. The default does
032: nothing. */
033: protected void handleException(Throwable thrown) {
034: Log.warn(thrown);
035: }
036:
037: // TODO: prevent scheduled tasks from throwing uncaught exceptions and
038: // thus canceling the Timer.
039: // We can easily wrap scheduled tasks with a catcher, but we can't readily
040: // cancel the wrapper when
041:
042: private class ProtectingTimerTask extends TimerTask {
043: private TimerTask task;
044:
045: public ProtectingTimerTask(TimerTask orig) {
046: this .task = orig;
047: }
048:
049: public void run() {
050: if (isCanceled()) {
051: cancel();
052: } else {
053: try {
054: task.run();
055: } catch (Throwable thrown) {
056: handleException(thrown);
057: }
058: }
059: }
060:
061: private boolean isCanceled() {
062: boolean canceled = false;
063: final int CANCELED = 3;
064: try {
065: Field f = TimerTask.class.getDeclaredField("state");
066: f.setAccessible(true);
067: int state = ((Integer) f.get(task)).intValue();
068: canceled = state == CANCELED;
069: } catch (Exception e) {
070: Log.warn(e);
071: }
072: return canceled;
073: }
074: }
075:
076: public void schedule(TimerTask task, Date time) {
077: super .schedule(new ProtectingTimerTask(task), time);
078: }
079:
080: public void schedule(TimerTask task, Date firstTime, long period) {
081: super
082: .schedule(new ProtectingTimerTask(task), firstTime,
083: period);
084: }
085:
086: public void schedule(TimerTask task, long delay) {
087: super .schedule(new ProtectingTimerTask(task), delay);
088: }
089:
090: public void schedule(TimerTask task, long delay, long period) {
091: super .schedule(new ProtectingTimerTask(task), delay, period);
092: }
093:
094: public void scheduleAtFixedRate(TimerTask task, Date firstTime,
095: long period) {
096: super .scheduleAtFixedRate(new ProtectingTimerTask(task),
097: firstTime, period);
098: }
099:
100: public void scheduleAtFixedRate(TimerTask task, long delay,
101: long period) {
102: super .scheduleAtFixedRate(new ProtectingTimerTask(task), delay,
103: period);
104: }
105: }
|