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.events.SimpleAction;
027    import com.liferay.portal.kernel.executor.PortalExecutorManagerUtil;
028    import com.liferay.portal.kernel.javadoc.JavadocManagerUtil;
029    import com.liferay.portal.kernel.log.Jdk14LogFactoryImpl;
030    import com.liferay.portal.kernel.log.Log;
031    import com.liferay.portal.kernel.log.LogFactoryUtil;
032    import com.liferay.portal.kernel.messaging.MessageBusUtil;
033    import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
034    import com.liferay.portal.kernel.util.CentralizedThreadLocal;
035    import com.liferay.portal.kernel.util.GetterUtil;
036    import com.liferay.portal.kernel.util.PropsKeys;
037    import com.liferay.portal.kernel.util.StringPool;
038    import com.liferay.portal.struts.AuthPublicPathRegistry;
039    import com.liferay.portal.util.PropsUtil;
040    import com.liferay.portal.util.PropsValues;
041    import com.liferay.portal.zip.TrueZIPHelperUtil;
042    import com.liferay.portlet.documentlibrary.util.DocumentConversionUtil;
043    import com.liferay.util.ThirdPartyThreadLocalRegistry;
044    
045    import java.sql.Connection;
046    import java.sql.Statement;
047    
048    import java.util.concurrent.Future;
049    import java.util.concurrent.TimeUnit;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     */
054    public class GlobalShutdownAction extends SimpleAction {
055    
056            @Override
057            public void run(String[] ids) {
058    
059                    // Lower shutdown levels have dependences on higher levels, therefore
060                    // lower ones need to shutdown before higher ones. Components within the
061                    // same shutdown level should not depend on each other.
062    
063                    shutdownLevel1();
064                    shutdownLevel2();
065                    shutdownLevel3();
066                    shutdownLevel4();
067                    shutdownLevel5();
068                    shutdownLevel6();
069                    shutdownLevel7();
070            }
071    
072            protected ThreadGroup getThreadGroup() {
073                    Thread currentThread = Thread.currentThread();
074    
075                    ThreadGroup threadGroup = currentThread.getThreadGroup();
076    
077                    for (int i = 0; i < 10; i++) {
078                            if (threadGroup.getParent() == null) {
079                                    break;
080                            }
081                            else {
082                                    threadGroup = threadGroup.getParent();
083                            }
084                    }
085    
086                    return threadGroup;
087            }
088    
089            protected Thread[] getThreads(ThreadGroup threadGroup) {
090                    Thread[] threads = new Thread[threadGroup.activeCount() * 2];
091    
092                    threadGroup.enumerate(threads);
093    
094                    return threads;
095            }
096    
097            protected void shutdownLevel1() {
098    
099                    // Authentication
100    
101                    AuthPublicPathRegistry.unregister(PropsValues.AUTH_PUBLIC_PATHS);
102    
103                    // Javadoc
104    
105                    JavadocManagerUtil.unload(StringPool.BLANK);
106    
107                    // OpenOffice
108    
109                    DocumentConversionUtil.disconnect();
110    
111                    // Plugins
112    
113                    RequiredPluginsUtil.stopCheckingRequiredPlugins();
114            }
115    
116            protected void shutdownLevel2() {
117    
118                    // Auto deploy
119    
120                    AutoDeployUtil.unregisterDir(AutoDeployDir.DEFAULT_NAME);
121    
122                    // Hot deploy
123    
124                    HotDeployUtil.unregisterListeners();
125            }
126    
127            protected void shutdownLevel3() {
128    
129                    // Messaging
130    
131                    MessageBusUtil.shutdown(true);
132    
133                    // Portal fabric
134    
135                    if (PropsValues.PORTAL_FABRIC_ENABLED) {
136                            try {
137                                    Future<?> future = FabricServerUtil.stop();
138    
139                                    future.get(
140                                            PropsValues.PORTAL_FABRIC_SHUTDOWN_TIMEOUT,
141                                            TimeUnit.MILLISECONDS);
142                            }
143                            catch (Exception e) {
144                                    _log.error("Unable to stop fabric server", e);
145                            }
146                    }
147            }
148    
149            protected void shutdownLevel4() {
150    
151                    // Hypersonic
152    
153                    DB db = DBManagerUtil.getDB();
154    
155                    if (db.getDBType() == DBType.HYPERSONIC) {
156                            Connection connection = null;
157                            Statement statement = null;
158    
159                            try {
160                                    connection = DataAccess.getConnection();
161    
162                                    statement = connection.createStatement();
163    
164                                    statement.executeUpdate("SHUTDOWN");
165                            }
166                            catch (Exception e) {
167                                    _log.error(e, e);
168                            }
169                            finally {
170                                    DataAccess.cleanUp(connection, statement);
171                            }
172                    }
173    
174                    // Portal Resiliency
175    
176                    MPIHelperUtil.shutdown();
177            }
178    
179            protected void shutdownLevel5() {
180    
181                    // Portal executors
182    
183                    PortalExecutorManagerUtil.shutdown(true);
184    
185                    // TrueZip
186    
187                    TrueZIPHelperUtil.shutdown();
188            }
189    
190            protected void shutdownLevel6() {
191    
192                    // Reset log to default JDK 1.4 logger. This will allow WARs dependent
193                    // on the portal to still log events after the portal WAR has been
194                    // destroyed.
195    
196                    try {
197                            LogFactoryUtil.setLogFactory(new Jdk14LogFactoryImpl());
198                    }
199                    catch (Exception e) {
200                    }
201    
202                    // Thread local registry
203    
204                    ThirdPartyThreadLocalRegistry.resetThreadLocals();
205                    CentralizedThreadLocal.clearShortLivedThreadLocals();
206            }
207    
208            protected void shutdownLevel7() {
209    
210                    // Programmatically exit
211    
212                    if (GetterUtil.getBoolean(
213                                    PropsUtil.get(PropsKeys.SHUTDOWN_PROGRAMMATICALLY_EXIT))) {
214    
215                            Thread currentThread = Thread.currentThread();
216    
217                            ThreadGroup threadGroup = getThreadGroup();
218    
219                            Thread[] threads = getThreads(threadGroup);
220    
221                            for (Thread thread : threads) {
222                                    if ((thread == null) || (thread == currentThread)) {
223                                            continue;
224                                    }
225    
226                                    try {
227                                            thread.interrupt();
228                                    }
229                                    catch (Exception e) {
230                                    }
231                            }
232    
233                            threadGroup.destroy();
234                    }
235            }
236    
237            private static final Log _log = LogFactoryUtil.getLog(
238                    GlobalShutdownAction.class);
239    
240    }