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.im.AIMConnector;
020    import com.liferay.portal.im.ICQConnector;
021    import com.liferay.portal.im.MSNConnector;
022    import com.liferay.portal.im.YMConnector;
023    import com.liferay.portal.jcr.JCRFactoryUtil;
024    import com.liferay.portal.kernel.dao.db.DB;
025    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
026    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
027    import com.liferay.portal.kernel.deploy.auto.AutoDeployDir;
028    import com.liferay.portal.kernel.deploy.auto.AutoDeployUtil;
029    import com.liferay.portal.kernel.deploy.hot.HotDeployUtil;
030    import com.liferay.portal.kernel.deploy.sandbox.SandboxDeployDir;
031    import com.liferay.portal.kernel.deploy.sandbox.SandboxDeployUtil;
032    import com.liferay.portal.kernel.events.SimpleAction;
033    import com.liferay.portal.kernel.executor.PortalExecutorManagerUtil;
034    import com.liferay.portal.kernel.javadoc.JavadocManagerUtil;
035    import com.liferay.portal.kernel.log.Jdk14LogFactoryImpl;
036    import com.liferay.portal.kernel.log.Log;
037    import com.liferay.portal.kernel.log.LogFactoryUtil;
038    import com.liferay.portal.kernel.messaging.MessageBusUtil;
039    import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
040    import com.liferay.portal.kernel.scheduler.SchedulerEngineHelperUtil;
041    import com.liferay.portal.kernel.util.CentralizedThreadLocal;
042    import com.liferay.portal.kernel.util.GetterUtil;
043    import com.liferay.portal.kernel.util.PropsKeys;
044    import com.liferay.portal.kernel.util.StringPool;
045    import com.liferay.portal.util.PropsUtil;
046    import com.liferay.portal.util.PropsValues;
047    import com.liferay.portal.zip.TrueZIPHelperUtil;
048    import com.liferay.portlet.documentlibrary.util.DocumentConversionUtil;
049    import com.liferay.util.ThirdPartyThreadLocalRegistry;
050    
051    import java.sql.Connection;
052    import java.sql.Statement;
053    
054    import java.util.concurrent.Future;
055    import java.util.concurrent.TimeUnit;
056    
057    /**
058     * @author Brian Wing Shun Chan
059     */
060    public class GlobalShutdownAction extends SimpleAction {
061    
062            @Override
063            public void run(String[] ids) {
064    
065                    // Lower shutdown levels have dependences on higher levels, therefore
066                    // lower ones need to shutdown before higher ones. Components within the
067                    // same shutdown level should not depend on each other.
068    
069                    shutdownLevel1();
070                    shutdownLevel2();
071                    shutdownLevel3();
072                    shutdownLevel4();
073                    shutdownLevel5();
074                    shutdownLevel6();
075                    shutdownLevel7();
076            }
077    
078            protected ThreadGroup getThreadGroup() {
079                    Thread currentThread = Thread.currentThread();
080    
081                    ThreadGroup threadGroup = currentThread.getThreadGroup();
082    
083                    for (int i = 0; i < 10; i++) {
084                            if (threadGroup.getParent() == null) {
085                                    break;
086                            }
087                            else {
088                                    threadGroup = threadGroup.getParent();
089                            }
090                    }
091    
092                    return threadGroup;
093            }
094    
095            protected Thread[] getThreads(ThreadGroup threadGroup) {
096                    Thread[] threads = new Thread[threadGroup.activeCount() * 2];
097    
098                    threadGroup.enumerate(threads);
099    
100                    return threads;
101            }
102    
103            protected void shutdownLevel1() {
104    
105                    // Instant messenger AIM
106    
107                    try {
108                            if (_log.isDebugEnabled()) {
109                                    _log.debug("Shutting down AIM");
110                            }
111    
112                            AIMConnector.disconnect();
113                    }
114                    catch (Exception e) {
115                    }
116    
117                    // Instant messenger ICQ
118    
119                    try {
120                            if (_log.isDebugEnabled()) {
121                                    _log.debug("Shutting down ICQ");
122                            }
123    
124                            ICQConnector.disconnect();
125                    }
126                    catch (Exception e) {
127                    }
128    
129                    // Instant messenger MSN
130    
131                    try {
132                            if (_log.isDebugEnabled()) {
133                                    _log.debug("Shutting down MSN");
134                            }
135    
136                            MSNConnector.disconnect();
137                    }
138                    catch (Exception e) {
139                    }
140    
141                    // Instant messenger YM
142    
143                    try {
144                            if (_log.isDebugEnabled()) {
145                                    _log.debug("Shutting down YM");
146                            }
147    
148                            YMConnector.disconnect();
149                    }
150                    catch (Exception e) {
151                    }
152    
153                    // Javadoc
154    
155                    JavadocManagerUtil.unload(StringPool.BLANK);
156    
157                    // JCR
158    
159                    try {
160                            if (_log.isDebugEnabled()) {
161                                    _log.debug("Shutting down JCR");
162                            }
163    
164                            JCRFactoryUtil.shutdown();
165                    }
166                    catch (Exception e) {
167                    }
168    
169                    // OpenOffice
170    
171                    DocumentConversionUtil.disconnect();
172    
173                    // Plugins
174    
175                    RequiredPluginsUtil.stopCheckingRequiredPlugins();
176    
177                    // Scheduler engine
178    
179                    try {
180                            SchedulerEngineHelperUtil.shutdown();
181                    }
182                    catch (Exception e) {
183                    }
184    
185                    // Wait 1 second so Quartz threads can cleanly shutdown
186    
187                    try {
188                            Thread.sleep(1000);
189                    }
190                    catch (Exception e) {
191                            e.printStackTrace();
192                    }
193            }
194    
195            protected void shutdownLevel2() {
196    
197                    // Auto deploy
198    
199                    AutoDeployUtil.unregisterDir(AutoDeployDir.DEFAULT_NAME);
200    
201                    // Hot deploy
202    
203                    HotDeployUtil.unregisterListeners();
204    
205                    // Sandbox deploy
206    
207                    SandboxDeployUtil.unregisterDir(SandboxDeployDir.DEFAULT_NAME);
208            }
209    
210            protected void shutdownLevel3() {
211    
212                    // Messaging
213    
214                    MessageBusUtil.shutdown(true);
215    
216                    // Portal fabric
217    
218                    if (PropsValues.PORTAL_FABRIC_ENABLED) {
219                            try {
220                                    Future<?> future = FabricServerUtil.stop();
221    
222                                    future.get(
223                                            PropsValues.PORTAL_FABRIC_SHUTDOWN_TIMEOUT,
224                                            TimeUnit.MILLISECONDS);
225                            }
226                            catch (Exception e) {
227                                    _log.error("Unable to stop fabric server", e);
228                            }
229                    }
230            }
231    
232            protected void shutdownLevel4() {
233    
234                    // Hypersonic
235    
236                    DB db = DBFactoryUtil.getDB();
237    
238                    String dbType = db.getType();
239    
240                    if (dbType.equals(DB.TYPE_HYPERSONIC)) {
241                            Connection connection = null;
242                            Statement statement = null;
243    
244                            try {
245                                    connection = DataAccess.getConnection();
246    
247                                    statement = connection.createStatement();
248    
249                                    statement.executeUpdate("SHUTDOWN");
250                            }
251                            catch (Exception e) {
252                                    _log.error(e, e);
253                            }
254                            finally {
255                                    DataAccess.cleanUp(connection, statement);
256                            }
257                    }
258    
259                    // Portal Resiliency
260    
261                    MPIHelperUtil.shutdown();
262            }
263    
264            protected void shutdownLevel5() {
265    
266                    // Portal executors
267    
268                    PortalExecutorManagerUtil.shutdown(true);
269    
270                    // TrueZip
271    
272                    TrueZIPHelperUtil.shutdown();
273            }
274    
275            protected void shutdownLevel6() {
276    
277                    // Reset log to default JDK 1.4 logger. This will allow WARs dependent
278                    // on the portal to still log events after the portal WAR has been
279                    // destroyed.
280    
281                    try {
282                            LogFactoryUtil.setLogFactory(new Jdk14LogFactoryImpl());
283                    }
284                    catch (Exception e) {
285                    }
286    
287                    // Thread local registry
288    
289                    ThirdPartyThreadLocalRegistry.resetThreadLocals();
290                    CentralizedThreadLocal.clearShortLivedThreadLocals();
291            }
292    
293            protected void shutdownLevel7() {
294    
295                    // Programmatically exit
296    
297                    if (GetterUtil.getBoolean(
298                                    PropsUtil.get(PropsKeys.SHUTDOWN_PROGRAMMATICALLY_EXIT))) {
299    
300                            Thread currentThread = Thread.currentThread();
301    
302                            ThreadGroup threadGroup = getThreadGroup();
303    
304                            Thread[] threads = getThreads(threadGroup);
305    
306                            for (Thread thread : threads) {
307                                    if ((thread == null) || (thread == currentThread)) {
308                                            continue;
309                                    }
310    
311                                    try {
312                                            thread.interrupt();
313                                    }
314                                    catch (Exception e) {
315                                    }
316                            }
317    
318                            threadGroup.destroy();
319                    }
320            }
321    
322            private static final Log _log = LogFactoryUtil.getLog(
323                    GlobalShutdownAction.class);
324    
325    }