001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.kernel.util.Validator;
035    import com.liferay.portal.util.ClassLoaderUtil;
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    
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 ArrayList<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 (int i = _hotDeployListeners.size() - 1; i >= 0; i--) {
103                            HotDeployListener hotDeployListener = _hotDeployListeners.get(i);
104    
105                            try {
106                                    PortletClassLoaderUtil.setClassLoader(
107                                            hotDeployEvent.getContextClassLoader());
108                                    PortletClassLoaderUtil.setServletContextName(
109                                            hotDeployEvent.getServletContextName());
110    
111                                    hotDeployListener.invokeUndeploy(hotDeployEvent);
112                            }
113                            catch (HotDeployException hde) {
114                                    _log.error(hde, hde);
115                            }
116                            finally {
117                                    PortletClassLoaderUtil.setClassLoader(null);
118                                    PortletClassLoaderUtil.setServletContextName(null);
119                            }
120                    }
121    
122                    _deployedServletContextNames.remove(
123                            hotDeployEvent.getServletContextName());
124    
125                    ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
126    
127                    TemplateManagerUtil.destroy(classLoader);
128    
129                    _pacl.unregister(classLoader);
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 static 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                                    try {
225                                            PortletClassLoaderUtil.setClassLoader(
226                                                    hotDeployEvent.getContextClassLoader());
227                                            PortletClassLoaderUtil.setServletContextName(
228                                                    hotDeployEvent.getServletContextName());
229    
230                                            hotDeployListener.invokeDeploy(hotDeployEvent);
231                                    }
232                                    catch (HotDeployException hde) {
233                                            _log.error(hde, hde);
234                                    }
235                                    finally {
236                                            PortletClassLoaderUtil.setClassLoader(null);
237                                            PortletClassLoaderUtil.setServletContextName(null);
238                                    }
239                            }
240    
241                            _deployedServletContextNames.add(servletContextName);
242    
243                            _dependentHotDeployEvents.remove(hotDeployEvent);
244    
245                            ClassLoader contextClassLoader = getContextClassLoader();
246    
247                            try {
248                                    setContextClassLoader(ClassLoaderUtil.getPortalClassLoader());
249    
250                                    List<HotDeployEvent> dependentEvents =
251                                            new ArrayList<HotDeployEvent>(_dependentHotDeployEvents);
252    
253                                    for (HotDeployEvent dependentEvent : dependentEvents) {
254                                            setContextClassLoader(
255                                                    dependentEvent.getContextClassLoader());
256    
257                                            doFireDeployEvent(dependentEvent);
258    
259                                            if (!_dependentHotDeployEvents.contains(dependentEvent)) {
260                                                    dependentEvent.flushInits();
261                                            }
262                                    }
263                            }
264                            finally {
265                                    setContextClassLoader(contextClassLoader);
266                            }
267                    }
268                    else {
269                            if (!_dependentHotDeployEvents.contains(hotDeployEvent)) {
270                                    if (_log.isInfoEnabled()) {
271                                            StringBundler sb = new StringBundler(4);
272    
273                                            sb.append("Queueing ");
274                                            sb.append(servletContextName);
275                                            sb.append(" for deploy because it is missing ");
276                                            sb.append(getRequiredServletContextNames(hotDeployEvent));
277    
278                                            _log.info(sb.toString());
279                                    }
280    
281                                    _dependentHotDeployEvents.add(hotDeployEvent);
282                            }
283                            else {
284                                    if (_log.isInfoEnabled()) {
285                                            for (HotDeployEvent dependentHotDeployEvent :
286                                                            _dependentHotDeployEvents) {
287    
288                                                    StringBundler sb = new StringBundler(3);
289    
290                                                    sb.append(servletContextName);
291                                                    sb.append(" is still in queue because it is missing ");
292                                                    sb.append(
293                                                            getRequiredServletContextNames(
294                                                                    dependentHotDeployEvent));
295    
296                                                    _log.info(sb.toString());
297                                            }
298                                    }
299                            }
300                    }
301            }
302    
303            protected ClassLoader getContextClassLoader() {
304                    return ClassLoaderUtil.getContextClassLoader();
305            }
306    
307            protected String getRequiredServletContextNames(
308                    HotDeployEvent hotDeployEvent) {
309    
310                    List<String> requiredServletContextNames = new ArrayList<String>();
311    
312                    for (String dependentServletContextName :
313                                    hotDeployEvent.getDependentServletContextNames()) {
314    
315                            if (!_deployedServletContextNames.contains(
316                                            dependentServletContextName)) {
317    
318                                    requiredServletContextNames.add(dependentServletContextName);
319                            }
320                    }
321    
322                    Collections.sort(requiredServletContextNames);
323    
324                    return StringUtil.merge(requiredServletContextNames, ", ");
325            }
326    
327            protected void setContextClassLoader(ClassLoader contextClassLoader) {
328                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
329            }
330    
331            private static Log _log = LogFactoryUtil.getLog(HotDeployImpl.class);
332    
333            private static PACL _pacl = new NoPACL();
334    
335            private boolean _capturePrematureEvents = true;
336            private final List<HotDeployEvent> _dependentHotDeployEvents;
337            private final Set<String> _deployedServletContextNames;
338            private final List<HotDeployListener> _hotDeployListeners;
339    
340            private static class NoPACL implements PACL {
341    
342                    @Override
343                    public void initPolicy(
344                            String servletContextName, ClassLoader classLoader,
345                            Properties properties) {
346                    }
347    
348                    @Override
349                    public void unregister(ClassLoader classLoader) {
350                    }
351    
352            }
353    
354            private class HotDeployPortalLifecycle extends BasePortalLifecycle {
355    
356                    public HotDeployPortalLifecycle(HotDeployEvent hotDeployEvent) {
357                            _servletContext = hotDeployEvent.getServletContext();
358                            _classLoader = hotDeployEvent.getContextClassLoader();
359    
360                            ServletContextPool.put(
361                                    _servletContext.getServletContextName(), _servletContext);
362                    }
363    
364                    @Override
365                    protected void doPortalDestroy() {
366                    }
367    
368                    @Override
369                    protected void doPortalInit() throws Exception {
370                            Properties properties = null;
371    
372                            String propertiesString = HttpUtil.URLtoString(
373                                    _servletContext.getResource(
374                                            "/WEB-INF/liferay-plugin-package.properties"));
375    
376                            if (propertiesString != null) {
377                                    properties = PropertiesUtil.load(propertiesString);
378                            }
379                            else {
380                                    properties = new Properties();
381                            }
382    
383                            _pacl.initPolicy(
384                                    _servletContext.getServletContextName(), _classLoader,
385                                    properties);
386                    }
387    
388                    private ClassLoader _classLoader;
389                    private ServletContext _servletContext;
390    
391            }
392    
393    }