001 package org.shiftone.jrat.core.shutdown;
002
003
004 import org.shiftone.jrat.util.Assert;
005 import org.shiftone.jrat.util.HtmlUtil;
006 import org.shiftone.jrat.util.log.Logger;
007
008 import java.util.Stack;
009
010
011 /**
012 * Shut down order is important!
013 *
014 * @author jeff@shiftone.org (Jeff Drost)
015 * <p/>
016 * http://java.sun.com/developer/JDCTechTips/2006/tt0211.html#1
017 */
018 public class ShutdownRegistry implements ShutdownRegistryMBean {
019
020 private static final Logger LOG = Logger.getLogger(ShutdownRegistry.class);
021 private Stack shutdownStack = new Stack();
022 private ShutdownListener firstShutdownListener;
023
024 public ShutdownRegistry() {
025
026 LOG.info("new");
027
028 Thread shutdownHook = new Thread(new ShutdownRunnable(), "JRat-Shutdown");
029
030 shutdownHook.setDaemon(true);
031 Runtime.getRuntime().addShutdownHook(shutdownHook);
032 }
033
034
035 public void setFirstShutdownListener(ShutdownListener firstShutdownListener) {
036 this.firstShutdownListener = firstShutdownListener;
037 }
038
039
040 public synchronized void registerShutdownListener(ShutdownListener shutdownListener) {
041
042 LOG.info("registerShutdownListener " + shutdownListener);
043 Assert.assertNotNull("ShutdownListener", shutdownListener);
044 shutdownStack.push(shutdownListener);
045 }
046
047
048 private static void shutdown(ShutdownListener shutdownListener) {
049
050 try {
051 LOG.info("shutting down " + shutdownListener + "...");
052 shutdownListener.shutdown();
053 LOG.info("shutdown " + shutdownListener + " complete.");
054 }
055 catch (Throwable e) {
056 LOG.error("shutdown failed for " + shutdownListener, e);
057 e.printStackTrace(System.err);
058 }
059 }
060
061
062 private synchronized void shutdown() {
063
064 LOG.info("shutting down..." + shutdownStack);
065
066 if (firstShutdownListener != null) {
067 shutdown(firstShutdownListener);
068 }
069
070 while (!shutdownStack.isEmpty()) {
071 shutdown((ShutdownListener) shutdownStack.pop());
072 }
073
074 LOG.info("shutdown complete.");
075 shutdownStack.clear();
076 }
077
078
079 private class ShutdownRunnable implements Runnable {
080
081 public void run() {
082 shutdown();
083 }
084 }
085
086 public int getShutdownListenerCount() {
087 return shutdownStack.size();
088 }
089
090
091 public String getShutdownListenersHtml() {
092 return HtmlUtil.toHtml(shutdownStack);
093 }
094
095
096 public void forceShutdownNow() {
097 LOG.info("forceShutdownNow");
098 shutdown();
099 }
100 }