1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.james.util.watchdog;
22
23 import org.apache.excalibur.thread.ThreadPool;
24 import org.apache.avalon.framework.activity.Disposable;
25 import org.apache.avalon.framework.container.ContainerUtil;
26 import org.apache.avalon.framework.logger.AbstractLogEnabled;
27
28
29
30
31
32
33
34
35
36
37 public class InaccurateTimeoutWatchdog
38 extends AbstractLogEnabled
39 implements Watchdog, Runnable, Disposable {
40
41
42
43
44 private volatile boolean isChecking = false;
45
46
47
48
49 private volatile boolean isReset = false;
50
51
52
53
54
55 private final long timeout;
56
57
58
59
60
61 private volatile long lastReset;
62
63
64
65
66
67 private WatchdogTarget triggerTarget;
68
69
70
71
72 private Thread watchdogThread;
73
74
75
76
77 private ThreadPool myThreadPool;
78
79
80
81
82
83
84
85
86 public InaccurateTimeoutWatchdog(long timeout, WatchdogTarget target, ThreadPool threadPool) {
87 if (target == null) {
88 throw new IllegalArgumentException("The WatchdogTarget for this TimeoutWatchdog cannot be null.");
89 }
90 if (threadPool == null) {
91 throw new IllegalArgumentException("The thread pool for this TimeoutWatchdog cannot be null.");
92 }
93 this.timeout = timeout;
94 triggerTarget = target;
95 myThreadPool = threadPool;
96 }
97
98
99
100
101 public void start() {
102 if (getLogger().isDebugEnabled()) {
103 getLogger().debug("[" + triggerTarget + "] Calling start()" );
104 }
105 lastReset = System.currentTimeMillis();
106 isChecking = true;
107 synchronized(this) {
108 if ( watchdogThread == null) {
109 myThreadPool.execute(this);
110 }
111 }
112 }
113
114
115
116
117
118 public void reset() {
119 if (watchdogThread != null) {
120 getLogger().debug("[" + triggerTarget + "] Calling reset() on thread '" + watchdogThread.getName() + "'");
121 } else {
122 getLogger().debug("[" + triggerTarget + "] Calling reset() for inactive watchdog");
123 }
124 isReset = true;
125 }
126
127
128
129
130
131 public void stop() {
132 if (watchdogThread != null) {
133 getLogger().debug("[" + triggerTarget + "] Calling stop() on thread '" + watchdogThread.getName() + "'");
134 } else {
135 getLogger().debug("[" + triggerTarget + "] Calling stop() for inactive watchdog");
136 }
137 isChecking = false;
138 }
139
140
141
142
143 public void run() {
144
145 try {
146 watchdogThread = Thread.currentThread();
147
148 while ((!(Thread.interrupted())) && (watchdogThread != null)) {
149 try {
150 if (!isChecking) {
151 if (getLogger().isDebugEnabled()) {
152 getLogger().debug("[" + triggerTarget + "] Watchdog on thread '" + Thread.currentThread().getName() + "' is not active - going to exit.");
153 }
154 synchronized (this) {
155 if (!isChecking) {
156 watchdogThread = null;
157 }
158 continue;
159 }
160 } else {
161 long currentTime = System.currentTimeMillis();
162 if (isReset) {
163 isReset = false;
164 lastReset = currentTime;
165 }
166 long timeToSleep = lastReset + timeout - currentTime;
167 if (watchdogThread != null) {
168 getLogger().debug("[" + triggerTarget + "] Watchdog on thread '" + watchdogThread.getName() + "' has time to sleep " + timeToSleep);
169 } else {
170 getLogger().debug("[" + triggerTarget + "] Watchdog has time to sleep " + timeToSleep);
171 }
172 if (timeToSleep <= 0) {
173 try {
174 synchronized (this) {
175 if ((isChecking) && (triggerTarget != null)) {
176 triggerTarget.execute();
177 }
178 watchdogThread = null;
179 }
180 } catch (Throwable t) {
181 getLogger().error("[" + triggerTarget + "] Encountered error while executing Watchdog target.", t);
182 }
183 isChecking = false;
184 continue;
185 } else {
186 synchronized(this) {
187 wait(timeToSleep);
188 }
189 }
190 }
191 } catch (InterruptedException ie) {
192 }
193 }
194
195 synchronized( this ) {
196 watchdogThread = null;
197 }
198 } finally {
199
200
201 Thread.interrupted();
202 }
203 if (getLogger().isDebugEnabled()) {
204 getLogger().debug("[" + triggerTarget + "] Watchdog on thread '" + Thread.currentThread().getName() + "' is exiting run().");
205 }
206 }
207
208
209
210
211 public void dispose() {
212 synchronized(this) {
213 isChecking = false;
214 if (getLogger().isDebugEnabled()) {
215 if (watchdogThread != null) {
216 getLogger().debug("[" + triggerTarget + "] Calling disposeWatchdog() on thread '" + watchdogThread.getName() + "'");
217 } else {
218 getLogger().debug("[" + triggerTarget + "] Calling disposeWatchdog() for inactive watchdog");
219 }
220 }
221 if (watchdogThread != null) {
222 watchdogThread = null;
223 notifyAll();
224 }
225 ContainerUtil.dispose(triggerTarget);
226 triggerTarget = null;
227 }
228 }
229 }