001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.kernel.config;
018
019 import java.io.File;
020 import java.io.FileInputStream;
021 import java.io.FileOutputStream;
022 import java.io.IOException;
023 import java.io.InputStream;
024 import java.io.OutputStream;
025 import java.io.Reader;
026 import java.io.Writer;
027 import java.net.MalformedURLException;
028 import java.net.URL;
029 import java.util.Collections;
030 import java.util.Enumeration;
031 import java.util.HashMap;
032 import java.util.LinkedHashMap;
033 import java.util.LinkedHashSet;
034 import java.util.Map;
035 import java.util.Set;
036 import java.util.jar.JarFile;
037 import java.util.zip.ZipEntry;
038
039 import org.apache.commons.logging.Log;
040 import org.apache.commons.logging.LogFactory;
041
042 /**
043 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
044 */
045 public class IOUtil {
046 private final static Log log = LogFactory.getLog(IOUtil.class);
047
048 public static void recursiveCopy(File srcDir, File destDir) throws IOException {
049 if (srcDir == null) throw new NullPointerException("sourceDir is null");
050 if (destDir == null) throw new NullPointerException("destDir is null");
051 if (!srcDir.isDirectory() || !srcDir.canRead()) {
052 throw new IllegalArgumentException("Source directory must be a readable directory " + srcDir);
053 }
054 if (destDir.exists()) {
055 throw new IllegalArgumentException("Destination directory already exists " + destDir);
056 }
057 if (srcDir.equals(destDir)) {
058 throw new IllegalArgumentException("Source and destination directory are the same " + srcDir);
059 }
060
061 destDir.mkdirs();
062 if (!destDir.exists()) {
063 throw new IOException("Could not create destination directory " + destDir);
064 }
065
066
067 File[] srcFiles = srcDir.listFiles();
068 if (srcFiles != null) {
069 for (int i = 0; i < srcFiles.length; i++) {
070 File srcFile = srcFiles[i];
071 File destFile = new File(destDir, srcFile.getName());
072 if (srcFile.isDirectory()) {
073 recursiveCopy(srcFile, destFile);
074 } else {
075 copyFile(srcFile, destFile);
076 }
077 }
078 }
079 }
080
081 public static void copyFile(File source, File destination) throws IOException {
082 File destinationDir = destination.getParentFile();
083 if (!destinationDir.exists() && !destinationDir.mkdirs()) {
084 throw new IOException("Cannot create directory : " + destinationDir);
085 }
086
087 InputStream in = null;
088 OutputStream out = null;
089 try {
090 in = new FileInputStream(source);
091 out = new FileOutputStream(destination);
092 writeAll(in, out);
093 } finally {
094 close(in);
095 close(out);
096 }
097 }
098
099 public static void writeAll(InputStream in, OutputStream out) throws IOException {
100 byte[] buffer = new byte[4096];
101 int count;
102 while ((count = in.read(buffer)) > 0) {
103 out.write(buffer, 0, count);
104 }
105 out.flush();
106 }
107
108 private static void listFiles(File directory) {
109 if (!log.isDebugEnabled() || !directory.isDirectory()) {
110 return;
111 }
112 File[] files = directory.listFiles();
113 log.debug(directory.getPath() + " has " + files.length + " files:");
114 for (File file : files) {
115 log.debug(file.getPath());
116 }
117 }
118
119 private static boolean deleteFile(File file) {
120 boolean fileDeleted = file.delete();
121 if (fileDeleted) {
122 return true;
123 }
124
125 // special retry code to handle occasional Windows JDK and Unix NFS timing failures
126 int retryLimit = 5;
127 int retries;
128 int interruptions = 0;
129 for (retries = 1; !fileDeleted && retries <= retryLimit; retries++) {
130 if (log.isDebugEnabled()) {
131 listFiles(file);
132 }
133 System.runFinalization();
134 try {
135 Thread.sleep(1000);
136 } catch (InterruptedException ie) {
137 interruptions++;
138 }
139 System.gc();
140 try {
141 Thread.sleep(1000);
142 } catch (InterruptedException ie) {
143 interruptions++;
144 }
145 fileDeleted = file.delete();
146 }
147 if (fileDeleted) {
148 if (log.isDebugEnabled()) {
149 log.debug(file.getPath() + " deleted after " + retries
150 + " retries, with " + interruptions + " interruptions.");
151 }
152 } else {
153 log.warn(file.getPath() + " not deleted after " + retryLimit
154 + " retries, with " + interruptions + " interruptions.");
155 }
156 return fileDeleted;
157 }
158
159 public static boolean recursiveDelete(File root) {
160 if (root == null) {
161 return true;
162 }
163
164 if (root.isDirectory()) {
165 File[] files = root.listFiles();
166 if (files != null) {
167 for (int i = 0; i < files.length; i++) {
168 File file = files[i];
169 if (file.isDirectory()) {
170 recursiveDelete(file);
171 } else {
172 deleteFile(file);
173 }
174 }
175 }
176 }
177 return deleteFile(root);
178 }
179
180 public static void flush(OutputStream thing) {
181 if (thing != null) {
182 try {
183 thing.flush();
184 } catch (Exception ignored) {
185 }
186 }
187 }
188
189 public static void flush(Writer thing) {
190 if (thing != null) {
191 try {
192 thing.flush();
193 } catch (Exception ignored) {
194 }
195 }
196 }
197
198 public static void close(JarFile thing) {
199 if (thing != null) {
200 try {
201 thing.close();
202 } catch (Exception ignored) {
203 }
204 }
205 }
206
207 public static void close(InputStream thing) {
208 if (thing != null) {
209 try {
210 thing.close();
211 } catch (Exception ignored) {
212 }
213 }
214 }
215
216 public static void close(OutputStream thing) {
217 if (thing != null) {
218 try {
219 thing.close();
220 } catch (Exception ignored) {
221 }
222 }
223 }
224
225 public static void close(Reader thing) {
226 if (thing != null) {
227 try {
228 thing.close();
229 } catch (Exception ignored) {
230 }
231 }
232 }
233
234 public static void close(Writer thing) {
235 if (thing != null) {
236 try {
237 thing.close();
238 } catch (Exception ignored) {
239 }
240 }
241 }
242
243 public static Map<String, File> find(File root, String pattern) {
244 Map<String, File> matches = new HashMap<String, File>();
245 find(root, pattern, matches);
246 return matches;
247 }
248
249 public static void find(File root, String pattern, Map<String, File> matches) {
250 if (!SelectorUtils.hasWildcards(pattern)) {
251 File match = new File(root, pattern);
252 if (match.exists() && match.canRead()) {
253 matches.put(pattern, match);
254 }
255 } else {
256 Map<String, File> files = IOUtil.listAllFileNames(root);
257 for (Map.Entry<String, File> entry : files.entrySet()) {
258 String fileName = entry.getKey();
259 if (SelectorUtils.matchPath(pattern, fileName)) {
260 matches.put(fileName, entry.getValue());
261 }
262 }
263 }
264 }
265
266 public static Set<URL> search(File root, String pattern) throws MalformedURLException {
267 if (root.isDirectory()) {
268 if (pattern == null || pattern.length() == 0) {
269 return Collections.singleton(new URL("file:" + root.toURI().normalize().getPath()));
270 }
271 if (!SelectorUtils.hasWildcards(pattern)) {
272 File match = new File(root, pattern);
273 if (match.exists() && match.canRead()) {
274 return Collections.singleton(new URL("file:" + match.toURI().normalize().getPath()));
275 } else {
276 return Collections.emptySet();
277 }
278 } else {
279 Set<URL> matches = new LinkedHashSet<URL>();
280 Map<String, File> files = listAllFileNames(root);
281 for (Map.Entry<String, File> entry : files.entrySet()) {
282 String fileName = entry.getKey();
283 if (SelectorUtils.matchPath(pattern, fileName)) {
284 File file = entry.getValue();
285 matches.add(new URL("file:" + file.toURI().normalize().getPath()));
286 }
287 }
288 return matches;
289 }
290 } else {
291 JarFile jarFile = null;
292 try {
293 jarFile = new JarFile(root);
294 URL baseURL = new URL("jar:" + root.toURL().toString() + "!/");
295 if (pattern == null || pattern.length() == 0) {
296 return Collections.singleton(baseURL);
297 }
298 if (!SelectorUtils.hasWildcards(pattern)) {
299 ZipEntry entry = jarFile.getEntry(pattern);
300 if (entry != null) {
301 URL match = new URL(baseURL, entry.getName());
302 return Collections.singleton(match);
303 } else {
304 return Collections.emptySet();
305 }
306 } else {
307 Set<URL> matches = new LinkedHashSet<URL>();
308 Enumeration entries = jarFile.entries();
309 while (entries.hasMoreElements()) {
310 ZipEntry entry = (ZipEntry) entries.nextElement();
311 String fileName = entry.getName();
312 if (SelectorUtils.matchPath(pattern, fileName)) {
313 URL url = new URL(baseURL, fileName);
314 matches.add(url);
315 }
316 }
317 return matches;
318 }
319 } catch (MalformedURLException e) {
320 throw e;
321 } catch (IOException e) {
322 return Collections.emptySet();
323 } finally {
324 close(jarFile);
325 }
326 }
327 }
328
329 public static Map<String, File> listAllFileNames(File base) {
330 return listAllFileNames(base, "");
331 }
332
333 private static Map<String, File> listAllFileNames(File base, String prefix) {
334 if (!base.canRead() || !base.isDirectory()) {
335 throw new IllegalArgumentException(base.getAbsolutePath());
336 }
337 Map<String, File> map = new LinkedHashMap<String, File>();
338 File[] hits = base.listFiles();
339 for (File hit : hits) {
340 if (hit.canRead()) {
341 if (hit.isDirectory()) {
342 map.putAll(listAllFileNames(hit, prefix.equals("") ? hit.getName() : prefix + "/" + hit.getName()));
343 } else {
344 map.put(prefix.equals("") ? hit.getName() : prefix + "/" + hit.getName(), hit);
345 }
346 }
347 }
348 map.put(prefix, base);
349 return map;
350 }
351 }