001    /**
002     * Copyright (c) 2000-2013 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.kernel.servlet;
016    
017    import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
018    import com.liferay.portal.kernel.deploy.hot.HotDeployUtil;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.BasePortalLifecycle;
022    import com.liferay.portal.kernel.util.ClassLoaderPool;
023    
024    import javax.servlet.ServletContext;
025    import javax.servlet.ServletContextAttributeEvent;
026    import javax.servlet.ServletContextAttributeListener;
027    import javax.servlet.ServletContextEvent;
028    import javax.servlet.ServletContextListener;
029    
030    /**
031     * @author Brian Wing Shun Chan
032     */
033    public class PluginContextListener
034            extends BasePortalLifecycle
035            implements ServletContextAttributeListener, ServletContextListener {
036    
037            public static final String PLUGIN_CLASS_LOADER = "PLUGIN_CLASS_LOADER";
038    
039            @Override
040            public void attributeAdded(
041                    ServletContextAttributeEvent servletContextAttributeEvent) {
042    
043                    String name = servletContextAttributeEvent.getName();
044    
045                    if (_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER) &&
046                            (servletContextAttributeEvent.getValue() != pluginClassLoader)) {
047    
048                            if (_log.isWarnEnabled()) {
049                                    _log.warn(
050                                            "Preventing the addition of another plugin class loader");
051                            }
052    
053                            servletContext.setAttribute(PLUGIN_CLASS_LOADER, pluginClassLoader);
054                    }
055                    else if (!_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER)) {
056                            _addedPluginClassLoader = true;
057                    }
058            }
059    
060            @Override
061            public void attributeRemoved(
062                    ServletContextAttributeEvent servletContextAttributeEvent) {
063    
064                    String name = servletContextAttributeEvent.getName();
065    
066                    if (_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER)) {
067                            if (_log.isWarnEnabled()) {
068                                    _log.warn("Preventing the removal of the plugin class loader");
069                            }
070    
071                            servletContext.setAttribute(PLUGIN_CLASS_LOADER, pluginClassLoader);
072                    }
073            }
074    
075            @Override
076            public void attributeReplaced(
077                    ServletContextAttributeEvent servletContextAttributeEvent) {
078    
079                    String name = servletContextAttributeEvent.getName();
080    
081                    if (_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER)) {
082                            if (_log.isWarnEnabled()) {
083                                    _log.warn(
084                                            "Preventing the replacement of the plugin class loader");
085                            }
086    
087                            servletContext.removeAttribute(PLUGIN_CLASS_LOADER);
088                    }
089            }
090    
091            @Override
092            public void contextDestroyed(ServletContextEvent servletContextEvent) {
093                    ServletContext servletContext = servletContextEvent.getServletContext();
094    
095                    ClassLoaderPool.unregister(servletContext.getServletContextName());
096    
097                    portalDestroy();
098            }
099    
100            @Override
101            public void contextInitialized(ServletContextEvent servletContextEvent) {
102                    servletContext = servletContextEvent.getServletContext();
103    
104                    Thread currentThread = Thread.currentThread();
105    
106                    pluginClassLoader = currentThread.getContextClassLoader();
107    
108                    ClassLoaderPool.register(
109                            servletContext.getServletContextName(), pluginClassLoader);
110    
111                    servletContext.setAttribute(PLUGIN_CLASS_LOADER, pluginClassLoader);
112    
113                    ServletContextPool.put(
114                            servletContext.getServletContextName(), servletContext);
115    
116                    registerPortalLifecycle();
117            }
118    
119            @Override
120            protected void doPortalDestroy() throws Exception {
121                    PluginContextLifecycleThreadLocal.setDestroying(true);
122    
123                    Thread currentThread = Thread.currentThread();
124    
125                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
126    
127                    if (contextClassLoader != pluginClassLoader) {
128                            currentThread.setContextClassLoader(pluginClassLoader);
129                    }
130    
131                    try {
132                            fireUndeployEvent();
133                    }
134                    finally {
135                            PluginContextLifecycleThreadLocal.setDestroying(false);
136    
137                            currentThread.setContextClassLoader(contextClassLoader);
138                    }
139            }
140    
141            @Override
142            protected void doPortalInit() throws Exception {
143                    PluginContextLifecycleThreadLocal.setInitializing(true);
144    
145                    Thread currentThread = Thread.currentThread();
146    
147                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
148    
149                    if (contextClassLoader != pluginClassLoader) {
150                            currentThread.setContextClassLoader(pluginClassLoader);
151                    }
152    
153                    try {
154                            fireDeployEvent();
155                    }
156                    finally {
157                            PluginContextLifecycleThreadLocal.setInitializing(false);
158    
159                            currentThread.setContextClassLoader(contextClassLoader);
160                    }
161            }
162    
163            protected void fireDeployEvent() {
164                    HotDeployUtil.fireDeployEvent(
165                            new HotDeployEvent(servletContext, pluginClassLoader));
166            }
167    
168            protected void fireUndeployEvent() {
169                    HotDeployUtil.fireUndeployEvent(
170                            new HotDeployEvent(servletContext, pluginClassLoader));
171            }
172    
173            protected ClassLoader pluginClassLoader;
174            protected ServletContext servletContext;
175    
176            private static Log _log = LogFactoryUtil.getLog(
177                    PluginContextListener.class);
178    
179            private boolean _addedPluginClassLoader;
180    
181    }