/** * Copyright (c) 2000-present Liferay, Inc. 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. */ package com.liferay.portal.events; import com.liferay.document.library.kernel.document.conversion.DocumentConversionUtil; import com.liferay.portal.deploy.RequiredPluginsUtil; import com.liferay.portal.fabric.server.FabricServerUtil; import com.liferay.portal.kernel.dao.db.DB; import com.liferay.portal.kernel.dao.db.DBManagerUtil; import com.liferay.portal.kernel.dao.db.DBType; import com.liferay.portal.kernel.dao.jdbc.DataAccess; import com.liferay.portal.kernel.deploy.auto.AutoDeployDir; import com.liferay.portal.kernel.deploy.auto.AutoDeployUtil; import com.liferay.portal.kernel.deploy.hot.HotDeployUtil; import com.liferay.portal.kernel.events.SimpleAction; import com.liferay.portal.kernel.executor.PortalExecutorManagerUtil; import com.liferay.portal.kernel.javadoc.JavadocManagerUtil; import com.liferay.portal.kernel.log.Jdk14LogFactoryImpl; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.messaging.MessageBusUtil; import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil; import com.liferay.portal.kernel.util.CentralizedThreadLocal; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.struts.AuthPublicPathRegistry; import com.liferay.portal.util.PropsUtil; import com.liferay.portal.util.PropsValues; import com.liferay.portal.zip.TrueZIPHelperUtil; import com.liferay.util.ThirdPartyThreadLocalRegistry; import java.sql.Connection; import java.sql.Statement; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * @author Brian Wing Shun Chan */ public class GlobalShutdownAction extends SimpleAction { @Override public void run(String[] ids) { // Lower shutdown levels have dependences on higher levels, therefore // lower ones need to shutdown before higher ones. Components within the // same shutdown level should not depend on each other. shutdownLevel1(); shutdownLevel2(); shutdownLevel3(); shutdownLevel4(); shutdownLevel5(); shutdownLevel6(); shutdownLevel7(); } protected ThreadGroup getThreadGroup() { Thread currentThread = Thread.currentThread(); ThreadGroup threadGroup = currentThread.getThreadGroup(); for (int i = 0; i < 10; i++) { if (threadGroup.getParent() == null) { break; } else { threadGroup = threadGroup.getParent(); } } return threadGroup; } protected Thread[] getThreads(ThreadGroup threadGroup) { Thread[] threads = new Thread[threadGroup.activeCount() * 2]; threadGroup.enumerate(threads); return threads; } protected void shutdownLevel1() { // Authentication AuthPublicPathRegistry.unregister(PropsValues.AUTH_PUBLIC_PATHS); // Javadoc JavadocManagerUtil.unload(StringPool.BLANK); // OpenOffice DocumentConversionUtil.disconnect(); // Plugins RequiredPluginsUtil.stopCheckingRequiredPlugins(); } protected void shutdownLevel2() { // Auto deploy AutoDeployUtil.unregisterDir(AutoDeployDir.DEFAULT_NAME); // Hot deploy HotDeployUtil.unregisterListeners(); } protected void shutdownLevel3() { // Messaging MessageBusUtil.shutdown(true); // Portal fabric if (PropsValues.PORTAL_FABRIC_ENABLED) { try { Future<?> future = FabricServerUtil.stop(); future.get( PropsValues.PORTAL_FABRIC_SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS); } catch (Exception e) { _log.error("Unable to stop fabric server", e); } } } protected void shutdownLevel4() { // Hypersonic DB db = DBManagerUtil.getDB(); if (db.getDBType() == DBType.HYPERSONIC) { Connection connection = null; Statement statement = null; try { connection = DataAccess.getConnection(); statement = connection.createStatement(); statement.executeUpdate("SHUTDOWN"); } catch (Exception e) { _log.error(e, e); } finally { DataAccess.cleanUp(connection, statement); } } // Portal Resiliency MPIHelperUtil.shutdown(); } protected void shutdownLevel5() { // Portal executors PortalExecutorManagerUtil.shutdown(true); // TrueZip TrueZIPHelperUtil.shutdown(); } protected void shutdownLevel6() { // Reset log to default JDK 1.4 logger. This will allow WARs dependent // on the portal to still log events after the portal WAR has been // destroyed. try { LogFactoryUtil.setLogFactory(new Jdk14LogFactoryImpl()); } catch (Exception e) { } // Thread local registry ThirdPartyThreadLocalRegistry.resetThreadLocals(); CentralizedThreadLocal.clearShortLivedThreadLocals(); } protected void shutdownLevel7() { // Programmatically exit if (GetterUtil.getBoolean( PropsUtil.get(PropsKeys.SHUTDOWN_PROGRAMMATICALLY_EXIT))) { Thread currentThread = Thread.currentThread(); ThreadGroup threadGroup = getThreadGroup(); Thread[] threads = getThreads(threadGroup); for (Thread thread : threads) { if ((thread == null) || (thread == currentThread)) { continue; } try { thread.interrupt(); } catch (Exception e) { } } threadGroup.destroy(); } } private static final Log _log = LogFactoryUtil.getLog( GlobalShutdownAction.class); }