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 }