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