1 package org.csc.phynixx.watchdog;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import org.csc.phynixx.common.logger.IPhynixxLogger;
25 import org.csc.phynixx.common.logger.PhynixxLogManager;
26 import org.csc.phynixx.watchdog.objectref.IObjectReference;
27 import org.csc.phynixx.watchdog.objectref.ObjectReference;
28 import org.csc.phynixx.watchdog.objectref.WeakObjectReference;
29
30 import java.util.HashSet;
31 import java.util.Iterator;
32 import java.util.Set;
33
34
35 class Watchdog implements Runnable, IWatchdog {
36
37 private IPhynixxLogger log = PhynixxLogManager.getLogger(this.getClass());
38
39
40
41
42 private RestartCondition restartCondition = null;
43
44
45
46
47 private class ThreadHandle {
48 private Thread thread = null;
49
50 private ThreadHandle() {
51 super();
52 }
53
54 private void start() {
55 if (this.thread != null && this.thread.isAlive()) {
56 throw new IllegalStateException("Thread " + this.thread + " is alive and can't be restartet");
57 }
58 String title = "Watchdog::" + Watchdog.this.getId().toString();
59 this.thread = new Thread(Watchdog.this, title);
60 this.thread.start();
61 }
62
63 private Thread getThread() {
64 return thread;
65 }
66
67 public String toString() {
68 return this.thread != null ? this.thread.toString() : "null";
69 }
70
71 private void shutdown() {
72 this.thread = null;
73 }
74 }
75
76
77 private Set<IObjectReference<IWatchedCondition>> conditions = new HashSet<IObjectReference<IWatchedCondition>>();
78
79 private String description = "";
80
81 private long checkInterval = 100L;
82 private volatile boolean killed = false;
83 private ThreadHandle threadHandle = new ThreadHandle();
84
85
86 private Long id =-1L;
87
88
89
90
91
92
93
94
95 Watchdog(Long id, long checkInterval) {
96 this(id, checkInterval, "");
97 }
98
99 Watchdog(Long id, long checkInterval, String description) {
100 super();
101 this.checkInterval = checkInterval;
102 this.description = description;
103 this.id = id;
104 this.threadHandle.start();
105 this.restartCondition = new RestartCondition(WatchdogRegistry.getWatchdogManagementInterval(), this);
106 }
107
108
109
110
111
112 public Long getId() {
113 return id;
114 }
115
116 ThreadHandle getThreadHandle() {
117 return threadHandle;
118 }
119
120
121
122
123
124 RestartCondition getRestartCondition() {
125 return restartCondition;
126 }
127
128
129
130
131
132 public Thread getThread() {
133 ThreadHandle th = this.getThreadHandle();
134 return th.thread;
135 }
136
137
138
139
140 public long getCheckInterval() {
141 return checkInterval;
142 }
143
144
145
146
147
148 public void registerCondition(IWatchedCondition cond) {
149 this.registerCondition(cond, true);
150 }
151
152
153
154
155
156 void registerCondition(IWatchedCondition cond, boolean weakReferenced) {
157 synchronized (conditions) {
158 if(!isConditionRegistered(cond)) {
159 IObjectReference<IWatchedCondition> objRef = null;
160 if (weakReferenced) {
161 objRef = new WeakObjectReference(cond);
162 } else {
163 objRef = new ObjectReference(cond);
164 }
165
166 this.conditions.add(objRef);
167 }
168 }
169 }
170
171 private boolean isConditionRegistered(IWatchedCondition cond) {
172 Set<IWatchedCondition> conds=copyConditions();
173 return conds.contains(cond);
174 }
175
176
177
178
179
180 public int getCountRegisteredConditions() {
181 return this.conditions.size();
182 }
183
184
185
186
187 public Set<IWatchedCondition> getAliveConditions() {
188 return this.copyConditions();
189 }
190
191
192
193
194
195 public void unregisterCondition(IWatchedCondition condition) {
196 synchronized (conditions) {
197 Set<IObjectReference<IWatchedCondition>> copiedRefs=new HashSet<IObjectReference<IWatchedCondition>>(this.conditions);
198
199 for (Iterator<IObjectReference<IWatchedCondition>> iterator = copiedRefs.iterator(); iterator.hasNext(); ) {
200 IObjectReference<IWatchedCondition> objRef = iterator.next();
201 IWatchedCondition cond = objRef.get();
202 if (cond == null || cond.equals(condition)) {
203 this.conditions.remove(objRef);
204 }
205 }
206 }
207 }
208
209 void copyConditions(IWatchdog wd) {
210 Set<IWatchedCondition> copiedConditions = this.copyConditions();
211 synchronized (wd) {
212 for (Iterator<IWatchedCondition> iterator = copiedConditions.iterator(); iterator.hasNext(); ) {
213 wd.registerCondition( iterator.next());
214 }
215 }
216 }
217
218
219
220
221
222
223 private Set<IWatchedCondition> copyConditions() {
224 Set<IWatchedCondition> copiedConditions = null;
225
226 synchronized (conditions) {
227
228 Set<IObjectReference<IWatchedCondition>> copiedObjref = new HashSet<IObjectReference<IWatchedCondition>>(this.conditions);
229 copiedConditions = new HashSet<IWatchedCondition>(this.conditions.size());
230
231 this.conditions.clear();
232 IWatchedCondition cond = null;
233 for (Iterator<IObjectReference<IWatchedCondition>> iterator = copiedObjref.iterator(); iterator.hasNext(); ) {
234 IObjectReference<IWatchedCondition> objRef = iterator.next();
235 cond = objRef.get();
236 if (!objRef.isStale() && cond != null && !cond.isUseless()) {
237 copiedConditions.add(cond);
238 this.conditions.add(objRef);
239 }
240 }
241
242 }
243
244 return copiedConditions;
245 }
246
247
248
249
250
251 public boolean isKilled() {
252 return killed;
253 }
254
255
256
257
258 public synchronized void activate() {
259
260 synchronized (this.conditions) {
261 IWatchedCondition cond = null;
262 for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); ) {
263 IObjectReference objRef = (IObjectReference) iterator.next();
264 if (objRef.get() != null) {
265 cond = (IWatchedCondition) objRef.get();
266 cond.setActive(true);
267 }
268 }
269 }
270 }
271
272
273
274
275 public synchronized void deactivate() {
276
277 synchronized (this.conditions) {
278 IWatchedCondition cond = null;
279 for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); ) {
280 IObjectReference objRef = (IObjectReference) iterator.next();
281 if (objRef.get() != null) {
282 cond = (IWatchedCondition) objRef.get();
283 cond.setActive(false);
284 }
285 }
286 }
287 }
288
289
290
291
292
293 public synchronized void stop() {
294 try {
295 this.kill();
296 } finally {
297 this.killed = false;
298 this.restartCondition.setUseless(false);
299 this.restartCondition.setActive(false);
300 }
301
302 }
303
304
305 public synchronized void kill() {
306 this.restartCondition.setUseless(true);
307
308 if (this.isKilled() || this.threadHandle.getThread() == null || !this.threadHandle.getThread().isAlive()) {
309 this.killed = true;
310 this.threadHandle.shutdown();
311 this.acknowledgeKilled();
312 return;
313 }
314
315
316 if (!this.isKilled() && this.threadHandle.getThread() != null && this.threadHandle.getThread().isAlive()) {
317 this.killed = true;
318 this.threadHandle.getThread().interrupt();
319 }
320
321
322 int limit = 10;
323 int count = 0;
324 while (this.threadHandle.getThread().isAlive() && count < limit) {
325 if (log.isInfoEnabled()) {
326 log.info("Watchdog.kill: Waiting to notification " + this.getId());
327 }
328 try {
329 this.wait(1000);
330 } catch (InterruptedException e) {
331 }
332 count++;
333 }
334 if (log.isInfoEnabled()) {
335 log.info("Watchdog.kill: Watchdog " + this.getId() + " killed");
336 }
337
338 this.threadHandle.shutdown();
339 }
340
341 public synchronized void restart() {
342
343 this.kill();
344
345 this.killed = false;
346 this.threadHandle.start();
347
348 if (this.log.isInfoEnabled()) {
349 this.log.info(" Watchdog " + getId() + " restarted");
350 }
351
352 this.restartCondition.setUseless(false);
353 this.restartCondition.setActive(true);
354
355 }
356
357
358
359
360 public boolean isUseless() {
361
362 boolean useless = true;
363 synchronized (conditions) {
364 for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); ) {
365 IObjectReference objRef = (IObjectReference) iterator.next();
366 if (!objRef.isStale() && !((IWatchedCondition) (objRef.get())).isUseless()) {
367 useless = false;
368 }
369 }
370 }
371
372 return useless;
373 }
374
375
376 public boolean isStale() {
377 return false;
378 }
379
380
381
382
383 public boolean isAlive() {
384 if (this.threadHandle.getThread() != null) {
385 return this.threadHandle.getThread().isAlive();
386 }
387 return false;
388 }
389
390 public void run() {
391 while (!this.isKilled()) {
392
393 long start = System.currentTimeMillis();
394 long waiting = this.checkInterval;
395 while (waiting > 0) {
396 try {
397 Thread.currentThread().sleep(waiting);
398 } catch (InterruptedException e) {
399 } finally {
400 if (this.isKilled()) {
401 break;
402 }
403 waiting = this.checkInterval - (System.currentTimeMillis() - start);
404 }
405 }
406
407
408 if (this.isKilled()) {
409 break;
410 }
411
412 evaluateConditions();
413
414
415 try {
416 Thread.currentThread().sleep(10);
417 } catch (InterruptedException e) {
418 }
419 }
420
421 this.acknowledgeKilled();
422 }
423
424
425
426
427
428
429
430 private synchronized void evaluateConditions() {
431
432 Set<IWatchedCondition> copiedConditions = this.copyConditions();
433
434
435 for (Iterator<IWatchedCondition> iterator = copiedConditions.iterator(); iterator.hasNext(); ) {
436 IWatchedCondition cond = iterator.next();
437
438 synchronized (cond) {
439
440 if (cond.isActive() && !cond.checkCondition()) {
441 cond.conditionViolated();
442 }
443 }
444 }
445 return;
446 }
447
448 private void acknowledgeKilled() {
449 synchronized (this) {
450 this.killed=true;
451 this.notifyAll();
452 }
453
454 }
455
456
457
458
459 public String[] getConditionInfos() {
460 String[] conds = new String[conditions.size()];
461 synchronized (conditions) {
462 int i = 0;
463 for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); i++) {
464 IObjectReference objRef = (IObjectReference) iterator.next();
465 StringBuffer buffer = new StringBuffer(" -- ");
466 if (objRef.isStale()) {
467 buffer.append("primarily description :: " + objRef.getObjectDescription());
468 } else {
469 buffer.append(objRef.get());
470 }
471 buffer.append("; isStale=").append(objRef.isStale()).
472 append(" ; isWeakReference=").append(objRef.isWeakReference());
473 conds[i] = buffer.toString();
474 }
475 }
476
477 return conds;
478 }
479
480
481
482
483 public String getWatchdogInfo() {
484 StringBuffer buffer = new StringBuffer("Watchdog [").
485 append("ID=").append(this.id).
486 append("; CheckInterval=").append(this.checkInterval).append(" msecs");
487 if (this.description != null && !this.description.equals("")) {
488 buffer.append("; ").append(this.description);
489 }
490 buffer.append("]");
491 buffer.append(" isAlive=").append(this.isAlive()).append("; ");
492 if (this.getThread() != null) {
493 buffer.append(this.getThread());
494 } else {
495 buffer.append("NO THREAD");
496 }
497 buffer.append(" #watched conditions=").append(this.getAliveConditions().size());
498
499 return buffer.toString();
500 }
501
502
503 public String toString() {
504 StringBuffer buffer = new StringBuffer(this.getWatchdogInfo()).append('\n');
505
506 String[] conditionInfos = this.getConditionInfos();
507 for (int i = 0; i < conditionInfos.length; i++) {
508 buffer.append(" . . . ").append(conditionInfos[i]).append("\n");
509 }
510
511 return buffer.toString();
512
513 }
514
515
516 }