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    }