View Javadoc

1   /*
2    * $Id: FileUtils.java 7976 2007-08-21 14:26:13Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util;
12  
13  import org.mule.MuleManager;
14  import org.mule.MuleRuntimeException;
15  import org.mule.config.i18n.MessageFactory;
16  
17  import java.io.BufferedOutputStream;
18  import java.io.BufferedWriter;
19  import java.io.File;
20  import java.io.FileOutputStream;
21  import java.io.FileWriter;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.io.UnsupportedEncodingException;
26  import java.net.JarURLConnection;
27  import java.net.URI;
28  import java.net.URL;
29  import java.net.URLConnection;
30  import java.net.URLDecoder;
31  import java.util.Enumeration;
32  import java.util.jar.JarEntry;
33  import java.util.jar.JarFile;
34  import java.util.zip.ZipEntry;
35  import java.util.zip.ZipFile;
36  
37  /**
38   * <code>FileUtils</code> contains useful methods for dealing with files &
39   * directories.
40   */
41  // @ThreadSafe
42  public class FileUtils extends org.apache.commons.io.FileUtils
43  {
44      public static synchronized void copyStreamToFile(InputStream input, File destination) throws IOException
45      {
46          if (destination.exists() && !destination.canWrite())
47          {
48              throw new IOException("Destination file does not exist or is not writeable");
49          }
50  
51          try
52          {
53              FileOutputStream output = new FileOutputStream(destination);
54              try
55              {
56                  IOUtils.copy(input, output);
57              }
58              finally
59              {
60                  IOUtils.closeQuietly(output);
61              }
62          }
63          finally
64          {
65              IOUtils.closeQuietly(input);
66          }
67      }
68  
69      // TODO Document me!
70      public static File createFile(String filename) throws IOException
71      {
72          File file = FileUtils.newFile(filename);
73          if (!file.canWrite())
74          {
75              String dirName = file.getPath();
76              int i = dirName.lastIndexOf(File.separator);
77              if (i > -1)
78              {
79                  dirName = dirName.substring(0, i);
80                  File dir = FileUtils.newFile(dirName);
81                  dir.mkdirs();
82              }
83              file.createNewFile();
84          }
85          return file;
86      }
87  
88      // TODO Document me!
89      public static String prepareWinFilename(String filename)
90      {
91          filename = filename.replaceAll("<", "(");
92          filename = filename.replaceAll(">", ")");
93          filename = filename.replaceAll("[/\\*?|:;\\]\\[\"]", "-");
94          return filename;
95      }
96  
97      // TODO Document me!
98      public static File openDirectory(String directory) throws IOException
99      {
100         File dir = FileUtils.newFile(directory);
101         if (!dir.exists())
102         {
103             dir.mkdirs();
104         }
105         if (!dir.isDirectory() || !dir.canRead())
106         {
107             throw new IOException("Path: " + directory + " exists but isn't a directory");
108         }
109         return dir;
110     }
111 
112     /**
113      * Reads the incoming String into a file at at the given destination.
114      *
115      * @param filename name and path of the file to create
116      * @param data     the contents of the file
117      * @return the new file.
118      * @throws IOException If the creating or writing to the file stream fails
119      */
120     public static File stringToFile(String filename, String data) throws IOException
121     {
122         return stringToFile(filename, data, false);
123     }
124 
125     // TODO Document me!
126     public static synchronized File stringToFile(String filename, String data, boolean append)
127             throws IOException
128     {
129         return stringToFile(filename, data, append, false);
130     }
131 
132     // TODO Document me!
133     public static synchronized File stringToFile(String filename, String data, boolean append, boolean newLine)
134             throws IOException
135     {
136         File f = createFile(filename);
137         BufferedWriter writer = null;
138         try
139         {
140             writer = new BufferedWriter(new FileWriter(f, append));
141             writer.write(data);
142             if (newLine)
143             {
144                 writer.newLine();
145             }
146         }
147         finally
148         {
149             if (writer != null)
150             {
151                 writer.close();
152             }
153         }
154         return f;
155     }
156 
157     // TODO Document me!
158     public static String getResourcePath(String resourceName, Class callingClass) throws IOException
159     {
160         return getResourcePath(resourceName, callingClass, MuleManager.getConfiguration().getEncoding());
161     }
162 
163     // TODO Document me!
164     public static String getResourcePath(String resourceName, Class callingClass, String encoding)
165             throws IOException
166     {
167         if (resourceName == null)
168         {
169             // no name
170             return null;
171         }
172 
173         URL url = IOUtils.getResourceAsUrl(resourceName, callingClass);
174         if (url == null)
175         {
176             // not found
177             return null;
178         }
179         return normalizeFilePath(url, encoding);
180     }
181 
182     /**
183      * Remove from uri to file prefix file:/
184      * Add if need file separator to begin
185      *
186      * @param url      file uri to resource
187      * @param encoding - Java encoding names
188      * @return normalized file path
189      * @throws UnsupportedEncodingException if encoding is unknown
190      */
191     public static String normalizeFilePath(URL url, String encoding) throws UnsupportedEncodingException
192     {
193         String resource = URLDecoder.decode(url.toExternalForm(), encoding);
194         if (resource != null)
195         {
196             if (resource.startsWith("file:/"))
197             {
198                 resource = resource.substring(6);
199             }
200             if (!resource.startsWith(File.separator))
201             {
202                 resource = File.separator + resource;
203             }
204         }
205         return resource;
206     }
207 
208 
209     /**
210      * Delete a file tree recursively.
211      * @param dir dir to wipe out
212      * @return false when the first unsuccessful attempt encountered
213      */
214     public static boolean deleteTree(File dir)
215     {
216         return deleteTree(dir, null);
217     }
218 
219     /**
220      * Delete a file tree recursively. This method additionally tries to be
221      * gentle with specified top-level dirs. E.g. this is the case when a
222      * transaction manager asynchronously handles the recovery log, and the test
223      * wipes out everything, leaving the transaction manager puzzled.  
224      * @param dir dir to wipe out
225      * @param topLevelDirsToIgnore which top-level directories to ignore,
226      *        if null or empty then ignored
227      * @return false when the first unsuccessful attempt encountered
228      */
229     public static boolean deleteTree(File dir, final String[] topLevelDirsToIgnore)
230     {
231         if (dir == null || !dir.exists())
232         {
233             return true;
234         }
235         File[] files = dir.listFiles();
236         if (files != null)
237         {
238             for (int i = 0; i < files.length; i++)
239             {
240                 OUTER:
241                 if (files[i].isDirectory())
242                 {
243                     if (topLevelDirsToIgnore != null)
244                     {
245                         for (int j = 0; j < topLevelDirsToIgnore.length; j++)
246                         {
247                             String ignored = topLevelDirsToIgnore[j];
248                             if (ignored.equals(FilenameUtils.getBaseName(files[i].getName())))
249                             {
250                                 break OUTER;
251                             }
252                         }
253                     }
254                     if (!deleteTree(files[i]))
255                     {
256                         return false;
257                     }
258                 }
259                 else
260                 {
261                     if (!files[i].delete())
262                     {
263                         return false;
264                     }
265                 }
266             }
267         }
268         return dir.delete();
269     }
270 
271     /**
272      * Unzip the specified archive to the given directory
273      */
274     public static void unzip(File archive, File directory) throws IOException
275     {
276         ZipFile zip = null;
277 
278         if (directory.exists())
279         {
280             if (!directory.isDirectory())
281             {
282                 throw new IOException("Directory is not a directory: " + directory);
283             }
284         }
285         else
286         {
287             if (!directory.mkdirs())
288             {
289                 throw new IOException("Could not create directory: " + directory);
290             }
291         }
292         try
293         {
294             zip = new ZipFile(archive);
295             for (Enumeration entries = zip.entries(); entries.hasMoreElements();)
296             {
297                 ZipEntry entry = (ZipEntry) entries.nextElement();
298                 File f = FileUtils.newFile(directory, entry.getName());
299                 if (entry.isDirectory())
300                 {
301                     if (!f.mkdirs())
302                     {
303                         throw new IOException("Could not create directory: " + f);
304                     }
305                 }
306                 else
307                 {
308                     InputStream is = zip.getInputStream(entry);
309                     OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
310                     IOUtils.copy(is, os);
311                     IOUtils.closeQuietly(is);
312                     IOUtils.closeQuietly(os);
313                 }
314             }
315         }
316         finally
317         {
318             if (zip != null)
319             {
320                 zip.close();
321             }
322         }
323     }
324 
325     /**
326      * Workaround for JDK bug <a href="http://bugs.sun.com/bugdatabase/view_bug.do;:YfiG?bug_id=4117557">
327      * 4117557</a>. More in-context information at
328      * <a href="http://mule.mulesource.org/jira/browse/MULE-1112">MULE-1112</a>
329      * <p/>
330      * Factory methods correspond to constructors of the <code>java.io.File class</code>.
331      * No physical file created in this method.
332      *
333      * @see File
334      */
335     public static File newFile(String pathName)
336     {
337         try
338         {
339             return new File(pathName).getCanonicalFile();
340         }
341         catch (IOException e)
342         {
343             throw new MuleRuntimeException(
344                     MessageFactory.createStaticMessage("Unable to create a canonical file for " + pathName),
345                     e);
346         }
347     }
348 
349     /**
350      * Workaround for JDK bug <a href="http://bugs.sun.com/bugdatabase/view_bug.do;:YfiG?bug_id=4117557">
351      * 4117557</a>. More in-context information at
352      * <a href="http://mule.mulesource.org/jira/browse/MULE-1112">MULE-1112</a>
353      * <p/>
354      * Factory methods correspond to constructors of the <code>java.io.File class</code>.
355      * No physical file created in this method.
356      *
357      * @see File
358      */
359     public static File newFile(URI uri)
360     {
361         try
362         {
363             return new File(uri).getCanonicalFile();
364         }
365         catch (IOException e)
366         {
367             throw new MuleRuntimeException(
368                     MessageFactory.createStaticMessage("Unable to create a canonical file for " + uri),
369                     e);
370         }
371     }
372 
373     /**
374      * Workaround for JDK bug <a href="http://bugs.sun.com/bugdatabase/view_bug.do;:YfiG?bug_id=4117557">
375      * 4117557</a>. More in-context information at
376      * <a href="http://mule.mulesource.org/jira/browse/MULE-1112">MULE-1112</a>
377      * <p/>
378      * Factory methods correspond to constructors of the <code>java.io.File class</code>.
379      * No physical file created in this method.
380      *
381      * @see File
382      */
383     public static File newFile(File parent, String child)
384     {
385         try
386         {
387             return new File(parent, child).getCanonicalFile();
388         }
389         catch (IOException e)
390         {
391             throw new MuleRuntimeException(
392                     MessageFactory.createStaticMessage("Unable to create a canonical file for parent: "
393                             + parent + " and child: " + child),
394                     e);
395         }
396     }
397 
398     /**
399      * Workaround for JDK bug <a href="http://bugs.sun.com/bugdatabase/view_bug.do;:YfiG?bug_id=4117557">
400      * 4117557</a>. More in-context information at
401      * <a href="http://mule.mulesource.org/jira/browse/MULE-1112">MULE-1112</a>
402      * <p/>
403      * Factory methods correspond to constructors of the <code>java.io.File class</code>.
404      * No physical file created in this method.
405      *
406      * @see File
407      */
408     public static File newFile(String parent, String child)
409     {
410         try
411         {
412             return new File(parent, child).getCanonicalFile();
413         }
414         catch (IOException e)
415         {
416             throw new MuleRuntimeException(
417                     MessageFactory.createStaticMessage("Unable to create a canonical file for parent: "
418                             + parent + " and child: " + child),
419                     e);
420         }
421     }
422 
423     /**
424      * Extract the specified resource to the given directory for
425      * remain all directory struct
426      *
427      * @param resourceName        - full resource name
428      * @param callingClass        - classloader for this class is used
429      * @param outputDir           - extract to this directory
430      * @param keepParentDirectory true -  full structure of directories is kept; false - file - removed all directories, directory - started from resource point
431      * @throws IOException if any errors
432      */
433     public static void extractResources(String resourceName, Class callingClass, File outputDir, boolean keepParentDirectory) throws IOException
434     {
435         URL url = callingClass.getClassLoader().getResource(resourceName);
436         URLConnection connection = url.openConnection();
437         if (connection instanceof JarURLConnection)
438         {
439             extractJarResources((JarURLConnection) connection, outputDir, keepParentDirectory);
440         }
441         else
442         {
443             extractFileResources(normalizeFilePath(url, MuleManager.getConfiguration().getEncoding()), outputDir, resourceName, keepParentDirectory);
444         }
445     }
446 
447     /**
448      * Extract resources contain in file
449      *
450      * @param path                - path to file
451      * @param outputDir           Directory for unpack recources
452      * @param resourceName
453      * @param keepParentDirectory true -  full structure of directories is kept; false - file - removed all directories, directory - started from resource point
454      * @throws IOException if any error
455      */
456     private static void extractFileResources(String path, File outputDir, String resourceName, boolean keepParentDirectory) throws IOException
457     {
458         File file = FileUtils.newFile(path);
459         if (!file.exists())
460         {
461             throw new IOException("The resource by path " + path + " ");
462         }
463         if (file.isDirectory())
464         {
465             if (keepParentDirectory)
466             {
467                 outputDir = FileUtils.newFile(outputDir.getPath() + File.separator + resourceName);
468                 if (!outputDir.exists())
469                 {
470                     outputDir.mkdirs();
471                 }
472             }
473             else
474             {
475                 outputDir = FileUtils.newFile(outputDir.getPath());
476             }
477             copyDirectory(file, outputDir);
478         }
479         else
480         {
481 
482             if (keepParentDirectory)
483             {
484                 outputDir = FileUtils.newFile(outputDir.getPath() + File.separator + resourceName);
485             }
486             else
487             {
488                 outputDir = FileUtils.newFile(outputDir.getPath() + File.separator + file.getName());
489             }
490             copyFile(file, outputDir);
491         }
492     }
493 
494     /**
495      * Extract recources contain if jar (have to in classpath)
496      *
497      * @param connection          JarURLConnection to jar library
498      * @param outputDir           Directory for unpack recources
499      * @param keepParentDirectory true -  full structure of directories is kept; false - file - removed all directories, directory - started from resource point
500      * @throws IOException if any error
501      */
502     private static void extractJarResources(JarURLConnection connection, File outputDir, boolean keepParentDirectory) throws IOException
503     {
504         JarFile jarFile = connection.getJarFile();
505         JarEntry jarResource = connection.getJarEntry();
506         Enumeration entries = jarFile.entries();
507         InputStream inputStream = null;
508         OutputStream outputStream = null;
509         int jarResourceNameLenght = jarResource.getName().length();
510         for (; entries.hasMoreElements();)
511         {
512             JarEntry entry = (JarEntry) entries.nextElement();
513             if (entry.getName().startsWith(jarResource.getName()))
514             {
515 
516                 String path = outputDir.getPath() + File.separator + entry.getName();
517 
518                 //remove directory struct for file and first dir for directory
519                 if (!keepParentDirectory)
520                 {
521                     if (entry.isDirectory())
522                     {
523                         if (entry.getName().equals(jarResource.getName()))
524                         {
525                             continue;
526                         }
527                         path = outputDir.getPath() + File.separator + entry.getName().substring(jarResourceNameLenght, entry.getName().length());
528                     }
529                     else
530                     {
531                         if (entry.getName().length() > jarResourceNameLenght)
532                         {
533                             path = outputDir.getPath() + File.separator + entry.getName().substring(jarResourceNameLenght, entry.getName().length());
534                         }
535                         else
536                         {
537                             path = outputDir.getPath() + File.separator + entry.getName().substring(entry.getName().lastIndexOf("/"), entry.getName().length());
538                         }
539                     }
540                 }
541 
542                 File file = FileUtils.newFile(path);
543                 if (!file.getParentFile().exists())
544                 {
545                     if (!file.getParentFile().mkdirs())
546                     {
547                         throw new IOException("Could not create directory: " + file.getParentFile());
548                     }
549                 }
550                 if (entry.isDirectory())
551                 {
552                     if (!file.exists() && !file.mkdirs())
553                     {
554                         throw new IOException("Could not create directory: " + file);
555                     }
556 
557                 }
558                 else
559                 {
560                     try
561                     {
562                         inputStream = jarFile.getInputStream(entry);
563                         outputStream = new BufferedOutputStream(new FileOutputStream(file));
564                         IOUtils.copy(inputStream, outputStream);
565                     }
566                     finally
567                     {
568                         IOUtils.closeQuietly(inputStream);
569                         IOUtils.closeQuietly(outputStream);
570                     }
571                 }
572 
573             }
574         }
575     }
576 
577 
578 }