/*
* Copyright (c) 2008-2010 by Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package de.mxro.thrd.xstreemfs.foundation;
import de.mxro.thrd.xstreemfs.foundation.logging.Logging;
import de.mxro.thrd.xstreemfs.foundation.logging.Logging.Category;
/**
* A base class for threads representing a life cycle. It offers methods for
* blocking other threads until a certain life cycle event has occured. It
* currently supports two life cycle-related events: startup and shutdown.
*
* @author stender
*
*/
public class LifeCycleThread extends Thread {
private final Object startLock;
private final Object stopLock;
private boolean started;
private boolean stopped;
private Exception exc;
private LifeCycleListener listener;
public LifeCycleThread(String name) {
super(name);
startLock = new Object();
stopLock = new Object();
}
/**
* This method should be invoked by subclasses when the startup procedure
* has been completed.
*/
protected void notifyStarted() {
if (Logging.isInfo())
Logging.logMessage(Logging.LEVEL_INFO, Category.lifecycle, this, "Thread %s started", Thread
.currentThread().getName());
synchronized (startLock) {
started = true;
startLock.notifyAll();
if (listener != null)
listener.startupPerformed();
}
}
/**
* This method should be invoked by subclasses when the shutdown procedure
* has been completed.
*/
protected void notifyStopped() {
if (Logging.isInfo())
Logging.logMessage(Logging.LEVEL_INFO, Category.lifecycle, this, "Thread %s terminated", Thread
.currentThread().getName());
synchronized (stopLock) {
stopped = true;
stopLock.notifyAll();
if (listener != null)
listener.shutdownPerformed();
}
}
/**
* This method should be invoked by subclasses when the thread has crashed.
*/
protected void notifyCrashed(Exception exc) {
Logging.logMessage(Logging.LEVEL_CRIT, this, "service ***CRASHED***, shutting down");
Logging.logError(Logging.LEVEL_CRIT, this, exc);
synchronized (startLock) {
this.exc = exc;
started = true;
startLock.notifyAll();
}
synchronized (stopLock) {
this.exc = exc;
stopped = true;
stopLock.notifyAll();
}
if (listener != null)
listener.crashPerformed(exc);
}
/**
* Synchronously waits for a notification indicating that the startup
* procedure has been completed.
*
* @throws Exception
* if an error occured during the startup procedure
*/
public void waitForStartup() throws Exception {
synchronized (startLock) {
while (!started)
startLock.wait();
if (exc != null)
throw exc;
}
}
/**
* Synchronously waits for a notification indicating that the shutdown
* procedure has been completed.
*
* @throws Exception
* if an error occured during the shutdown procedure
*/
public void waitForShutdown() throws Exception {
synchronized (stopLock) {
if (!started)
return;
while (!stopped)
stopLock.wait();
if (exc != null)
throw exc;
}
}
/**
* Terminates the thread. This method should be overridden in subclasses.
* @throws Exception if an error occurred
*/
public void shutdown() throws Exception {
}
/**
* Sets a listener waiting for life cycle events.
*
* @param listener
* the listener
*/
public void setLifeCycleListener(LifeCycleListener listener) {
this.listener = listener;
}
}