001    /**
002     * Copyright (c) 2000-2013 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.IntegerWrapper;
021    import com.liferay.portal.kernel.util.StringBundler;
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.HashSet;
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            public static void deploy(
043                            AutoDeploymentContext autoDeploymentContext,
044                            List<AutoDeployListener> autoDeployListeners)
045                    throws AutoDeployException {
046    
047                    List<String> duplicateApplicableAutoDeployListenerClassNames =
048                            new ArrayList<String>();
049    
050                    for (AutoDeployListener autoDeployListener : autoDeployListeners) {
051                            if (autoDeployListener.deploy(autoDeploymentContext) !=
052                                            AutoDeployer.CODE_NOT_APPLICABLE) {
053    
054                                    Class<?> autoDeployListenerClass =
055                                            autoDeployListener.getClass();
056    
057                                    duplicateApplicableAutoDeployListenerClassNames.add(
058                                            autoDeployListenerClass.getName());
059                            }
060                    }
061    
062                    if (duplicateApplicableAutoDeployListenerClassNames.size() > 1) {
063                            StringBundler sb = new StringBundler();
064    
065                            sb.append("The auto deploy listeners ");
066                            sb.append(
067                                    StringUtil.merge(
068                                            duplicateApplicableAutoDeployListenerClassNames, ", "));
069                            sb.append(" all deployed ");
070                            sb.append(autoDeploymentContext.getFile());
071                            sb.append(", but only one should have.");
072    
073                            throw new AutoDeployException(sb.toString());
074                    }
075            }
076    
077            public AutoDeployDir(
078                    String name, File deployDir, File destDir, long interval,
079                    int blacklistThreshold, List<AutoDeployListener> autoDeployListeners) {
080    
081                    _name = name;
082                    _deployDir = deployDir;
083                    _destDir = destDir;
084                    _interval = interval;
085                    _blacklistThreshold = blacklistThreshold;
086                    _autoDeployListeners = new CopyOnWriteArrayList<AutoDeployListener>(
087                            autoDeployListeners);
088                    _inProcessFiles = new HashMap<String, IntegerWrapper>();
089                    _blacklistFiles = new HashSet<String>();
090            }
091    
092            public int getBlacklistThreshold() {
093                    return _blacklistThreshold;
094            }
095    
096            public File getDeployDir() {
097                    return _deployDir;
098            }
099    
100            public File getDestDir() {
101                    return _destDir;
102            }
103    
104            public long getInterval() {
105                    return _interval;
106            }
107    
108            public List<AutoDeployListener> getListeners() {
109                    return _autoDeployListeners;
110            }
111    
112            public String getName() {
113                    return _name;
114            }
115    
116            public void registerListener(AutoDeployListener listener) {
117                    _autoDeployListeners.add(listener);
118            }
119    
120            public void start() {
121                    if (!_deployDir.exists()) {
122                            if (_log.isInfoEnabled()) {
123                                    _log.info("Creating missing directory " + _deployDir);
124                            }
125    
126                            boolean created = _deployDir.mkdirs();
127    
128                            if (!created) {
129                                    _log.error("Directory " + _deployDir + " could not be created");
130                            }
131                    }
132    
133                    if (_interval > 0) {
134                            try {
135                                    Thread currentThread = Thread.currentThread();
136    
137                                    _autoDeployScanner = new AutoDeployScanner(
138                                            currentThread.getThreadGroup(),
139                                            AutoDeployScanner.class.getName(), this);
140    
141                                    _autoDeployScanner.start();
142    
143                                    if (_log.isInfoEnabled()) {
144                                            _log.info("Auto deploy scanner started for " + _deployDir);
145                                    }
146                            }
147                            catch (Exception e) {
148                                    _log.error(e, e);
149    
150                                    stop();
151    
152                                    return;
153                            }
154                    }
155                    else {
156                            if (_log.isInfoEnabled()) {
157                                    _log.info("Auto deploy scanning is disabled for " + _deployDir);
158                            }
159                    }
160            }
161    
162            public void stop() {
163                    if (_autoDeployScanner != null) {
164                            _autoDeployScanner.pause();
165                    }
166            }
167    
168            public void unregisterListener(AutoDeployListener autoDeployListener) {
169                    _autoDeployListeners.remove(autoDeployListener);
170            }
171    
172            protected AutoDeploymentContext buildAutoDeploymentContext(File file) {
173                    AutoDeploymentContext autoDeploymentContext =
174                            new AutoDeploymentContext();
175    
176                    autoDeploymentContext.setFile(file);
177    
178                    return autoDeploymentContext;
179            }
180    
181            protected void processFile(File file) {
182                    String fileName = file.getName();
183    
184                    if (!file.canRead()) {
185                            _log.error("Unable to read " + fileName);
186    
187                            return;
188                    }
189    
190                    if (!file.canWrite()) {
191                            _log.error("Unable to write " + fileName);
192    
193                            return;
194                    }
195    
196                    if (_blacklistFiles.contains(fileName)) {
197                            if (_log.isDebugEnabled()) {
198                                    _log.debug(
199                                            "Skip processing of " + fileName + " because it is " +
200                                                    "blacklisted. You must restart the server to remove " +
201                                                            "the file from the blacklist.");
202                            }
203    
204                            return;
205                    }
206    
207                    IntegerWrapper attempt = _inProcessFiles.get(fileName);
208    
209                    if (attempt == null) {
210                            attempt = new IntegerWrapper(1);
211    
212                            _inProcessFiles.put(fileName, attempt);
213    
214                            if (_log.isInfoEnabled()) {
215                                    _log.info("Processing " + fileName);
216                            }
217                    }
218                    else {
219                            if (_log.isInfoEnabled()) {
220                                    _log.info(
221                                            "Processing " + fileName + ". This is attempt " +
222                                                    attempt.getValue() + ".");
223                            }
224                    }
225    
226                    try {
227                            AutoDeploymentContext autoDeploymentContext =
228                                    buildAutoDeploymentContext(file);
229    
230                            deploy(autoDeploymentContext, _autoDeployListeners);
231    
232                            if (file.delete()) {
233                                    _inProcessFiles.remove(fileName);
234                            }
235                            else {
236                                    _log.error("Auto deploy failed to remove " + fileName);
237    
238                                    if (_log.isInfoEnabled()) {
239                                            _log.info("Add " + fileName + " to the blacklist");
240                                    }
241    
242                                    _blacklistFiles.add(fileName);
243                            }
244                    }
245                    catch (Exception e) {
246                            _log.error(e, e);
247    
248                            attempt.increment();
249    
250                            if (attempt.getValue() >= _blacklistThreshold) {
251                                    if (_log.isInfoEnabled()) {
252                                            _log.info("Add " + fileName + " to the blacklist");
253                                    }
254    
255                                    _blacklistFiles.add(fileName);
256                            }
257                    }
258            }
259    
260            protected void scanDirectory() {
261                    File[] files = _deployDir.listFiles();
262    
263                    for (File file : files) {
264                            String fileName = file.getName().toLowerCase();
265    
266                            if (file.isFile() &&
267                                    (fileName.endsWith(".jar") || fileName.endsWith(".lpkg") ||
268                                     fileName.endsWith(".war") || fileName.endsWith(".xml") ||
269                                     fileName.endsWith(".zip"))) {
270    
271                                    processFile(file);
272                            }
273                    }
274            }
275    
276            private static Log _log = LogFactoryUtil.getLog(AutoDeployDir.class);
277    
278            private List<AutoDeployListener> _autoDeployListeners;
279            private AutoDeployScanner _autoDeployScanner;
280            private Set<String> _blacklistFiles;
281            private int _blacklistThreshold;
282            private File _deployDir;
283            private File _destDir;
284            private Map<String, IntegerWrapper> _inProcessFiles;
285            private long _interval;
286            private String _name;
287    
288    }