001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.events;
016    
017    import com.liferay.portal.deploy.RequiredPluginsUtil;
018    import com.liferay.portal.fabric.server.FabricServerUtil;
019    import com.liferay.portal.kernel.dao.db.DB;
020    import com.liferay.portal.kernel.dao.db.DBManagerUtil;
021    import com.liferay.portal.kernel.dao.db.DBType;
022    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
023    import com.liferay.portal.kernel.deploy.auto.AutoDeployDir;
024    import com.liferay.portal.kernel.deploy.auto.AutoDeployUtil;
025    import com.liferay.portal.kernel.deploy.hot.HotDeployUtil;
026    import com.liferay.portal.kernel.deploy.sandbox.SandboxDeployDir;
027    import com.liferay.portal.kernel.deploy.sandbox.SandboxDeployUtil;
028    import com.liferay.portal.kernel.events.SimpleAction;
029    import com.liferay.portal.kernel.executor.PortalExecutorManagerUtil;
030    import com.liferay.portal.kernel.javadoc.JavadocManagerUtil;
031    import com.liferay.portal.kernel.log.Jdk14LogFactoryImpl;
032    import com.liferay.portal.kernel.log.Log;
033    import com.liferay.portal.kernel.log.LogFactoryUtil;
034    import com.liferay.portal.kernel.messaging.MessageBusUtil;
035    import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
036    import com.liferay.portal.kernel.util.CentralizedThreadLocal;
037    import com.liferay.portal.kernel.util.GetterUtil;
038    import com.liferay.portal.kernel.util.PropsKeys;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.struts.AuthPublicPathRegistry;
041    import com.liferay.portal.util.PropsUtil;
042    import com.liferay.portal.util.PropsValues;
043    import com.liferay.portal.zip.TrueZIPHelperUtil;
044    import com.liferay.portlet.documentlibrary.util.DocumentConversionUtil;
045    import com.liferay.util.ThirdPartyThreadLocalRegistry;
046    
047    import java.sql.Connection;
048    import java.sql.Statement;
049    
050    import java.util.concurrent.Future;
051    import java.util.concurrent.TimeUnit;
052    
053    /**
054     * @author Brian Wing Shun Chan
055     */
056    public class GlobalShutdownAction extends SimpleAction {
057    
058            @Override
059            public void run(String[] ids) {
060    
061                    // Lower shutdown levels have dependences on higher levels, therefore
062                    // lower ones need to shutdown before higher ones. Components within the
063                    // same shutdown level should not depend on each other.
064    
065                    shutdownLevel1();
066                    shutdownLevel2();
067                    shutdownLevel3();
068                    shutdownLevel4();
069                    shutdownLevel5();
070                    shutdownLevel6();
071                    shutdownLevel7();
072            }
073    
074            protected ThreadGroup getThreadGroup() {
075                    Thread currentThread = Thread.currentThread();
076    
077                    ThreadGroup threadGroup = currentThread.getThreadGroup();
078    
079                    for (int i = 0; i < 10; i++) {
080                            if (threadGroup.getParent() == null) {
081                                    break;
082                            }
083                            else {
084                                    threadGroup = threadGroup.getParent();
085                            }
086                    }
087    
088                    return threadGroup;
089            }
090    
091            protected Thread[] getThreads(ThreadGroup threadGroup) {
092                    Thread[] threads = new Thread[threadGroup.activeCount() * 2];
093    
094                    threadGroup.enumerate(threads);
095    
096                    return threads;
097            }
098    
099            protected void shutdownLevel1() {
100    
101                    // Authentication
102    
103                    AuthPublicPathRegistry.unregister(PropsValues.AUTH_PUBLIC_PATHS);
104    
105                    // Javadoc
106    
107                    JavadocManagerUtil.unload(StringPool.BLANK);
108    
109                    // OpenOffice
110    
111                    DocumentConversionUtil.disconnect();
112    
113                    // Plugins
114    
115                    RequiredPluginsUtil.stopCheckingRequiredPlugins();
116            }
117    
118            protected void shutdownLevel2() {
119    
120                    // Auto deploy
121    
122                    AutoDeployUtil.unregisterDir(AutoDeployDir.DEFAULT_NAME);
123    
124                    // Hot deploy
125    
126                    HotDeployUtil.unregisterListeners();
127    
128                    // Sandbox deploy
129    
130                    SandboxDeployUtil.unregisterDir(SandboxDeployDir.DEFAULT_NAME);
131            }
132    
133            protected void shutdownLevel3() {
134    
135                    // Messaging
136    
137                    MessageBusUtil.shutdown(true);
138    
139                    // Portal fabric
140    
141                    if (PropsValues.PORTAL_FABRIC_ENABLED) {
142                            try {
143                                    Future<?> future = FabricServerUtil.stop();
144    
145                                    future.get(
146                                            PropsValues.PORTAL_FABRIC_SHUTDOWN_TIMEOUT,
147                                            TimeUnit.MILLISECONDS);
148                            }
149                            catch (Exception e) {
150                                    _log.error("Unable to stop fabric server", e);
151                            }
152                    }
153            }
154    
155            protected void shutdownLevel4() {
156    
157                    // Hypersonic
158    
159                    DB db = DBManagerUtil.getDB();
160    
161                    if (db.getDBType() == DBType.HYPERSONIC) {
162                            Connection connection = null;
163                            Statement statement = null;
164    
165                            try {
166                                    connection = DataAccess.getConnection();
167    
168                                    statement = connection.createStatement();
169    
170                                    statement.executeUpdate("SHUTDOWN");
171                            }
172                            catch (Exception e) {
173                                    _log.error(e, e);
174                            }
175                            finally {
176                                    DataAccess.cleanUp(connection, statement);
177                            }
178                    }
179    
180                    // Portal Resiliency
181    
182                    MPIHelperUtil.shutdown();
183            }
184    
185            protected void shutdownLevel5() {
186    
187                    // Portal executors
188    
189                    PortalExecutorManagerUtil.shutdown(true);
190    
191                    // TrueZip
192    
193                    TrueZIPHelperUtil.shutdown();
194            }
195    
196            protected void shutdownLevel6() {
197    
198                    // Reset log to default JDK 1.4 logger. This will allow WARs dependent
199                    // on the portal to still log events after the portal WAR has been
200                    // destroyed.
201    
202                    try {
203                            LogFactoryUtil.setLogFactory(new Jdk14LogFactoryImpl());
204                    }
205                    catch (Exception e) {
206                    }
207    
208                    // Thread local registry
209    
210                    ThirdPartyThreadLocalRegistry.resetThreadLocals();
211                    CentralizedThreadLocal.clearShortLivedThreadLocals();
212            }
213    
214            protected void shutdownLevel7() {
215    
216                    // Programmatically exit
217    
218                    if (GetterUtil.getBoolean(
219                                    PropsUtil.get(PropsKeys.SHUTDOWN_PROGRAMMATICALLY_EXIT))) {
220    
221                            Thread currentThread = Thread.currentThread();
222    
223                            ThreadGroup threadGroup = getThreadGroup();
224    
225                            Thread[] threads = getThreads(threadGroup);
226    
227                            for (Thread thread : threads) {
228                                    if ((thread == null) || (thread == currentThread)) {
229                                            continue;
230                                    }
231    
232                                    try {
233                                            thread.interrupt();
234                                    }
235                                    catch (Exception e) {
236                                    }
237                            }
238    
239                            threadGroup.destroy();
240                    }
241            }
242    
243            private static final Log _log = LogFactoryUtil.getLog(
244                    GlobalShutdownAction.class);
245    
246    }