001 /**
002 * Copyright 2010-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.common.util;
017
018 import java.io.File;
019 import java.io.IOException;
020 import java.util.ArrayList;
021 import java.util.Arrays;
022 import java.util.List;
023
024 import org.apache.commons.io.FileUtils;
025 import org.apache.commons.lang3.StringUtils;
026 import org.slf4j.Logger;
027 import org.slf4j.LoggerFactory;
028
029 public class FileSystemUtils {
030
031 private static final Logger logger = LoggerFactory.getLogger(FileSystemUtils.class);
032
033 /**
034 * Examine the contents of a text file, stopping as soon as it contains <code>token</code>, or <code>timeout</code> is exceeded, whichever comes first.
035 */
036 public static MonitorTextFileResult monitorTextFile(File file, String token, int intervalMillis, int timeoutMillis, String encoding) {
037
038 // Make sure we are configured correctly
039 Assert.notNull(file, "file is null");
040 Assert.hasText(token, "token has no text");
041 Assert.hasText(encoding, "encoding has no text");
042 Assert.isTrue(intervalMillis > 0, "interval must be a positive integer");
043 Assert.isTrue(timeoutMillis > 0, "timeout must be a positive integer");
044
045 // Setup some member variables to record what happens
046 long start = System.currentTimeMillis();
047 long stop = start + timeoutMillis;
048 boolean exists = false;
049 boolean contains = false;
050 boolean timeoutExceeded = false;
051 long now = -1;
052 String content = null;
053
054 // loop until timeout is exceeded or we find the token inside the file
055 for (;;) {
056
057 // Always pause (unless this is the first iteration)
058 if (now != -1) {
059 ThreadUtils.sleep(intervalMillis);
060 }
061
062 // Check to make sure we haven't exceeded our timeout limit
063 now = System.currentTimeMillis();
064 if (now > stop) {
065 timeoutExceeded = true;
066 break;
067 }
068
069 // If the file does not exist, no point in going any further
070 exists = LocationUtils.exists(file);
071 if (!exists) {
072 continue;
073 }
074
075 // The file exists, check to see if the token we are looking for is present in the file
076 content = LocationUtils.toString(file, encoding);
077 contains = StringUtils.contains(content, token);
078 if (contains) {
079 // We found what we are looking for, we are done
080 break;
081 }
082 }
083
084 // Record how long the overall process took
085 long elapsed = now - start;
086
087 // Fill in a pojo detailing what happened
088 MonitorTextFileResult mtfr = new MonitorTextFileResult(exists, contains, timeoutExceeded, elapsed);
089 mtfr.setAbsolutePath(LocationUtils.getCanonicalPath(file));
090 mtfr.setContent(content);
091 return mtfr;
092 }
093
094 public static List<SyncResult> syncFiles(List<SyncRequest> requests) throws IOException {
095 List<SyncResult> results = new ArrayList<SyncResult>();
096 for (SyncRequest request : requests) {
097 SyncResult result = syncFiles(request);
098 results.add(result);
099 }
100 return results;
101 }
102
103 public static SyncResult syncFiles(SyncRequest request) throws IOException {
104 logger.info("Sync [{}] -> [{}]", request.getSrcDir(), request.getDstDir());
105 List<File> dstFiles = getAllFiles(request.getDstDir());
106 List<File> srcFiles = request.getSrcFiles();
107
108 List<String> dstPaths = getRelativePaths(request.getDstDir(), dstFiles);
109 List<String> srcPaths = getRelativePaths(request.getSrcDir(), srcFiles);
110
111 List<String> adds = new ArrayList<String>();
112 List<String> updates = new ArrayList<String>();
113 List<String> deletes = new ArrayList<String>();
114
115 for (String srcPath : srcPaths) {
116 boolean existing = dstPaths.contains(srcPath);
117 if (existing) {
118 updates.add(srcPath);
119 } else {
120 adds.add(srcPath);
121 }
122 }
123 for (String dstPath : dstPaths) {
124 boolean extra = !srcPaths.contains(dstPath);
125 if (extra) {
126 deletes.add(dstPath);
127 }
128 }
129
130 copyFiles(request.getSrcDir(), request.getSrcFiles(), request.getDstDir());
131
132 SyncResult result = new SyncResult();
133 result.setAdds(getFullPaths(request.getDstDir(), adds));
134 result.setUpdates(getFullPaths(request.getDstDir(), updates));
135 result.setDeletes(getFullPaths(request.getDstDir(), deletes));
136 return result;
137 }
138
139 protected static void copyFiles(File srcDir, List<File> files, File dstDir) throws IOException {
140 for (File file : files) {
141 String relativePath = getRelativePath(srcDir, file);
142 File dstFile = new File(dstDir, relativePath);
143 FileUtils.copyFile(file, dstFile);
144 }
145 }
146
147 protected static List<File> getFullPaths(File dir, List<String> relativePaths) {
148 List<File> files = new ArrayList<File>();
149 for (String relativePath : relativePaths) {
150 File file = new File(dir, relativePath);
151 files.add(file);
152 }
153 return files;
154 }
155
156 protected static List<String> getRelativePaths(File dir, List<File> files) {
157 List<String> relativePaths = new ArrayList<String>();
158 for (File file : files) {
159 String relativePath = getRelativePath(dir, file);
160 relativePaths.add(relativePath);
161 }
162 return relativePaths;
163 }
164
165 protected static String getRelativePath(File dir, File file) {
166 String dirPath = LocationUtils.getCanonicalPath(dir);
167 String filePath = LocationUtils.getCanonicalPath(file);
168 if (!StringUtils.contains(filePath, dirPath)) {
169 throw new IllegalArgumentException(file + " does not reside under " + dir);
170 }
171 return StringUtils.remove(filePath, dirPath);
172 }
173
174 protected static List<File> getAllFiles(File dir) {
175 SimpleScanner scanner = new SimpleScanner(dir, Arrays.asList("**/*"), Arrays.asList("**/.svn/**", "**/.git/**"));
176 return scanner.getFiles();
177 }
178
179 }