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.deploy.hot;
016    
017    import com.liferay.portal.kernel.deploy.hot.HotDeploy;
018    import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
019    import com.liferay.portal.kernel.deploy.hot.HotDeployException;
020    import com.liferay.portal.kernel.deploy.hot.HotDeployListener;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.portlet.PortletClassLoaderUtil;
024    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
025    import com.liferay.portal.kernel.servlet.ServletContextPool;
026    import com.liferay.portal.kernel.template.TemplateManagerUtil;
027    import com.liferay.portal.kernel.util.BasePortalLifecycle;
028    import com.liferay.portal.kernel.util.HttpUtil;
029    import com.liferay.portal.kernel.util.PortalLifecycle;
030    import com.liferay.portal.kernel.util.PortalLifecycleUtil;
031    import com.liferay.portal.kernel.util.PropertiesUtil;
032    import com.liferay.portal.kernel.util.StringBundler;
033    import com.liferay.portal.kernel.util.StringUtil;
034    import com.liferay.portal.util.ClassLoaderUtil;
035    
036    import java.util.ArrayList;
037    import java.util.Collections;
038    import java.util.HashSet;
039    import java.util.List;
040    import java.util.Properties;
041    import java.util.Set;
042    
043    import javax.servlet.ServletContext;
044    
045    /**
046     * @author Ivica Cardic
047     * @author Brian Wing Shun Chan
048     * @author Raymond Aug??
049     */
050    @DoPrivileged
051    public class HotDeployImpl implements HotDeploy {
052    
053            public HotDeployImpl() {
054                    if (_log.isDebugEnabled()) {
055                            _log.debug("Initializing hot deploy manager " + this.hashCode());
056                    }
057    
058                    _dependentHotDeployEvents = new ArrayList<HotDeployEvent>();
059                    _deployedServletContextNames = new HashSet<String>();
060                    _hotDeployListeners = new ArrayList<HotDeployListener>();
061            }
062    
063            @Override
064            public synchronized void fireDeployEvent(
065                    final HotDeployEvent hotDeployEvent) {
066    
067                    PortalLifecycleUtil.register(
068                            new HotDeployPortalLifecycle(hotDeployEvent),
069                            PortalLifecycle.METHOD_INIT);
070    
071                    if (_capturePrematureEvents) {
072    
073                            // Capture events that are fired before the portal initialized
074    
075                            PortalLifecycle portalLifecycle = new BasePortalLifecycle() {
076    
077                                    @Override
078                                    protected void doPortalDestroy() {
079                                    }
080    
081                                    @Override
082                                    protected void doPortalInit() {
083                                            fireDeployEvent(hotDeployEvent);
084                                    }
085    
086                            };
087    
088                            PortalLifecycleUtil.register(
089                                    portalLifecycle, PortalLifecycle.METHOD_INIT);
090                    }
091                    else {
092    
093                            // Fire event
094    
095                            doFireDeployEvent(hotDeployEvent);
096                    }
097            }
098    
099            @Override
100            public synchronized void fireUndeployEvent(HotDeployEvent hotDeployEvent) {
101                    for (int i = _hotDeployListeners.size() - 1; i >= 0; i--) {
102                            HotDeployListener hotDeployListener = _hotDeployListeners.get(i);
103    
104                            try {
105                                    PortletClassLoaderUtil.setClassLoader(
106                                            hotDeployEvent.getContextClassLoader());
107                                    PortletClassLoaderUtil.setServletContextName(
108                                            hotDeployEvent.getServletContextName());
109    
110                                    hotDeployListener.invokeUndeploy(hotDeployEvent);
111                            }
112                            catch (HotDeployException hde) {
113                                    _log.error(hde, hde);
114                            }
115                            finally {
116                                    PortletClassLoaderUtil.setClassLoader(null);
117                                    PortletClassLoaderUtil.setServletContextName(null);
118                            }
119                    }
120    
121                    _deployedServletContextNames.remove(
122                            hotDeployEvent.getServletContextName());
123    
124                    ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
125    
126                    TemplateManagerUtil.destroy(classLoader);
127    
128                    _pacl.unregister(classLoader);
129            }
130    
131            @Override
132            public synchronized void registerListener(
133                    HotDeployListener hotDeployListener) {
134    
135                    _hotDeployListeners.add(hotDeployListener);
136            }
137    
138            @Override
139            public synchronized void reset() {
140                    _capturePrematureEvents = true;
141                    _dependentHotDeployEvents.clear();
142                    _deployedServletContextNames.clear();
143                    _hotDeployListeners.clear();
144            }
145    
146            @Override
147            public synchronized void setCapturePrematureEvents(
148                    boolean capturePrematureEvents) {
149    
150                    _capturePrematureEvents = capturePrematureEvents;
151            }
152    
153            @Override
154            public synchronized void unregisterListener(
155                    HotDeployListener hotDeployListener) {
156    
157                    _hotDeployListeners.remove(hotDeployListener);
158            }
159    
160            @Override
161            public synchronized void unregisterListeners() {
162                    _hotDeployListeners.clear();
163            }
164    
165            public static interface PACL {
166    
167                    public void initPolicy(
168                            String servletContextName, ClassLoader classLoader,
169                            Properties properties);
170    
171                    public void unregister(ClassLoader classLoader);
172    
173            }
174    
175            protected void doFireDeployEvent(HotDeployEvent hotDeployEvent) {
176                    String servletContextName = hotDeployEvent.getServletContextName();
177    
178                    if (_deployedServletContextNames.contains(servletContextName)) {
179                            return;
180                    }
181    
182                    boolean hasDependencies = true;
183    
184                    for (String dependentServletContextName :
185                                    hotDeployEvent.getDependentServletContextNames()) {
186    
187                            if (!_deployedServletContextNames.contains(
188                                            dependentServletContextName)) {
189    
190                                    hasDependencies = false;
191    
192                                    break;
193                            }
194                    }
195    
196                    if (hasDependencies) {
197                            if (_log.isInfoEnabled()) {
198                                    _log.info("Deploying " + servletContextName + " from queue");
199                            }
200    
201                            for (HotDeployListener hotDeployListener : _hotDeployListeners) {
202                                    try {
203                                            PortletClassLoaderUtil.setClassLoader(
204                                                    hotDeployEvent.getContextClassLoader());
205                                            PortletClassLoaderUtil.setServletContextName(
206                                                    hotDeployEvent.getServletContextName());
207    
208                                            hotDeployListener.invokeDeploy(hotDeployEvent);
209                                    }
210                                    catch (HotDeployException hde) {
211                                            _log.error(hde, hde);
212                                    }
213                                    finally {
214                                            PortletClassLoaderUtil.setClassLoader(null);
215                                            PortletClassLoaderUtil.setServletContextName(null);
216                                    }
217                            }
218    
219                            _deployedServletContextNames.add(servletContextName);
220    
221                            _dependentHotDeployEvents.remove(hotDeployEvent);
222    
223                            ClassLoader contextClassLoader = getContextClassLoader();
224    
225                            try {
226                                    setContextClassLoader(ClassLoaderUtil.getPortalClassLoader());
227    
228                                    List<HotDeployEvent> dependentEvents =
229                                            new ArrayList<HotDeployEvent>(_dependentHotDeployEvents);
230    
231                                    for (HotDeployEvent dependentEvent : dependentEvents) {
232                                            setContextClassLoader(
233                                                    dependentEvent.getContextClassLoader());
234    
235                                            doFireDeployEvent(dependentEvent);
236                                    }
237                            }
238                            finally {
239                                    setContextClassLoader(contextClassLoader);
240                            }
241                    }
242                    else {
243                            if (!_dependentHotDeployEvents.contains(hotDeployEvent)) {
244                                    if (_log.isInfoEnabled()) {
245                                            StringBundler sb = new StringBundler(4);
246    
247                                            sb.append("Queueing ");
248                                            sb.append(servletContextName);
249                                            sb.append(" for deploy because it is missing ");
250                                            sb.append(getRequiredServletContextNames(hotDeployEvent));
251    
252                                            _log.info(sb.toString());
253                                    }
254    
255                                    _dependentHotDeployEvents.add(hotDeployEvent);
256                            }
257                            else {
258                                    if (_log.isInfoEnabled()) {
259                                            for (HotDeployEvent dependentHotDeployEvent :
260                                                            _dependentHotDeployEvents) {
261    
262                                                    StringBundler sb = new StringBundler(3);
263    
264                                                    sb.append(servletContextName);
265                                                    sb.append(" is still in queue because it is missing ");
266                                                    sb.append(
267                                                            getRequiredServletContextNames(
268                                                                    dependentHotDeployEvent));
269    
270                                                    _log.info(sb.toString());
271                                            }
272                                    }
273                            }
274                    }
275            }
276    
277            protected ClassLoader getContextClassLoader() {
278                    return ClassLoaderUtil.getContextClassLoader();
279            }
280    
281            protected String getRequiredServletContextNames(
282                    HotDeployEvent hotDeployEvent) {
283    
284                    List<String> requiredServletContextNames = new ArrayList<String>();
285    
286                    for (String dependentServletContextName :
287                                    hotDeployEvent.getDependentServletContextNames()) {
288    
289                            if (!_deployedServletContextNames.contains(
290                                            dependentServletContextName)) {
291    
292                                    requiredServletContextNames.add(dependentServletContextName);
293                            }
294                    }
295    
296                    Collections.sort(requiredServletContextNames);
297    
298                    return StringUtil.merge(requiredServletContextNames, ", ");
299            }
300    
301            protected void setContextClassLoader(ClassLoader contextClassLoader) {
302                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
303            }
304    
305            private static Log _log = LogFactoryUtil.getLog(HotDeployImpl.class);
306    
307            private static PACL _pacl = new NoPACL();
308    
309            private boolean _capturePrematureEvents = true;
310            private final List<HotDeployEvent> _dependentHotDeployEvents;
311            private final Set<String> _deployedServletContextNames;
312            private final List<HotDeployListener> _hotDeployListeners;
313    
314            private static class NoPACL implements PACL {
315    
316                    @Override
317                    public void initPolicy(
318                            String servletContextName, ClassLoader classLoader,
319                            Properties properties) {
320                    }
321    
322                    @Override
323                    public void unregister(ClassLoader classLoader) {
324                    }
325    
326            }
327    
328            private class HotDeployPortalLifecycle extends BasePortalLifecycle {
329    
330                    public HotDeployPortalLifecycle(HotDeployEvent hotDeployEvent) {
331                            _servletContext = hotDeployEvent.getServletContext();
332                            _classLoader = hotDeployEvent.getContextClassLoader();
333    
334                            ServletContextPool.put(
335                                    _servletContext.getServletContextName(), _servletContext);
336                    }
337    
338                    @Override
339                    protected void doPortalDestroy() {
340                    }
341    
342                    @Override
343                    protected void doPortalInit() throws Exception {
344                            Properties properties = null;
345    
346                            String propertiesString = HttpUtil.URLtoString(
347                                    _servletContext.getResource(
348                                            "/WEB-INF/liferay-plugin-package.properties"));
349    
350                            if (propertiesString != null) {
351                                    properties = PropertiesUtil.load(propertiesString);
352                            }
353                            else {
354                                    properties = new Properties();
355                            }
356    
357                            _pacl.initPolicy(
358                                    _servletContext.getServletContextName(), _classLoader,
359                                    properties);
360                    }
361    
362                    private ClassLoader _classLoader;
363                    private ServletContext _servletContext;
364    
365            }
366    
367    }