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.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.servlet.ServletContextPool;
025    import com.liferay.portal.kernel.template.TemplateManagerUtil;
026    import com.liferay.portal.kernel.util.BasePortalLifecycle;
027    import com.liferay.portal.kernel.util.HttpUtil;
028    import com.liferay.portal.kernel.util.PortalLifecycle;
029    import com.liferay.portal.kernel.util.PortalLifecycleUtil;
030    import com.liferay.portal.kernel.util.PropertiesUtil;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
034    import com.liferay.portal.security.pacl.PACLPolicy;
035    import com.liferay.portal.security.pacl.PACLPolicyManager;
036    
037    import java.util.ArrayList;
038    import java.util.Collections;
039    import java.util.HashSet;
040    import java.util.List;
041    import java.util.Properties;
042    import java.util.Set;
043    import java.util.concurrent.CopyOnWriteArrayList;
044    
045    import javax.servlet.ServletContext;
046    
047    /**
048     * @author Ivica Cardic
049     * @author Brian Wing Shun Chan
050     * @author Raymond Augé
051     */
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            public synchronized void fireDeployEvent(
065                    final HotDeployEvent hotDeployEvent) {
066    
067                    PortalLifecycleUtil.register(
068                            new PACLPortalLifecycle(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            public synchronized void fireUndeployEvent(HotDeployEvent hotDeployEvent) {
100                    for (HotDeployListener hotDeployListener : _hotDeployListeners) {
101                            try {
102                                    PortletClassLoaderUtil.setClassLoader(
103                                            hotDeployEvent.getContextClassLoader());
104                                    PortletClassLoaderUtil.setServletContextName(
105                                            hotDeployEvent.getServletContextName());
106    
107                                    hotDeployListener.invokeUndeploy(hotDeployEvent);
108                            }
109                            catch (HotDeployException hde) {
110                                    _log.error(hde, hde);
111                            }
112                            finally {
113                                    PortletClassLoaderUtil.setClassLoader(null);
114                                    PortletClassLoaderUtil.setServletContextName(null);
115                            }
116                    }
117    
118                    _deployedServletContextNames.remove(
119                            hotDeployEvent.getServletContextName());
120    
121                    ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
122    
123                    TemplateManagerUtil.destroy(classLoader);
124    
125                    PACLPolicyManager.unregister(classLoader);
126            }
127    
128            public void registerListener(HotDeployListener hotDeployListener) {
129                    _hotDeployListeners.add(hotDeployListener);
130            }
131    
132            public synchronized void reset() {
133                    _capturePrematureEvents = true;
134                    _dependentHotDeployEvents.clear();
135                    _deployedServletContextNames.clear();
136                    _hotDeployListeners.clear();
137            }
138    
139            public synchronized void setCapturePrematureEvents(
140                    boolean capturePrematureEvents) {
141    
142                    _capturePrematureEvents = capturePrematureEvents;
143            }
144    
145            public void unregisterListener(HotDeployListener hotDeployListener) {
146                    _hotDeployListeners.remove(hotDeployListener);
147            }
148    
149            public void unregisterListeners() {
150                    _hotDeployListeners.clear();
151            }
152    
153            protected void doFireDeployEvent(HotDeployEvent hotDeployEvent) {
154                    String servletContextName = hotDeployEvent.getServletContextName();
155    
156                    if (_deployedServletContextNames.contains(servletContextName)) {
157                            return;
158                    }
159    
160                    boolean hasDependencies = true;
161    
162                    for (String dependentServletContextName :
163                                    hotDeployEvent.getDependentServletContextNames()) {
164    
165                            if (!_deployedServletContextNames.contains(
166                                            dependentServletContextName)) {
167    
168                                    hasDependencies = false;
169    
170                                    break;
171                            }
172                    }
173    
174                    if (hasDependencies) {
175                            if (_log.isInfoEnabled()) {
176                                    _log.info("Deploying " + servletContextName + " from queue");
177                            }
178    
179                            for (HotDeployListener hotDeployListener : _hotDeployListeners) {
180                                    try {
181                                            PortletClassLoaderUtil.setClassLoader(
182                                                    hotDeployEvent.getContextClassLoader());
183                                            PortletClassLoaderUtil.setServletContextName(
184                                                    hotDeployEvent.getServletContextName());
185    
186                                            hotDeployListener.invokeDeploy(hotDeployEvent);
187                                    }
188                                    catch (HotDeployException hde) {
189                                            _log.error(hde, hde);
190                                    }
191                                    finally {
192                                            PortletClassLoaderUtil.setClassLoader(null);
193                                            PortletClassLoaderUtil.setServletContextName(null);
194                                    }
195                            }
196    
197                            _deployedServletContextNames.add(servletContextName);
198    
199                            _dependentHotDeployEvents.remove(hotDeployEvent);
200    
201                            ClassLoader contextClassLoader = getContextClassLoader();
202    
203                            try {
204                                    setContextClassLoader(
205                                            PACLClassLoaderUtil.getPortalClassLoader());
206    
207                                    List<HotDeployEvent> dependentEvents =
208                                            new ArrayList<HotDeployEvent>(_dependentHotDeployEvents);
209    
210                                    for (HotDeployEvent dependentEvent : dependentEvents) {
211                                            setContextClassLoader(
212                                                    dependentEvent.getContextClassLoader());
213    
214                                            doFireDeployEvent(dependentEvent);
215                                    }
216                            }
217                            finally {
218                                    setContextClassLoader(contextClassLoader);
219                            }
220                    }
221                    else {
222                            if (!_dependentHotDeployEvents.contains(hotDeployEvent)) {
223                                    if (_log.isInfoEnabled()) {
224                                            StringBundler sb = new StringBundler(4);
225    
226                                            sb.append("Queueing ");
227                                            sb.append(servletContextName);
228                                            sb.append(" for deploy because it is missing ");
229                                            sb.append(getRequiredServletContextNames(hotDeployEvent));
230    
231                                            _log.info(sb.toString());
232                                    }
233    
234                                    _dependentHotDeployEvents.add(hotDeployEvent);
235                            }
236                            else {
237                                    if (_log.isInfoEnabled()) {
238                                            for (HotDeployEvent dependentHotDeployEvent :
239                                                            _dependentHotDeployEvents) {
240    
241                                                    StringBundler sb = new StringBundler(3);
242    
243                                                    sb.append(servletContextName);
244                                                    sb.append(" is still in queue because it is missing ");
245                                                    sb.append(
246                                                            getRequiredServletContextNames(
247                                                                    dependentHotDeployEvent));
248    
249                                                    _log.info(sb.toString());
250                                            }
251                                    }
252                            }
253                    }
254            }
255    
256            protected ClassLoader getContextClassLoader() {
257                    return PACLClassLoaderUtil.getContextClassLoader();
258            }
259    
260            protected String getRequiredServletContextNames(
261                    HotDeployEvent hotDeployEvent) {
262    
263                    List<String> requiredServletContextNames = new ArrayList<String>();
264    
265                    for (String dependentServletContextName :
266                                    hotDeployEvent.getDependentServletContextNames()) {
267    
268                            if (!_deployedServletContextNames.contains(
269                                            dependentServletContextName)) {
270    
271                                    requiredServletContextNames.add(dependentServletContextName);
272                            }
273                    }
274    
275                    Collections.sort(requiredServletContextNames);
276    
277                    return StringUtil.merge(requiredServletContextNames, ", ");
278            }
279    
280            protected void setContextClassLoader(ClassLoader contextClassLoader) {
281                    PACLClassLoaderUtil.setContextClassLoader(contextClassLoader);
282            }
283    
284            private static Log _log = LogFactoryUtil.getLog(HotDeployImpl.class);
285    
286            private boolean _capturePrematureEvents = true;
287            private List<HotDeployEvent> _dependentHotDeployEvents;
288            private Set<String> _deployedServletContextNames;
289            private List<HotDeployListener> _hotDeployListeners;
290    
291            private class PACLPortalLifecycle extends BasePortalLifecycle {
292    
293                    public PACLPortalLifecycle(HotDeployEvent hotDeployEvent) {
294                            _servletContext = hotDeployEvent.getServletContext();
295                            _classLoader = hotDeployEvent.getContextClassLoader();
296    
297                            ServletContextPool.put(
298                                    _servletContext.getServletContextName(), _servletContext);
299                    }
300    
301                    @Override
302                    protected void doPortalDestroy() {
303                    }
304    
305                    @Override
306                    protected void doPortalInit() throws Exception {
307                            Properties properties = null;
308    
309                            String propertiesString = HttpUtil.URLtoString(
310                                    _servletContext.getResource(
311                                            "/WEB-INF/liferay-plugin-package.properties"));
312    
313                            if (propertiesString != null) {
314                                    properties = PropertiesUtil.load(propertiesString);
315                            }
316                            else {
317                                    properties = new Properties();
318                            }
319    
320                            PACLPolicy paclPolicy = PACLPolicyManager.buildPACLPolicy(
321                                    _servletContext.getServletContextName(), _classLoader,
322                                    properties);
323    
324                            PACLPolicyManager.register(_classLoader, paclPolicy);
325                    }
326    
327                    private ClassLoader _classLoader;
328                    private ServletContext _servletContext;
329    
330            };
331    
332    }