//
// ERXGracefulShutdown.java
// ERExtensions
//
// Created by Max Muller III on Thu Nov 06 2003.
//
package er.extensions.components;
import java.util.Enumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Signal;
import sun.misc.SignalHandler;
import com.webobjects.appserver.WOApplication;
import com.webobjects.foundation.NSArray;
import er.extensions.foundation.ERXProperties;
import er.extensions.foundation.ERXUtilities;
/**
* Graceful shutdown adds signal handling support for gracefully
* terminating a WOApplication. The default implementation in
* ERXApplication simply calls the terminate method. By default
* only the TERM and INT signals are registered to handle.
*/
public class ERXGracefulShutdown implements SignalHandler {
// ===========================================================================
// Class Constant(s)
// ---------------------------------------------------------------------------
private static final Logger log = LoggerFactory.getLogger(ERXGracefulShutdown.class);
// ===========================================================================
// Interfaces(s)
// ---------------------------------------------------------------------------
/**
* Interface to be implemented by the WOApplication subclass to gracefully
* handle termination. Implemented by ERXApplication.
*/
public static interface GracefulApplication {
public void gracefulTerminate();
}
// ===========================================================================
// Class Method(s)
// ---------------------------------------------------------------------------
/**
* Determines if signal handling is enabled. Defaults to false.
* @return if signal handling is enabled
*/
public static boolean isEnabled() {
return ERXProperties.booleanForKeyWithDefault("er.extensions.ERXGracefulShutdown.Enabled",
false);
}
/**
* Installs signal handlers for the given array of signals. Default signals
* to catch are TERM and INT. The previous handler is saved to chain back to
* if anything goes wrong with the graceful termination method.
*/
public static void installHandler() {
if (isEnabled()) {
// Just the rgular termination request
NSArray signals = ERXProperties.arrayForKey("er.extensions.ERXGracefulShutdown.SignalsToHandle");
if (signals != null && signals.count() > 0) {
for (Enumeration signalsEnumerator = signals.objectEnumerator();
signalsEnumerator.hasMoreElements();) {
Signal signal = new Signal((String)signalsEnumerator.nextElement());
ERXGracefulShutdown handler = new ERXGracefulShutdown();
handler.setDefaultHandler(Signal.handle(signal, handler));
}
}
}
}
// ===========================================================================
// Instance Variable(s)
// ---------------------------------------------------------------------------
/** caches the previous handler for chaining */
protected SignalHandler defaultHandler;
// ===========================================================================
// Instance Method(s)
// ---------------------------------------------------------------------------
/**
* Signal handling method. Gracefully terminates the currently running
* WOApplication.
* @param signal to be handled
*/
public void handle(Signal signal) {
log.info("Received {}, starting graceful shutdown.", signal);
try {
if (WOApplication.application() instanceof GracefulApplication) {
((GracefulApplication)WOApplication.application()).gracefulTerminate();
}
} catch (RuntimeException e) {
log.warn("Caught exception when attempting to gracefully shutdown! {} stack: {}", e.getClass().getName(), ERXUtilities.stackTrace(e));
}
// Chaining back to original handler
defaultHandler().handle(signal);
}
// ===========================================================================
// Instance Accessor Method(s)
// ---------------------------------------------------------------------------
/**
* @return the default handler
*/
public SignalHandler defaultHandler() { return defaultHandler; }
/**
*/
public void setDefaultHandler(SignalHandler value) { defaultHandler = value; }
}