/** * DataCleaner (community edition) * Copyright (C) 2014 Neopost - Customer Information Management * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program 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 distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.datacleaner.bootstrap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class DCExitActionListener implements ExitActionListener { private static final Logger logger = LoggerFactory.getLogger(DCExitActionListener.class); public static void printThreadInformation(final ThreadGroup threadGroup, final String prefix) { logger.warn("Thread group: " + threadGroup); final ThreadGroup[] groups = new ThreadGroup[threadGroup.activeGroupCount() + 2]; final int groupCount = threadGroup.enumerate(groups); for (int i = 0; i < groupCount; i++) { final ThreadGroup group = groups[i]; printThreadInformation(group, prefix + " "); } final Thread[] threads = new Thread[threadGroup.activeCount() + 4]; final int threadCount = threadGroup.enumerate(threads); for (int i = 0; i < threadCount; i++) { final Thread thread = threads[i]; if (thread != null) { final boolean alive = thread.isAlive(); final boolean daemon = thread.isDaemon(); logger.warn( prefix + "thread #" + (i + 1) + " (" + (alive ? "alive" : "dead") + (daemon ? ",daemon" : "") + ")" + ": " + thread); if (alive && !daemon) { final StackTraceElement[] stackTrace = thread.getStackTrace(); for (int j = stackTrace.length - 1; j >= 0; j--) { logger.warn(prefix + " | stack " + (j + 1) + ": " + stackTrace[j]); } } } } } @Override public void exit(final int statusCode) { final Thread thread = new Thread() { @Override public void run() { try { // sleep for 5 seconds, to give the non-daemon threads a // chance to shut down the applications properly Thread.sleep(5000); } catch (final InterruptedException e) { logger.info("Interrupted", e); } if (logger.isWarnEnabled()) { logger.warn("Some threads are still running:"); ThreadGroup topLevelThreadGroup = null; { ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); while (threadGroup != null) { topLevelThreadGroup = threadGroup; threadGroup = threadGroup.getParent(); } } printThreadInformation(topLevelThreadGroup, ""); logger.warn("Invoking system.exit({})", statusCode); } System.exit(statusCode); } }; thread.setDaemon(true); logger.info("Scheduling shutdown thread"); thread.start(); } }