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