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            public void attributeAdded(
040                    ServletContextAttributeEvent servletContextAttributeEvent) {
041    
042                    String name = servletContextAttributeEvent.getName();
043    
044                    if (_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER) &&
045                            (servletContextAttributeEvent.getValue() != pluginClassLoader)) {
046    
047                            if (_log.isWarnEnabled()) {
048                                    _log.warn(
049                                            "Preventing the addition of another plugin class loader");
050                            }
051    
052                            servletContext.setAttribute(PLUGIN_CLASS_LOADER, pluginClassLoader);
053                    }
054                    else if (!_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER)) {
055                            _addedPluginClassLoader = true;
056                    }
057            }
058    
059            public void attributeRemoved(
060                    ServletContextAttributeEvent servletContextAttributeEvent) {
061    
062                    String name = servletContextAttributeEvent.getName();
063    
064                    if (_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER)) {
065                            if (_log.isWarnEnabled()) {
066                                    _log.warn("Preventing the removal of the plugin class loader");
067                            }
068    
069                            servletContext.setAttribute(PLUGIN_CLASS_LOADER, pluginClassLoader);
070                    }
071            }
072    
073            public void attributeReplaced(
074                    ServletContextAttributeEvent servletContextAttributeEvent) {
075    
076                    String name = servletContextAttributeEvent.getName();
077    
078                    if (_addedPluginClassLoader && name.equals(PLUGIN_CLASS_LOADER)) {
079                            if (_log.isWarnEnabled()) {
080                                    _log.warn(
081                                            "Preventing the replacement of the plugin class loader");
082                            }
083    
084                            servletContext.removeAttribute(PLUGIN_CLASS_LOADER);
085                    }
086            }
087    
088            public void contextDestroyed(ServletContextEvent servletContextEvent) {
089                    ServletContext servletContext = servletContextEvent.getServletContext();
090    
091                    ClassLoaderPool.unregister(servletContext.getServletContextName());
092    
093                    portalDestroy();
094            }
095    
096            public void contextInitialized(ServletContextEvent servletContextEvent) {
097                    servletContext = servletContextEvent.getServletContext();
098    
099                    Thread currentThread = Thread.currentThread();
100    
101                    pluginClassLoader = currentThread.getContextClassLoader();
102    
103                    ClassLoaderPool.register(
104                            servletContext.getServletContextName(), pluginClassLoader);
105    
106                    servletContext.setAttribute(PLUGIN_CLASS_LOADER, pluginClassLoader);
107    
108                    ServletContextPool.put(
109                            servletContext.getServletContextName(), servletContext);
110    
111                    registerPortalLifecycle();
112            }
113    
114            @Override
115            protected void doPortalDestroy() throws Exception {
116                    PluginContextLifecycleThreadLocal.setDestroying(true);
117    
118                    Thread currentThread = Thread.currentThread();
119    
120                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
121    
122                    if (contextClassLoader != pluginClassLoader) {
123                            currentThread.setContextClassLoader(pluginClassLoader);
124                    }
125    
126                    try {
127                            fireUndeployEvent();
128                    }
129                    finally {
130                            PluginContextLifecycleThreadLocal.setDestroying(false);
131    
132                            currentThread.setContextClassLoader(contextClassLoader);
133                    }
134            }
135    
136            @Override
137            protected void doPortalInit() throws Exception {
138                    PluginContextLifecycleThreadLocal.setInitializing(true);
139    
140                    Thread currentThread = Thread.currentThread();
141    
142                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
143    
144                    if (contextClassLoader != pluginClassLoader) {
145                            currentThread.setContextClassLoader(pluginClassLoader);
146                    }
147    
148                    try {
149                            fireDeployEvent();
150                    }
151                    finally {
152                            PluginContextLifecycleThreadLocal.setInitializing(false);
153    
154                            currentThread.setContextClassLoader(contextClassLoader);
155                    }
156            }
157    
158            protected void fireDeployEvent() {
159                    HotDeployUtil.fireDeployEvent(
160                            new HotDeployEvent(servletContext, pluginClassLoader));
161            }
162    
163            protected void fireUndeployEvent() {
164                    HotDeployUtil.fireUndeployEvent(
165                            new HotDeployEvent(servletContext, pluginClassLoader));
166            }
167    
168            protected ClassLoader pluginClassLoader;
169            protected ServletContext servletContext;
170    
171            private static Log _log = LogFactoryUtil.getLog(
172                    PluginContextListener.class);
173    
174            private boolean _addedPluginClassLoader;
175    
176    }