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