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.kernel.deploy.auto;
016    
017    import com.liferay.portal.kernel.deploy.auto.context.AutoDeploymentContext;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.StringBundler;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    
024    import java.io.File;
025    
026    import java.util.ArrayList;
027    import java.util.HashMap;
028    import java.util.Iterator;
029    import java.util.List;
030    import java.util.Map;
031    import java.util.Set;
032    import java.util.concurrent.CopyOnWriteArrayList;
033    
034    /**
035     * @author Ivica Cardic
036     * @author Brian Wing Shun Chan
037     */
038    public class AutoDeployDir {
039    
040            public static final String DEFAULT_NAME = "defaultAutoDeployDir";
041    
042            /**
043             * @see com.liferay.portal.osgi.web.wab.generator.internal.processor#getAutoDeployListener
044             */
045            public static void deploy(
046                            AutoDeploymentContext autoDeploymentContext,
047                            List<AutoDeployListener> autoDeployListeners)
048                    throws AutoDeployException {
049    
050                    List<AutoDeployListener> deployableAutoDeployListeners =
051                            new ArrayList<>();
052    
053                    for (AutoDeployListener autoDeployListener : autoDeployListeners) {
054                            if (autoDeployListener.isDeployable(autoDeploymentContext)) {
055                                    deployableAutoDeployListeners.add(autoDeployListener);
056                            }
057                    }
058    
059                    if (deployableAutoDeployListeners.size() > 1) {
060                            StringBundler sb = new StringBundler(
061                                    3 + (deployableAutoDeployListeners.size() * 2) - 1);
062    
063                            sb.append("More than one auto deploy listener is available for ");
064                            sb.append(autoDeploymentContext.getFile());
065                            sb.append(": ");
066    
067                            for (int i = 0; i < deployableAutoDeployListeners.size(); i++) {
068                                    AutoDeployListener deployableAutoDeployListener =
069                                            deployableAutoDeployListeners.get(i);
070    
071                                    Class<?> clazz = deployableAutoDeployListener.getClass();
072    
073                                    if (i != 0) {
074                                            sb.append(StringPool.COMMA_AND_SPACE);
075                                    }
076    
077                                    sb.append(clazz.getName());
078                            }
079    
080                            throw new AutoDeployException(sb.toString());
081                    }
082    
083                    for (AutoDeployListener deployableAutoDeployListener :
084                                    deployableAutoDeployListeners) {
085    
086                            deployableAutoDeployListener.deploy(autoDeploymentContext);
087                    }
088            }
089    
090            public AutoDeployDir(
091                    String name, File deployDir, File destDir, long interval,
092                    List<AutoDeployListener> autoDeployListeners) {
093    
094                    _name = name;
095                    _deployDir = deployDir;
096                    _destDir = destDir;
097                    _interval = interval;
098                    _autoDeployListeners = new CopyOnWriteArrayList<>(autoDeployListeners);
099                    _blacklistFileTimestamps = new HashMap<>();
100            }
101    
102            public File getDeployDir() {
103                    return _deployDir;
104            }
105    
106            public File getDestDir() {
107                    return _destDir;
108            }
109    
110            public long getInterval() {
111                    return _interval;
112            }
113    
114            public List<AutoDeployListener> getListeners() {
115                    return _autoDeployListeners;
116            }
117    
118            public String getName() {
119                    return _name;
120            }
121    
122            public void registerListener(AutoDeployListener listener) {
123                    _autoDeployListeners.add(listener);
124            }
125    
126            public void start() {
127                    if (!_deployDir.exists()) {
128                            if (_log.isInfoEnabled()) {
129                                    _log.info("Creating missing directory " + _deployDir);
130                            }
131    
132                            boolean created = _deployDir.mkdirs();
133    
134                            if (!created) {
135                                    _log.error("Directory " + _deployDir + " could not be created");
136                            }
137                    }
138    
139                    if ((_interval > 0) &&
140                            ((_autoDeployScanner == null) || !_autoDeployScanner.isAlive())) {
141    
142                            try {
143                                    Thread currentThread = Thread.currentThread();
144    
145                                    _autoDeployScanner = new AutoDeployScanner(
146                                            currentThread.getThreadGroup(),
147                                            AutoDeployScanner.class.getName(), this);
148    
149                                    _autoDeployScanner.start();
150    
151                                    if (_log.isInfoEnabled()) {
152                                            _log.info("Auto deploy scanner started for " + _deployDir);
153                                    }
154                            }
155                            catch (Exception e) {
156                                    _log.error(e, e);
157    
158                                    stop();
159    
160                                    return;
161                            }
162                    }
163                    else {
164                            if (_log.isInfoEnabled()) {
165                                    _log.info("Auto deploy scanning is disabled for " + _deployDir);
166                            }
167                    }
168            }
169    
170            public void stop() {
171                    if (_autoDeployScanner != null) {
172                            _autoDeployScanner.pause();
173                    }
174            }
175    
176            public void unregisterListener(AutoDeployListener autoDeployListener) {
177                    _autoDeployListeners.remove(autoDeployListener);
178            }
179    
180            protected AutoDeploymentContext buildAutoDeploymentContext(File file) {
181                    AutoDeploymentContext autoDeploymentContext =
182                            new AutoDeploymentContext();
183    
184                    autoDeploymentContext.setFile(file);
185    
186                    return autoDeploymentContext;
187            }
188    
189            protected void processFile(File file) {
190                    String fileName = file.getName();
191    
192                    if (!file.canRead()) {
193                            _log.error("Unable to read " + fileName);
194    
195                            return;
196                    }
197    
198                    if (!file.canWrite()) {
199                            _log.error("Unable to write " + fileName);
200    
201                            return;
202                    }
203    
204                    if (_blacklistFileTimestamps.containsKey(fileName) &&
205                            (_blacklistFileTimestamps.get(fileName) == file.lastModified())) {
206    
207                            if (_log.isDebugEnabled()) {
208                                    _log.debug(
209                                            "Skip processing of " + fileName + " because it is " +
210                                                    "blacklisted");
211                            }
212    
213                            return;
214                    }
215    
216                    if (_log.isInfoEnabled()) {
217                            _log.info("Processing " + fileName);
218                    }
219    
220                    try {
221                            AutoDeploymentContext autoDeploymentContext =
222                                    buildAutoDeploymentContext(file);
223    
224                            deploy(autoDeploymentContext, _autoDeployListeners);
225    
226                            if (file.delete()) {
227                                    return;
228                            }
229    
230                            _log.error("Auto deploy failed to remove " + fileName);
231                    }
232                    catch (Exception e) {
233                            _log.error(e, e);
234                    }
235    
236                    if (_log.isInfoEnabled()) {
237                            _log.info("Add " + fileName + " to the blacklist");
238                    }
239    
240                    _blacklistFileTimestamps.put(fileName, file.lastModified());
241            }
242    
243            protected void scanDirectory() {
244                    File[] files = _deployDir.listFiles();
245    
246                    if (files == null) {
247                            return;
248                    }
249    
250                    Set<String> blacklistedFileNames = _blacklistFileTimestamps.keySet();
251    
252                    Iterator<String> iterator = blacklistedFileNames.iterator();
253    
254                    while (iterator.hasNext()) {
255                            String blacklistedFileName = iterator.next();
256    
257                            boolean blacklistedFileExists = false;
258    
259                            for (File file : files) {
260                                    if (StringUtil.equalsIgnoreCase(
261                                                    blacklistedFileName, file.getName())) {
262    
263                                            blacklistedFileExists = true;
264                                    }
265                            }
266    
267                            if (!blacklistedFileExists) {
268                                    if (_log.isDebugEnabled()) {
269                                            _log.debug(
270                                                    "Remove blacklisted file " + blacklistedFileName +
271                                                            " because it was deleted");
272                                    }
273    
274                                    iterator.remove();
275                            }
276                    }
277    
278                    for (File file : files) {
279                            String fileName = file.getName();
280    
281                            fileName = StringUtil.toLowerCase(fileName);
282    
283                            if (file.isFile() &&
284                                    (fileName.endsWith(".jar") || fileName.endsWith(".lpkg") ||
285                                     fileName.endsWith(".war") || fileName.endsWith(".xml") ||
286                                     fileName.endsWith(".zip"))) {
287    
288                                    processFile(file);
289                            }
290                    }
291            }
292    
293            private static final Log _log = LogFactoryUtil.getLog(AutoDeployDir.class);
294    
295            private static AutoDeployScanner _autoDeployScanner;
296    
297            private final List<AutoDeployListener> _autoDeployListeners;
298            private final Map<String, Long> _blacklistFileTimestamps;
299            private final File _deployDir;
300            private final File _destDir;
301            private final long _interval;
302            private final String _name;
303    
304    }