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