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