/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2002
* Copyright by ESO (in the framework of the ALMA collaboration),
* All rights reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package alma.acs.shutdown;
import java.util.logging.Logger;
/**
* A subclass can be registered to the JVM Runtime as a shutdown thread to be run at shutdown,
* both for regular termination and for interruption like Ctrl-C (SIGINT).
* Make sure to call {@link #setRegularShutdownExpected()} before regularly exiting the JVM,
* as otherwise {@link #interruptDetected()} would be called erroneously.
* <p>
* Recommended reading: http://www-106.ibm.com/developerworks/ibm/library/i-signalhandling/
* (also talks about signals for tougher mishaps than Ctrl-c).
* See also {@link java.lang.Runtime#addShutdownHook(Thread)}
* <p>
* Abstracted from the java container's shutdown hook, to simplify registering such hooks also in jlog etc.
* @author hsommer
*/
public abstract class ShutdownHookBase extends Thread
{
protected volatile boolean m_regularShutdownExpected = false;
protected final Logger logger;
protected final String processName;
/**
* @param logger
* The logger to be used by this object.
* @param processName
* Used as the thread name, with "ShutdownHook" appended.
*/
public ShutdownHookBase(Logger logger, String processName) {
super(processName + "ShutdownHook");
this.processName = processName;
this.logger = logger;
}
/**
* @see java.lang.Runnable#run()
*/
public void run() {
try {
if (m_regularShutdownExpected) {
regularTermination();
} else {
interruptDetected();
}
} catch (Throwable thr) {
System.err.println("failure in ShutdownHook#run: ");
// at this stage it's too risky to use the logger
thr.printStackTrace();
}
}
/**
* Subclasses can override this method to log nothing or something else.
* No other action is expected in the overridden method.
*/
protected void regularTermination() {
// we can assume a regular exit (unless something went wrong after setRegularShutdownExpected() had been called
logger.info("about to exit the JVM of " + processName);
}
/**
* Is called when the JVM is about to terminate due to an interrupt signal.
* Subclasses should perform emergency cleanup.
*/
abstract protected void interruptDetected();
/**
* Must be called right before the program ends. This helps the ShutdownHook to decide
* whether it's being called for a regular program termination or because of an interrupt.
*/
public void setRegularShutdownExpected() {
m_regularShutdownExpected = true;
}
}