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    }