Clover Coverage Report - Atlassian Core
Coverage timestamp: Sun Nov 30 2008 18:33:35 CST
117   483   51   5.85
50   282   0.44   20
20     2.55  
1    
 
 
  FileUtils       Line # 16 117 51 36.9% 0.36898395
 
  (8)
 
1    package com.atlassian.core.util;
2   
3    import com.atlassian.core.util.zip.FolderArchiver;
4    import org.apache.log4j.Logger;
5    import org.apache.commons.io.IOUtils;
6   
7    import javax.servlet.http.HttpServletRequest;
8    import java.io.*;
9    import java.util.ArrayList;
10    import java.util.List;
11    import java.util.Iterator;
12   
13    /*
14    * A series of utility methods for manipulating files.
15    */
 
16    public class FileUtils
17    {
18    private static final Logger log = Logger.getLogger(FileUtils.class);
19   
20    /**
21    * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
22    * @param input the <code>InputStream</code> to read from
23    * @param output the <code>OutputStream</code> to write to
24    * @return the number of bytes copied
25    * @throws IOException In case of an I/O problem
26    * @deprecated since 3.18 use {@link IOUtils#copy(InputStream, OutputStream)}
27    * @see IOUtils#copy(InputStream, OutputStream)
28    */
 
29  1 toggle public static int copy(final InputStream input, final OutputStream output)
30    throws IOException
31    {
32  1 return IOUtils.copy(input, output);
33    }
34   
35    /**
36    * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
37    * @param input the <code>InputStream</code> to read from
38    * @param output the <code>OutputStream</code> to write to
39    * @param bufferSize ignored
40    * @return the number of bytes copied
41    * @throws IOException In case of an I/O problem
42    * @deprecated since 3.18 use {@link IOUtils#copy(InputStream, OutputStream)}
43    * @see IOUtils#copy(InputStream, OutputStream)
44    */
 
45  0 toggle public static int copy(final InputStream input,
46    final OutputStream output,
47    final int bufferSize)
48    throws IOException
49    {
50  0 return IOUtils.copy(input, output);
51    }
52   
53    /**
54    * Unconditionally close an <code>OutputStream</code>.
55    * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
56    * @param output A (possibly null) OutputStream
57    * @deprecated since 3.18 use {@link IOUtils#closeQuietly(OutputStream)}
58    * @see IOUtils#closeQuietly(OutputStream)
59    */
 
60  2 toggle public static void shutdownStream(final OutputStream output)
61    {
62  2 IOUtils.closeQuietly(output);
63    }
64   
65    /**
66    * Unconditionally close an <code>InputStream</code>.
67    * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
68    * @param input A (possibly null) InputStream
69    * @deprecated since 3.18 use {@link IOUtils#closeQuietly(OutputStream)}
70    * @see IOUtils#closeQuietly(OutputStream)
71    */
 
72  2 toggle public static void shutdownStream(final InputStream input)
73    {
74  2 IOUtils.closeQuietly(input);
75    }
76   
77    /**
78    * safely performs a recursive delete on a directory
79    */
 
80  2 toggle public static boolean deleteDir(File dir)
81    {
82  2 if (dir == null)
83    {
84  0 return false;
85    }
86   
87    // to see if this directory is actually a symbolic link to a directory,
88    // we want to get its canonical path - that is, we follow the link to
89    // the file it's actually linked to
90  2 File candir;
91  2 try
92    {
93  2 candir = dir.getCanonicalFile();
94    }
95    catch (IOException e)
96    {
97  0 return false;
98    }
99   
100    // a symbolic link has a different canonical path than its actual path,
101    // unless it's a link to itself
102  2 if (!candir.equals(dir.getAbsoluteFile()))
103    {
104    // this file is a symbolic link, and there's no reason for us to
105    // follow it, because then we might be deleting something outside of
106    // the directory we were told to delete
107  0 return false;
108    }
109   
110    // now we go through all of the files and subdirectories in the
111    // directory and delete them one by one
112  2 File[] files = candir.listFiles();
113  2 if (files != null)
114    {
115  4 for (int i = 0; i < files.length; i++)
116    {
117  2 File file = files[i];
118   
119    // in case this directory is actually a symbolic link, or it's
120    // empty, we want to try to delete the link before we try
121    // anything
122  2 boolean deleted = !file.delete();
123  2 if (deleted)
124    {
125    // deleting the file failed, so maybe it's a non-empty
126    // directory
127  1 if (file.isDirectory()) deleteDir(file);
128   
129    // otherwise, there's nothing else we can do
130    }
131    }
132    }
133   
134    // now that we tried to clear the directory out, we can try to delete it
135    // again
136  2 return dir.delete();
137    }
138   
139   
140    /**
141    * Recursively delete everything beneath <param>file</param> then delete dir.
142    */
 
143  0 toggle public static void recursiveDelete(File file)
144    {
145  0 if (!file.isDirectory())
146    {
147  0 file.delete();
148  0 return;
149    }
150   
151  0 File[] files = file.listFiles();
152  0 for (int i = 0; i < files.length; i++)
153    {
154  0 File next = files[i];
155  0 recursiveDelete(next);
156    }
157   
158  0 file.delete();
159    }
160   
161   
162    /**
163    * Get the contents of a classpath resource as a String. Returns <tt>null</tt> if
164    * the resource cannot be found or an error occurs reading the resource.
165    */
 
166  0 toggle public static String getResourceContent(String resource)
167    {
168  0 InputStream is = ClassLoaderUtils.getResourceAsStream(resource, FileUtils.class);
169  0 if (is == null) return null;
170   
171  0 try
172    {
173  0 return IOUtils.toString(is);
174    }
175    catch (IOException e)
176    {
177  0 log.error("IOException reading stream: " + e, e);
178  0 return null;
179    }
180    finally
181    {
182  0 IOUtils.closeQuietly(is);
183    }
184    }
185   
186    /**
187    * Get the contents of a servlet context resource as a String. Returns an empty
188    * String ("") if the resource cannot be found or an error occurs reading the resource.
189    */
 
190  0 toggle public static String getResourceContent(HttpServletRequest req, String resource)
191    {
192  0 InputStream is = req.getSession().getServletContext().getResourceAsStream(resource);
193  0 if (is == null) return "";
194   
195  0 try
196    {
197  0 String result = IOUtils.toString(is);
198  0 return (result == null) ? "" : result;
199    }
200    catch (IOException e)
201    {
202  0 log.error("IOException reading stream: " + e, e);
203  0 return "";
204    }
205    finally
206    {
207  0 IOUtils.closeQuietly(is);
208    }
209    }
210   
211    /**
212    * Get the contents of an inputstream as a String.
213    *
214    * @deprecated since 3.18 use {@link IOUtils#toString(InputStream, String)}
215    * @see IOUtils#toString(InputStream, String)
216    */
 
217  0 toggle public static String getInputStreamTextContent(InputStream is)
218    {
219  0 if (is == null)
220    {
221  0 return null;
222    }
223   
224  0 try
225    {
226  0 return IOUtils.toString(is);
227    }
228    catch (IOException e)
229    {
230  0 log.error("IOException reading stream: " + e, e);
231  0 return null;
232    }
233    finally
234    {
235  0 IOUtils.closeQuietly(is);
236    }
237    }
238   
239    /**
240    * Writes text to the nominated file.
241    * If this file already exists, its content will be overwritten
242    */
 
243  5 toggle public static void saveTextFile(String stringContent, File destFile) throws IOException
244    {
245  5 ensureFileAndPathExist(destFile);
246   
247  5 FileWriter writer = new FileWriter(destFile);
248  5 writer.write(stringContent);
249  5 writer.close();
250    }
251   
252    /**
253    * Check that a given file and its parent directories exist - will create blank file and all directories if necessary.
254    */
 
255  5 toggle public static void ensureFileAndPathExist(File file) throws IOException
256    {
257  5 file.getParentFile().mkdirs();
258  5 file.createNewFile();
259    }
260   
261    /**
262    * move a directory with all it's children into another directory
263    * if destination directory already exists, it will be deleted.
264    *
265    * e.g. rename c:/foo/bar to c:/fooz/bar
266    */
 
267  1 toggle public static boolean moveDir(File dirName, File destDir)
268    {
269  1 File destParent = new File(destDir.getParent());
270   
271    // if the destDir exists, we override
272  1 if (destDir.exists())
273    {
274  0 destDir.delete();
275    }
276    // destParent is the new directory we're moving dirName to
277    // we have to ensure all its directories are created before moving
278  1 destParent.mkdirs();
279  1 return dirName.renameTo(destDir);
280    }
281   
282    /**
283    * Create a zip file of a given directory.
284    */
 
285  0 toggle public static void createZipFile(File baseDir, File zipFile) throws Exception
286    {
287  0 FolderArchiver compressor = new FolderArchiver(baseDir, zipFile);
288  0 compressor.doArchive();
289    }
290   
291    /**
292    * Get the contents of a resource as a list, one line representing one list item.
293    * <p />
294    * Note: lines starting with # are deemed to be comments and not included.
295    */
 
296  0 toggle public static List readResourcesAsList(String resource)
297    {
298  0 List result = new ArrayList();
299   
300  0 InputStream is = ClassLoaderUtils.getResourceAsStream(resource, FileUtils.class);
301   
302  0 try
303    {
304  0 result.addAll(IOUtils.readLines(is));
305    }
306    catch (IOException e)
307    {
308  0 log.error("IOException reading stream: " + e, e);
309  0 return result;
310    }
311    finally
312    {
313  0 IOUtils.closeQuietly(is);
314    }
315   
316  0 for (Iterator iterator = result.iterator(); iterator.hasNext();)
317    {
318  0 String s = (String) iterator.next();
319  0 if (org.apache.commons.lang.StringUtils.isBlank(s) || org.apache.commons.lang.StringUtils.trimToEmpty(s).startsWith("#"))
320  0 iterator.remove();
321    }
322   
323  0 return result;
324    }
325   
326    /**
327    * Copies all files from srcDir to destDir. Currently it just copies the files at te root, it's not recursive.
328    */
 
329  0 toggle public static void copyDirectory(File srcDir, File destDir) throws IOException
330    {
331  0 copyDirectory(srcDir, destDir, false);
332    }
333   
 
334  0 toggle public static void copyDirectory(File srcDir, File destDir, boolean overwrite) throws IOException
335    {
336  0 File[] files = srcDir.listFiles();
337   
338  0 if (!destDir.exists())
339  0 destDir.mkdirs();
340    else
341  0 log.debug(destDir.getAbsolutePath() + " already exists");
342   
343  0 if (files != null)
344    {
345  0 for (int i = 0; i < files.length; i++)
346    {
347  0 File file = files[i];
348  0 File dest = new File(destDir, file.getName());
349   
350  0 if (file.isFile())
351  0 copyFile(new FileInputStream(file), dest, overwrite);
352    else
353  0 copyDirectory(file, dest, overwrite);
354    }
355    }
356    }
357   
358    /**
359    * Copy file from source to destination. The directories up to <code>destination</code> will be
360    * created if they don't already exist. <code>destination</code> will be overwritten if it
361    * already exists.
362    *
363    * @param srcFile An existing non-directory <code>File</code> to copy bytes from.
364    * @param destFile A non-directory <code>File</code> to write bytes to (possibly
365    * overwriting).
366    *
367    * @throws java.io.IOException if <code>source</code> does not exist, <code>destination</code> cannot be
368    * written to, or an IO error occurs during copying.
369    *
370    */
 
371  1 toggle public static void copyFile(File srcFile, File destFile) throws IOException
372    {
373  1 copyFile(srcFile, destFile, true);
374    }
375   
376    /**
377    * Copies a file to a new location, optionally overwriting an existing file in the new location.
378    * <p/>
379    * If overwrite is <tt>false</tt> and the file already exists, this method logs a warning and returns.
380    * If the parent directory of the destination file does not exist, it is created.
381    * <p/>
382    * If the source file does not exist, this method throws an IOException. If the length of the two files
383    * are not the same after the copy completes,
384    *
385    * @param srcFile the file to copy
386    * @param destFile the file to be saved, which can already exist if overwrite is set
387    * @param overwrite <tt>true</tt> if an existing file should be overwritten
388    * @throws IOException if the source file does not exist, a problem occurs writing to the destination file,
389    * or the destination file exists and is read-only
390    */
 
391  1 toggle public static void copyFile(File srcFile, File destFile, boolean overwrite) throws IOException
392    {
393  1 if (!srcFile.exists())
394    {
395  0 throw new IOException("File " + srcFile + " does not exist");
396    }
397   
398  1 InputStream input = new FileInputStream(srcFile);
399  1 try
400    {
401  1 copyFile(input, destFile, overwrite);
402    }
403    finally
404    {
405  1 IOUtils.closeQuietly(input);
406    }
407   
408  1 if (srcFile.length() != srcFile.length())
409    {
410  0 throw new IOException("Failed to copy full contents from " + srcFile + " to " + destFile);
411    }
412    }
413   
414    /**
415    * Save an input stream to a file. The client is responsible for opening and closing the provided
416    * InputStream. If the file already exists, a warning will be logged and the method will not
417    * ovewrite it.
418    * <p/>
419    * If the parent directory of the destination file does not exist, it is created.
420    *
421    * @param srcStream the input stream to save
422    * @param destFile the file to be saved
423    * @throws IOException if a problem occurs writing to the file, or the file exists and is read-only
424    */
 
425  0 toggle public static void copyFile(InputStream srcStream, File destFile) throws IOException
426    {
427  0 copyFile(srcStream, destFile, false);
428    }
429   
430    /**
431    * Save an input stream to a file, optionally overwriting the file if is exists. The client
432    * is responsible for opening and closing the provided InputStream.
433    * <p/>
434    * If overwrite is <tt>false</tt> and the file already exists, this method logs a warning and returns.
435    * If the parent directory of the destination file does not exist, it is created.
436    *
437    * @param srcStream the input stream to save
438    * @param destFile the file to be saved, which can already exist if overwrite is set
439    * @param overwrite <tt>true</tt> if an existing file should be overwritten
440    * @throws IOException if a problem occurs writing to the file, or the file exists and is read-only
441    */
 
442  1 toggle public static void copyFile(InputStream srcStream, File destFile, boolean overwrite) throws IOException
443    {
444  1 File parentFile = destFile.getParentFile();
445  1 if (!parentFile.isDirectory())
446    {
447  0 parentFile.mkdirs();
448    }
449   
450  1 if (destFile.exists())
451    {
452  1 if (!destFile.canWrite())
453    {
454  0 throw new IOException("Unable to open file " + destFile + " for writing.");
455    }
456  1 if (!overwrite)
457    {
458  0 log.warn(destFile.getAbsolutePath() + " already exists");
459  0 return;
460    }
461  1 log.debug("Overwriting file at: " + destFile.getAbsolutePath());
462    }
463    else
464    {
465  0 destFile.createNewFile();
466    }
467   
468  1 OutputStream output = new BufferedOutputStream(new FileOutputStream(destFile));
469  1 try
470    {
471  1 IOUtils.copy(srcStream, output);
472    }
473    catch (IOException e)
474    {
475  0 log.error("Error writing stream to file: " + destFile.getAbsolutePath());
476  0 throw e;
477    }
478    finally
479    {
480  1 IOUtils.closeQuietly(output);
481    }
482    }
483    }