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.kernel.deploy.hot;
016    
017    import com.liferay.portal.kernel.concurrent.LockRegistry;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.spring.context.PortletContextLoaderListener;
021    import com.liferay.portal.kernel.util.BasePortalLifecycle;
022    import com.liferay.portal.kernel.util.PortalLifecycle;
023    import com.liferay.portal.kernel.util.PortalLifecycleUtil;
024    import com.liferay.portal.kernel.util.StringUtil;
025    
026    import java.util.ArrayList;
027    import java.util.Collections;
028    import java.util.HashSet;
029    import java.util.List;
030    import java.util.Set;
031    import java.util.concurrent.CopyOnWriteArrayList;
032    
033    /**
034     * @author Ivica Cardic
035     * @author Brian Wing Shun Chan
036     */
037    public class HotDeployUtil {
038    
039            public static void fireDeployEvent(HotDeployEvent event) {
040                    _instance._fireDeployEvent(event);
041            }
042    
043            public static void fireUndeployEvent(HotDeployEvent event) {
044                    _instance._fireUndeployEvent(event);
045            }
046    
047            public static void registerListener(HotDeployListener listener) {
048                    _instance._registerListener(listener);
049            }
050    
051            public static void reset() {
052                    _instance._reset();
053            }
054    
055            public static void setCapturePrematureEvents(
056                    boolean capturePrematureEvents) {
057    
058                    _instance._setCapturePrematureEvents(capturePrematureEvents);
059            }
060    
061            public static void unregisterListener(HotDeployListener listener) {
062                    _instance._unregisterListener(listener);
063            }
064    
065            public static void unregisterListeners() {
066                    _instance._unregisterListeners();
067            }
068    
069            private HotDeployUtil() {
070                    if (_log.isInfoEnabled()) {
071                            _log.info("Initializing hot deploy manager " + this.hashCode());
072                    }
073    
074                    _dependentEvents = new ArrayList<HotDeployEvent>();
075                    _deployedServletContextNames = new HashSet<String>();
076                    _listeners = new CopyOnWriteArrayList<HotDeployListener>();
077            }
078    
079            private void _doFireDeployEvent(HotDeployEvent event) {
080                    if (_deployedServletContextNames.contains(
081                                    event.getServletContextName())) {
082    
083                            return;
084                    }
085    
086                    boolean hasDependencies = true;
087    
088                    for (String dependentServletContextName :
089                                    event.getDependentServletContextNames()) {
090    
091                            if (!_deployedServletContextNames.contains(
092                                            dependentServletContextName)) {
093    
094                                    hasDependencies = false;
095    
096                                    break;
097                            }
098                    }
099    
100                    if (hasDependencies) {
101                            if (_dependentEvents.contains(event)) {
102                                    if (_log.isInfoEnabled()) {
103                                            _log.info(
104                                                    "Deploying " + event.getServletContextName() +
105                                                            " from queue");
106                                    }
107                            }
108    
109                            for (HotDeployListener listener : _listeners) {
110                                    try {
111                                            listener.invokeDeploy(event);
112                                    }
113                                    catch (HotDeployException hde) {
114                                            _log.error(hde, hde);
115                                    }
116                            }
117    
118                            _deployedServletContextNames.add(event.getServletContextName());
119    
120                            _dependentEvents.remove(event);
121    
122                            List<HotDeployEvent> dependentEvents =
123                                    new ArrayList<HotDeployEvent>(_dependentEvents);
124    
125                            for (HotDeployEvent dependentEvent : dependentEvents) {
126                                    _doFireDeployEvent(dependentEvent);
127                            }
128                    }
129                    else {
130                            if (!_dependentEvents.contains(event)) {
131                                    if (_log.isInfoEnabled()) {
132                                            StringBuilder sb = new StringBuilder();
133    
134                                            sb.append("Queueing ");
135                                            sb.append(event.getServletContextName());
136                                            sb.append(" for deploy because it is missing ");
137                                            sb.append(_getRequiredServletContextNames(event));
138    
139                                            _log.info(sb.toString());
140                                    }
141    
142                                    _dependentEvents.add(event);
143                            }
144                            else {
145                                    if (_log.isInfoEnabled()) {
146                                            for (HotDeployEvent dependentEvent : _dependentEvents) {
147    
148                                                    StringBuilder sb = new StringBuilder();
149    
150                                                    sb.append(dependentEvent.getServletContextName());
151                                                    sb.append(" is still in queue because it is missing ");
152                                                    sb.append(
153                                                            _getRequiredServletContextNames(dependentEvent));
154    
155                                                    _log.info(sb.toString());
156                                            }
157                                    }
158                            }
159                    }
160            }
161    
162            private void _fireDeployEvent(final HotDeployEvent event) {
163                    if (_capturePrematureEvents) {
164    
165                            // Capture events that are fired before the portal initialized
166    
167                            PortalLifecycle portalLifecycle = new BasePortalLifecycle() {
168    
169                                    @Override
170                                    protected void doPortalDestroy() {
171                                    }
172    
173                                    @Override
174                                    protected void doPortalInit() {
175                                            HotDeployUtil.fireDeployEvent(event);
176                                    }
177    
178                            };
179    
180                            PortalLifecycleUtil.register(
181                                    portalLifecycle, PortalLifecycle.METHOD_INIT);
182                    }
183                    else {
184    
185                            // Fire current event
186    
187                            try {
188                                    _doFireDeployEvent(event);
189                            }
190                            finally {
191                                    String lockKey = PortletContextLoaderListener.getLockKey(
192                                            event.getServletContext());
193    
194                                    LockRegistry.finallyFreeLock(lockKey, lockKey, true);
195                            }
196                    }
197            }
198    
199            private void _fireUndeployEvent(HotDeployEvent event) {
200                    for (HotDeployListener listener : _listeners) {
201                            try {
202                                    listener.invokeUndeploy(event);
203                            }
204                            catch (HotDeployException hde) {
205                                    _log.error(hde, hde);
206                            }
207                    }
208    
209                    _deployedServletContextNames.remove(event.getServletContextName());
210            }
211    
212            private String _getRequiredServletContextNames(HotDeployEvent event) {
213                    List<String> requiredServletContextNames = new ArrayList<String>();
214    
215                    for (String dependentServletContextName :
216                                    event.getDependentServletContextNames()) {
217    
218                            if (!_deployedServletContextNames.contains(
219                                            dependentServletContextName)) {
220    
221                                    requiredServletContextNames.add(dependentServletContextName);
222                            }
223                    }
224    
225                    Collections.sort(requiredServletContextNames);
226    
227                    return StringUtil.merge(requiredServletContextNames, ", ");
228            }
229    
230            private void _registerListener(HotDeployListener listener) {
231                    _listeners.add(listener);
232            }
233    
234            private void _reset() {
235                    _capturePrematureEvents = true;
236                    _dependentEvents.clear();
237                    _deployedServletContextNames.clear();
238                    _listeners.clear();
239            }
240    
241            private void _setCapturePrematureEvents(boolean capturePrematureEvents) {
242                    _capturePrematureEvents = capturePrematureEvents;
243            }
244    
245            private void _unregisterListener(HotDeployListener listener) {
246                    _listeners.remove(listener);
247            }
248    
249            private void _unregisterListeners() {
250                    _listeners.clear();
251            }
252    
253            private static Log _log = LogFactoryUtil.getLog(HotDeployUtil.class);
254    
255            private static HotDeployUtil _instance = new HotDeployUtil();
256    
257            private boolean _capturePrematureEvents = true;
258            private List<HotDeployEvent> _dependentEvents;
259            private Set<String> _deployedServletContextNames;
260            private List<HotDeployListener> _listeners;
261    
262    }