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