001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.main; 029 030import java.lang.reflect.Method; 031import java.sql.Driver; 032import java.sql.DriverManager; 033import java.util.Enumeration; 034 035import javax.servlet.ServletContextEvent; 036import javax.servlet.ServletContextListener; 037import javax.servlet.http.HttpSessionEvent; 038import javax.servlet.http.HttpSessionListener; 039 040import org.apache.commons.logging.Log; 041 042/** 043 * Provides the OpenCms system with information from the servlet context.<p> 044 * 045 * Used for the following purposes:<ul> 046 * <li>Starting up OpenCms when the servlet container is started.</li> 047 * <li>Shutting down OpenCms when the servlet container is shut down.</li> 048 * <li>Informing the <code>{@link org.opencms.main.CmsSessionManager}</code> if a new session is created.</li> 049 * <li>Informing the <code>{@link org.opencms.main.CmsSessionManager}</code> session is destroyed or invalidated.</li> 050 * </ul> 051 * 052 * @since 6.0.0 053 */ 054public class OpenCmsListener implements ServletContextListener, HttpSessionListener { 055 056 /** The log object for this class. */ 057 private static final Log LOG = CmsLog.getLog(OpenCmsListener.class); 058 059 /** 060 * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) 061 */ 062 public void contextDestroyed(ServletContextEvent event) { 063 064 try { 065 // destroy the OpenCms instance 066 OpenCmsCore.getInstance().shutDown(); 067 shutDownSqlDrivers(); 068 } catch (CmsInitException e) { 069 if (e.isNewError()) { 070 LOG.error(e.getLocalizedMessage(), e); 071 } 072 } catch (Throwable t) { 073 // make sure all other errors are displayed in the OpenCms log 074 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERROR_GENERIC_0), t); 075 } 076 } 077 078 /** 079 * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) 080 */ 081 public void contextInitialized(ServletContextEvent event) { 082 083 String basePath = event.getServletContext().getRealPath("/"); 084 String path = basePath + "/WEB-INF/logs/startup-stacktraces.zip"; 085 String summaryPath = basePath + "/WEB-INF/logs/startup-summary.xml"; 086 CmsSingleThreadDumperThread dumpThread = new CmsSingleThreadDumperThread( 087 path, 088 summaryPath, 089 Thread.currentThread().getId()); 090 boolean enableThreadDumps = "true".equalsIgnoreCase(System.getProperty("opencms.profile.startup.stacktraces")); 091 try { 092 if (enableThreadDumps) { 093 dumpThread.start(); 094 } 095 // upgrade the OpenCms runlevel 096 OpenCmsCore.getInstance().upgradeRunlevel(event.getServletContext()); 097 } catch (CmsInitException e) { 098 if (e.isNewError()) { 099 // only log new init errors 100 LOG.error(e.getLocalizedMessage(), e); 101 } 102 } catch (Throwable t) { 103 // make sure all other errors are displayed in the OpenCms log 104 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERROR_GENERIC_0), t); 105 // throw a new init Exception to make sure a "context destroyed" event is triggered 106 throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_GENERIC_1, t.getMessage())); 107 } finally { 108 // Signal the thread to finish its business. 109 // This doesn't do anything if the thread isn't running. 110 dumpThread.interrupt(); 111 } 112 } 113 114 /** 115 * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent) 116 */ 117 public void sessionCreated(HttpSessionEvent event) { 118 119 try { 120 // inform the OpenCms session manager 121 OpenCmsCore.getInstance().getSessionManager().sessionCreated(event); 122 } catch (CmsInitException e) { 123 if (e.isNewError()) { 124 LOG.error(e.getLocalizedMessage(), e); 125 } 126 } catch (Throwable t) { 127 // make sure all other errors are displayed in the OpenCms log 128 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERROR_GENERIC_0), t); 129 } 130 } 131 132 /** 133 * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) 134 */ 135 public void sessionDestroyed(HttpSessionEvent event) { 136 137 try { 138 // inform the OpenCms session manager 139 OpenCmsCore.getInstance().getSessionManager().sessionDestroyed(event); 140 } catch (CmsInitException e) { 141 if (e.isNewError()) { 142 LOG.error(e.getLocalizedMessage(), e); 143 } 144 } catch (Throwable t) { 145 // make sure all other errors are displayed in the OpenCms log 146 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERROR_GENERIC_0), t); 147 } 148 } 149 150 /** 151 * De-registers the SQL drivers in order to prevent potential memory leaks.<p> 152 */ 153 private void shutDownSqlDrivers() { 154 155 // This manually deregisters JDBC driver, which prevents Tomcat 7 from complaining about memory leaks 156 Enumeration<Driver> drivers = DriverManager.getDrivers(); 157 while (drivers.hasMoreElements()) { 158 Driver driver = drivers.nextElement(); 159 try { 160 DriverManager.deregisterDriver(driver); 161 } catch (Throwable e) { 162 System.out.println( 163 Messages.get().getBundle().key( 164 Messages.ERR_DEREGISTERING_JDBC_DRIVER_1, 165 driver.getClass().getName())); 166 e.printStackTrace(System.out); 167 } 168 } 169 170 try { 171 Class<?> cls = Class.forName("com.mysql.jdbc.AbandonedConnectionCleanupThread"); 172 Method shutdownMethod = (cls == null ? null : cls.getMethod("shutdown")); 173 if (shutdownMethod != null) { 174 shutdownMethod.invoke(null); 175 } 176 } catch (Throwable e) { 177 System.out.println("Failed to shutdown MySQL connection cleanup thread: " + e.getMessage()); 178 } 179 } 180}