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