![JAR search and dependency download from the Maven repository](/logo.png)
org.csc.phynixx.watchdog.Watchdog Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of phynixx-watchdog Show documentation
Show all versions of phynixx-watchdog Show documentation
generic watchdog implementation keeping dependent threads alive
The newest version!
package org.csc.phynixx.watchdog;
/*
* #%L
* phynixx-watchdog
* %%
* Copyright (C) 2014 csc
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.csc.phynixx.common.logger.IPhynixxLogger;
import org.csc.phynixx.common.logger.PhynixxLogManager;
import org.csc.phynixx.watchdog.objectref.IObjectReference;
import org.csc.phynixx.watchdog.objectref.ObjectReference;
import org.csc.phynixx.watchdog.objectref.WeakObjectReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
class Watchdog implements Runnable, IWatchdog {
private IPhynixxLogger log = PhynixxLogManager.getLogger(this.getClass());
/**
* condition checks if the current Watchdog's thread is running
*/
private RestartCondition restartCondition = null;
/**
* to be able to restart the watchdog thread it is kept as a handle. The basic thread can be restarted
*/
private class ThreadHandle {
private Thread thread = null;
private ThreadHandle() {
super();
}
private void start() {
if (this.thread != null && this.thread.isAlive()) {
throw new IllegalStateException("Thread " + this.thread + " is alive and can't be restartet");
}
String title = "Watchdog::" + Watchdog.this.getId().toString();
this.thread = new Thread(Watchdog.this, title);
this.thread.start();
}
private Thread getThread() {
return thread;
}
public String toString() {
return this.thread != null ? this.thread.toString() : "null";
}
private void shutdown() {
this.thread = null;
}
}
private Set> conditions = new HashSet>();
private String description = "";
private long checkInterval = 100L;
private volatile boolean killed = false;
private ThreadHandle threadHandle = new ThreadHandle();
private Long id =-1L;
/**
* instanciate Watchdog via WatchdogFactory
*
* @param id TODO
* @param checkInterval
*/
Watchdog(Long id, long checkInterval) {
this(id, checkInterval, "");
}
Watchdog(Long id, long checkInterval, String description) {
super();
this.checkInterval = checkInterval;
this.description = description;
this.id = id;
this.threadHandle.start(); // start the watchdog thread
this.restartCondition = new RestartCondition(WatchdogRegistry.getWatchdogManagementInterval(), this);
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#getId()
*/
public Long getId() {
return id;
}
ThreadHandle getThreadHandle() {
return threadHandle;
}
/**
* @return
*/
RestartCondition getRestartCondition() {
return restartCondition;
}
/**
* @return thread executing the background watch
* my be null (the watchdog needs to be restarted)
*/
public Thread getThread() {
ThreadHandle th = this.getThreadHandle();
return th.thread;
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#getCheckInterval()
*/
public long getCheckInterval() {
return checkInterval;
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#registerCondition(org.csc.phynixx.watchdog.IWatchedCondition)
*/
public void registerCondition(IWatchedCondition cond) {
this.registerCondition(cond, true);
}
/**
* @param cond
* @param weakReferenced indicates if the condition ist weak referenced
*/
void registerCondition(IWatchedCondition cond, boolean weakReferenced) {
synchronized (conditions) {
if(!isConditionRegistered(cond)) {
IObjectReference objRef = null;
if (weakReferenced) {
objRef = new WeakObjectReference(cond);
} else {
objRef = new ObjectReference(cond);
}
// keep a weak reference to the condition
this.conditions.add(objRef);
}
}
}
private boolean isConditionRegistered(IWatchedCondition cond) {
Set conds=copyConditions();
return conds.contains(cond);
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#getCountRegisteredConditions()
*/
public int getCountRegisteredConditions() {
return this.conditions.size();
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#getAliveConditions()
*/
public Set getAliveConditions() {
return this.copyConditions();
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#unregisterCondition(org.csc.phynixx.watchdog.IWatchedCondition)
*/
public void unregisterCondition(IWatchedCondition condition) {
synchronized (conditions) {
Set> copiedRefs=new HashSet>(this.conditions);
for (Iterator> iterator = copiedRefs.iterator(); iterator.hasNext(); ) {
IObjectReference objRef = iterator.next();
IWatchedCondition cond = objRef.get();
if (cond == null || cond.equals(condition)) {
this.conditions.remove(objRef);
}
}
}
}
void copyConditions(IWatchdog wd) {
Set copiedConditions = this.copyConditions();
synchronized (wd) {
for (Iterator iterator = copiedConditions.iterator(); iterator.hasNext(); ) {
wd.registerCondition( iterator.next());
}
}
}
/**
* copies the current set of conditions and cleans up the current set of conditions
*
* @return
*/
private Set copyConditions() {
Set copiedConditions = null;
// Copy the current Conditions ...
synchronized (conditions) {
Set> copiedObjref = new HashSet>(this.conditions);
copiedConditions = new HashSet(this.conditions.size());
this.conditions.clear();
IWatchedCondition cond = null;
for (Iterator> iterator = copiedObjref.iterator(); iterator.hasNext(); ) {
IObjectReference objRef = iterator.next();
cond = objRef.get();
if (!objRef.isStale() && cond != null && !cond.isUseless()) {
copiedConditions.add(cond);
this.conditions.add(objRef);
}
}
}
return copiedConditions;
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#isKilled()
*/
public boolean isKilled() {
return killed;
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#activate()
*/
public synchronized void activate() {
synchronized (this.conditions) {
IWatchedCondition cond = null;
for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); ) {
IObjectReference objRef = (IObjectReference) iterator.next();
if (objRef.get() != null) {
cond = (IWatchedCondition) objRef.get();
cond.setActive(true);
}
}
}
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#deactivate()
*/
public synchronized void deactivate() {
synchronized (this.conditions) {
IWatchedCondition cond = null;
for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); ) {
IObjectReference objRef = (IObjectReference) iterator.next();
if (objRef.get() != null) {
cond = (IWatchedCondition) objRef.get();
cond.setActive(false);
}
}
}
}
/**
* stops the executing thread but does not kill the thread.
* It can be restarted
*/
public synchronized void stop() {
try {
this.kill();
} finally {
this.killed = false;
this.restartCondition.setUseless(false);
this.restartCondition.setActive(false);
}
}
public synchronized void kill() {
this.restartCondition.setUseless(true);
if (this.isKilled() || this.threadHandle.getThread() == null || !this.threadHandle.getThread().isAlive()) {
this.killed = true;
this.threadHandle.shutdown();
this.acknowledgeKilled();
return;
}
// Interrupt the excuting thread an waiting for shutdown
if (!this.isKilled() && this.threadHandle.getThread() != null && this.threadHandle.getThread().isAlive()) {
this.killed = true;
this.threadHandle.getThread().interrupt();
}
// wait until the thread is stopped ....
int limit = 10;
int count = 0;
while (this.threadHandle.getThread().isAlive() && count < limit) {
if (log.isInfoEnabled()) {
log.info("Watchdog.kill: Waiting to notification " + this.getId());
}
try {
this.wait(1000);
} catch (InterruptedException e) {
}
count++;
}
if (log.isInfoEnabled()) {
log.info("Watchdog.kill: Watchdog " + this.getId() + " killed");
}
this.threadHandle.shutdown();
}
public synchronized void restart() {
this.kill();
this.killed = false;
this.threadHandle.start();
if (this.log.isInfoEnabled()) {
this.log.info(" Watchdog " + getId() + " restarted");
}
this.restartCondition.setUseless(false);
this.restartCondition.setActive(true);
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#isUseless()
*/
public boolean isUseless() {
boolean useless = true;
synchronized (conditions) {
for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); ) {
IObjectReference objRef = (IObjectReference) iterator.next();
if (!objRef.isStale() && !((IWatchedCondition) (objRef.get())).isUseless()) {
useless = false;
}
}
}
return useless;
}
public boolean isStale() {
return false;
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#isAlive()
*/
public boolean isAlive() {
if (this.threadHandle.getThread() != null) {
return this.threadHandle.getThread().isAlive();
}
return false;
}
public void run() {
while (!this.isKilled()) {
// wait until it time to check the conditions
long start = System.currentTimeMillis();
long waiting = this.checkInterval;
while (waiting > 0) {
try {
Thread.currentThread().sleep(waiting);
} catch (InterruptedException e) {
} finally {
if (this.isKilled()) {
break;
}
waiting = this.checkInterval - (System.currentTimeMillis() - start);
}
}
// recvheck if killed
if (this.isKilled()) {
break;
}
evaluateConditions();
// yielding ...
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
}
}
// acknowledge the thread starvation for all waiting for the dead of the thread
this.acknowledgeKilled();
}
/**
* evaluate the conditions
* it's synchronized to prevent any other thread from changing the state of
* the watchdog or of one of its conditions
*/
private synchronized void evaluateConditions() {
// Copy the current Conditions ...
Set copiedConditions = this.copyConditions();
// check the conditions ....
for (Iterator iterator = copiedConditions.iterator(); iterator.hasNext(); ) {
IWatchedCondition cond = iterator.next();
synchronized (cond) {
// the conditions are not accessed in a synchronized way. This has to be make sure by the Implementations
if (cond.isActive() && !cond.checkCondition()) {
cond.conditionViolated();
}
}
}
return;
}
private void acknowledgeKilled() {
synchronized (this) {
this.killed=true;
this.notifyAll();
}
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#getConditionInfos()
*/
public String[] getConditionInfos() {
String[] conds = new String[conditions.size()];
synchronized (conditions) {
int i = 0;
for (Iterator iterator = this.conditions.iterator(); iterator.hasNext(); i++) {
IObjectReference objRef = (IObjectReference) iterator.next();
StringBuffer buffer = new StringBuffer(" -- ");
if (objRef.isStale()) {
buffer.append("primarily description :: " + objRef.getObjectDescription());
} else {
buffer.append(objRef.get());
}
buffer.append("; isStale=").append(objRef.isStale()).
append(" ; isWeakReference=").append(objRef.isWeakReference());
conds[i] = buffer.toString();
}
}
return conds;
}
/* (non-Javadoc)
* @see org.csc.phynixx.watchdog.IWatchog#getWatchdogInfo()
*/
public String getWatchdogInfo() {
StringBuffer buffer = new StringBuffer("Watchdog [").
append("ID=").append(this.id).
append("; CheckInterval=").append(this.checkInterval).append(" msecs");
if (this.description != null && !this.description.equals("")) {
buffer.append("; ").append(this.description);
}
buffer.append("]");
buffer.append(" isAlive=").append(this.isAlive()).append("; ");
if (this.getThread() != null) {
buffer.append(this.getThread());
} else {
buffer.append("NO THREAD");
}
buffer.append(" #watched conditions=").append(this.getAliveConditions().size());
return buffer.toString();
}
public String toString() {
StringBuffer buffer = new StringBuffer(this.getWatchdogInfo()).append('\n');
String[] conditionInfos = this.getConditionInfos();
for (int i = 0; i < conditionInfos.length; i++) {
buffer.append(" . . . ").append(conditionInfos[i]).append("\n");
}
return buffer.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy