Coverage Report - org.apache.maven.it.util.FileUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
FileUtils
0%
0/486
0%
0/274
3.431
FileUtils$FilterWrapper
0%
0/1
N/A
3.431
 
 1  
 package org.apache.maven.it.util;
 2  
 
 3  
 /* ====================================================================
 4  
  * The Apache Software License, Version 1.1
 5  
  *
 6  
  * Copyright (c) 2001 The Apache Software Foundation.  All rights
 7  
  * reserved.
 8  
  *
 9  
  * Redistribution and use in source and binary forms, with or without
 10  
  * modification, are permitted provided that the following conditions
 11  
  * are met:
 12  
  *
 13  
  * 1. Redistributions of source code must retain the above copyright
 14  
  *    notice, this list of conditions and the following disclaimer.
 15  
  *
 16  
  * 2. Redistributions in binary form must reproduce the above copyright
 17  
  *    notice, this list of conditions and the following disclaimer in
 18  
  *    the documentation and/or other materials provided with the
 19  
  *    distribution.
 20  
  *
 21  
  * 3. The end-user documentation included with the redistribution,
 22  
  *    if any, must include the following acknowledgment:
 23  
  *       "This product includes software developed by the
 24  
  *        Apache Software Foundation (http://www.apache.org/)."
 25  
  *    Alternately, this acknowledgment may appear in the software itself,
 26  
  *    if and wherever such third-party acknowledgments normally appear.
 27  
  *
 28  
  * 4. The names "Apache" and "Apache Software Foundation" and
 29  
  *    "Apache Turbine" must not be used to endorse or promote products
 30  
  *    derived from this software without prior written permission. For
 31  
  *    written permission, please contact apache@apache.org.
 32  
  *
 33  
  * 5. Products derived from this software may not be called "Apache",
 34  
  *    "Apache Turbine", nor may "Apache" appear in their name, without
 35  
  *    prior written permission of the Apache Software Foundation.
 36  
  *
 37  
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 38  
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 39  
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 40  
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 41  
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 42  
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 43  
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 44  
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 45  
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 46  
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 47  
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 48  
  * SUCH DAMAGE.
 49  
  * ====================================================================
 50  
  *
 51  
  * This software consists of voluntary contributions made by many
 52  
  * individuals on behalf of the Apache Software Foundation.  For more
 53  
  * information on the Apache Software Foundation, please see
 54  
  * <http://www.apache.org/>.
 55  
  *
 56  
  */
 57  
 
 58  
 import java.io.BufferedReader;
 59  
 import java.io.File;
 60  
 import java.io.FileInputStream;
 61  
 import java.io.FileOutputStream;
 62  
 import java.io.FileReader;
 63  
 import java.io.FileWriter;
 64  
 import java.io.IOException;
 65  
 import java.io.InputStream;
 66  
 import java.io.InputStreamReader;
 67  
 import java.io.OutputStreamWriter;
 68  
 import java.io.Reader;
 69  
 import java.io.Writer;
 70  
 import java.net.URL;
 71  
 import java.text.DecimalFormat;
 72  
 import java.util.ArrayList;
 73  
 import java.util.Arrays;
 74  
 import java.util.Iterator;
 75  
 import java.util.List;
 76  
 import java.util.Random;
 77  
 import java.util.Vector;
 78  
 
 79  
 /**
 80  
  * This class provides basic facilities for manipulating files and file paths.
 81  
  * <p/>
 82  
  * <h3>Path-related methods</h3>
 83  
  * <p/>
 84  
  * <p>Methods exist to retrieve the components of a typical file path. For example
 85  
  * <code>/www/hosted/mysite/index.html</code>, can be broken into:
 86  
  * <ul>
 87  
  * <li><code>/www/hosted/mysite/</code> -- retrievable through {@link #getPath}</li>
 88  
  * <li><code>index.html</code> -- retrievable through {@link #removePath}</li>
 89  
  * <li><code>/www/hosted/mysite/index</code> -- retrievable through {@link #removeExtension}</li>
 90  
  * <li><code>html</code> -- retrievable through {@link #getExtension}</li>
 91  
  * </ul>
 92  
  * There are also methods to {@link #catPath concatenate two paths}, {@link #resolveFile resolve a
 93  
  * path relative to a File} and {@link #normalize} a path.
 94  
  * </p>
 95  
  * <p/>
 96  
  * <h3>File-related methods</h3>
 97  
  * <p/>
 98  
  * There are methods to  create a {@link #toFile File from a URL}, copy a
 99  
  * {@link #copyFileToDirectory File to a directory},
 100  
  * copy a {@link #copyFile File to another File},
 101  
  * copy a {@link #copyURLToFile URL's contents to a File},
 102  
  * as well as methods to {@link #deleteDirectory(File) delete} and {@link #cleanDirectory(File)
 103  
  * clean} a directory.
 104  
  * </p>
 105  
  * <p/>
 106  
  * Common {@link java.io.File} manipulation routines.
 107  
  * <p/>
 108  
  * Taken from the commons-utils repo.
 109  
  * Also code from Alexandria's FileUtils.
 110  
  * And from Avalon Excalibur's IO.
 111  
  * And from Ant.
 112  
  *
 113  
  * @author <a href="mailto:burton@relativity.yi.org">Kevin A. Burton</A>
 114  
  * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
 115  
  * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
 116  
  * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph.Reck</a>
 117  
  * @author <a href="mailto:peter@apache.org">Peter Donald</a>
 118  
  * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
 119  
  * @version $Id: FileUtils.java 723852 2008-12-05 20:28:26Z bentmann $
 120  
  */
 121  0
 public class FileUtils
 122  
 {
 123  
     /**
 124  
      * The number of bytes in a kilobyte.
 125  
      */
 126  
     public static final int ONE_KB = 1024;
 127  
 
 128  
     /**
 129  
      * The number of bytes in a megabyte.
 130  
      */
 131  
     public static final int ONE_MB = ONE_KB * ONE_KB;
 132  
 
 133  
     /**
 134  
      * The number of bytes in a gigabyte.
 135  
      */
 136  
     public static final int ONE_GB = ONE_KB * ONE_MB;
 137  
 
 138  0
     public static String FS = System.getProperty( "file.separator" );
 139  
 
 140  
     public static String[] getDefaultExcludes()
 141  
     {
 142  0
         return DirectoryScanner.DEFAULTEXCLUDES;
 143  
     }
 144  
 
 145  
     public static List getDefaultExcludesAsList()
 146  
     {
 147  0
         return Arrays.asList( getDefaultExcludes() );
 148  
     }
 149  
 
 150  
     /**
 151  
      * Returns a human-readable version of the file size (original is in
 152  
      * bytes).
 153  
      *
 154  
      * @param size The number of bytes.
 155  
      * @return A human-readable display value (includes units).
 156  
      */
 157  
     public static String byteCountToDisplaySize( int size )
 158  
     {
 159  
         String displaySize;
 160  
 
 161  0
         if ( size / ONE_GB > 0 )
 162  
         {
 163  0
             displaySize = String.valueOf( size / ONE_GB ) + " GB";
 164  
         }
 165  0
         else if ( size / ONE_MB > 0 )
 166  
         {
 167  0
             displaySize = String.valueOf( size / ONE_MB ) + " MB";
 168  
         }
 169  0
         else if ( size / ONE_KB > 0 )
 170  
         {
 171  0
             displaySize = String.valueOf( size / ONE_KB ) + " KB";
 172  
         }
 173  
         else
 174  
         {
 175  0
             displaySize = String.valueOf( size ) + " bytes";
 176  
         }
 177  
 
 178  0
         return displaySize;
 179  
     }
 180  
 
 181  
     /**
 182  
      * Returns the directory path portion of a file specification string.
 183  
      * Matches the equally named unix command.
 184  
      *
 185  
      * @return The directory portion excluding the ending file separator.
 186  
      */
 187  
     public static String dirname( String filename )
 188  
     {
 189  0
         int i = filename.lastIndexOf( File.separator );
 190  0
         return ( i >= 0 ? filename.substring( 0, i ) : "" );
 191  
     }
 192  
 
 193  
     /**
 194  
      * Returns the filename portion of a file specification string.
 195  
      *
 196  
      * @return The filename string with extension.
 197  
      */
 198  
     public static String filename( String filename )
 199  
     {
 200  0
         int i = filename.lastIndexOf( File.separator );
 201  0
         return ( i >= 0 ? filename.substring( i + 1 ) : filename );
 202  
     }
 203  
 
 204  
     /**
 205  
      * Returns the filename portion of a file specification string.
 206  
      * Matches the equally named unix command.
 207  
      *
 208  
      * @return The filename string without extension.
 209  
      */
 210  
     public static String basename( String filename )
 211  
     {
 212  0
         return basename( filename, extension( filename ) );
 213  
     }
 214  
 
 215  
     /**
 216  
      * Returns the filename portion of a file specification string.
 217  
      * Matches the equally named unix command.
 218  
      */
 219  
     public static String basename( String filename, String suffix )
 220  
     {
 221  0
         int i = filename.lastIndexOf( File.separator ) + 1;
 222  0
         int lastDot = ( ( suffix != null ) && ( suffix.length() > 0 ) ) ? filename.lastIndexOf( suffix ) : -1;
 223  
 
 224  0
         if ( lastDot >= 0 )
 225  
         {
 226  0
             return filename.substring( i, lastDot );
 227  
         }
 228  0
         else if ( i > 0 )
 229  
         {
 230  0
             return filename.substring( i );
 231  
         }
 232  
         else
 233  
         {
 234  0
             return filename; // else returns all (no path and no extension)
 235  
         }
 236  
     }
 237  
 
 238  
     /**
 239  
      * Returns the extension portion of a file specification string.
 240  
      * This everything after the last dot '.' in the filename (NOT including
 241  
      * the dot).
 242  
      */
 243  
     public static String extension( String filename )
 244  
     {
 245  0
         int lastDot = filename.lastIndexOf( '.' );
 246  
 
 247  0
         if ( lastDot >= 0 )
 248  
         {
 249  0
             return filename.substring( lastDot + 1 );
 250  
         }
 251  
         else
 252  
         {
 253  0
             return "";
 254  
         }
 255  
     }
 256  
 
 257  
     /**
 258  
      * Check if a file exits.
 259  
      *
 260  
      * @param fileName The name of the file to check.
 261  
      * @return true if file exists.
 262  
      */
 263  
     public static boolean fileExists( String fileName )
 264  
     {
 265  0
         File file = new File( fileName );
 266  0
         return file.exists();
 267  
     }
 268  
 
 269  
     public static String fileRead( String file )
 270  
         throws IOException
 271  
     {
 272  0
         return fileRead( new File( file ) );
 273  
     }
 274  
 
 275  
     public static String fileRead( File file )
 276  
         throws IOException
 277  
     {
 278  0
         return fileRead( file, null );
 279  
     }
 280  
 
 281  
     public static String fileRead( File file, String encoding )
 282  
         throws IOException
 283  
     {
 284  0
         StringBuffer buf = new StringBuffer();
 285  
 
 286  0
         Reader reader = null;
 287  
 
 288  
         try
 289  
         {
 290  0
             if ( encoding != null && encoding.length() > 0 )
 291  
             {
 292  0
                 reader = new InputStreamReader( new FileInputStream( file ), encoding );
 293  
             }
 294  
             else
 295  
             {
 296  0
                 reader = new InputStreamReader( new FileInputStream( file ) );
 297  
             }
 298  
             int count;
 299  0
             char[] b = new char[512];
 300  0
             while ( ( count = reader.read( b ) ) > 0 ) // blocking read
 301  
             {
 302  0
                 buf.append( b, 0, count );
 303  
             }
 304  
         }
 305  
         finally
 306  
         {
 307  0
             IOUtil.close( reader );
 308  0
         }
 309  
 
 310  0
         return buf.toString();
 311  
     }
 312  
 
 313  
     /**
 314  
      * Appends data to a file. The file will be created if it does not exist.
 315  
      *
 316  
      * @param fileName The name of the file to write.
 317  
      * @param data     The content to write to the file.
 318  
      */
 319  
     public static void fileAppend( String fileName, String data )
 320  
         throws IOException
 321  
     {
 322  0
         FileOutputStream out = null;
 323  
         try
 324  
         {
 325  0
             out = new FileOutputStream( fileName, true );
 326  0
             out.write( data.getBytes() );
 327  
         }
 328  
         finally
 329  
         {
 330  0
             IOUtil.close( out );
 331  0
         }
 332  0
     }
 333  
 
 334  
     /**
 335  
      * Writes data to a file. The file will be created if it does not exist.
 336  
      *
 337  
      * @param fileName The name of the file to write.
 338  
      * @param data     The content to write to the file.
 339  
      */
 340  
     public static void fileWrite( String fileName, String data )
 341  
         throws IOException
 342  
     {
 343  0
         fileWrite( fileName, null, data );
 344  0
     }
 345  
 
 346  
     /**
 347  
      * Writes data to a file. The file will be created if it does not exist.
 348  
      * 
 349  
      * @param fileName The name of the file to write.
 350  
      * @param encoding The encoding of the file.
 351  
      * @param data The content to write to the file.
 352  
      */
 353  
     public static void fileWrite( String fileName, String encoding, String data )
 354  
         throws IOException
 355  
     {
 356  0
         FileOutputStream out = null;
 357  
         try
 358  
         {
 359  0
             out = new FileOutputStream( fileName );
 360  0
             if ( encoding != null && encoding.length() > 0 )
 361  
             {
 362  0
                 out.write( data.getBytes( encoding ) );
 363  
             }
 364  
             else
 365  
             {
 366  0
                 out.write( data.getBytes() );
 367  
             }
 368  
         }
 369  
         finally
 370  
         {
 371  0
             IOUtil.close( out );
 372  0
         }
 373  0
     }
 374  
 
 375  
     /**
 376  
      * Deletes a file.
 377  
      *
 378  
      * @param fileName The name of the file to delete.
 379  
      */
 380  
     public static void fileDelete( String fileName )
 381  
     {
 382  0
         File file = new File( fileName );
 383  0
         file.delete();
 384  0
     }
 385  
 
 386  
     /**
 387  
      * Waits for NFS to propagate a file creation, imposing a timeout.
 388  
      *
 389  
      * @param fileName The name of the file.
 390  
      * @param seconds  The maximum time in seconds to wait.
 391  
      * @return True if file exists.
 392  
      */
 393  
     public static boolean waitFor( String fileName, int seconds )
 394  
     {
 395  0
         return waitFor( new File( fileName ), seconds );
 396  
     }
 397  
 
 398  
     public static boolean waitFor( File file, int seconds )
 399  
     {
 400  0
         int timeout = 0;
 401  0
         int tick = 0;
 402  0
         while ( !file.exists() )
 403  
         {
 404  0
             if ( tick++ >= 10 )
 405  
             {
 406  0
                 tick = 0;
 407  0
                 if ( timeout++ > seconds )
 408  
                 {
 409  0
                     return false;
 410  
                 }
 411  
             }
 412  
             try
 413  
             {
 414  0
                 Thread.sleep( 100 );
 415  
             }
 416  0
             catch ( InterruptedException ignore )
 417  
             {
 418  0
             }
 419  
         }
 420  0
         return true;
 421  
     }
 422  
 
 423  
     /**
 424  
      * Creates a file handle.
 425  
      *
 426  
      * @param fileName The name of the file.
 427  
      * @return A <code>File</code> manager.
 428  
      */
 429  
     public static File getFile( String fileName )
 430  
     {
 431  0
         return new File( fileName );
 432  
     }
 433  
 
 434  
     /**
 435  
      * Given a directory and an array of extensions return an array of compliant files.
 436  
      * <p/>
 437  
      * TODO Should an ignore list be passed in?
 438  
      * TODO Should a recurse flag be passed in?
 439  
      * <p/>
 440  
      * The given extensions should be like "java" and not like ".java"
 441  
      */
 442  
     public static String[] getFilesFromExtension( String directory, String[] extensions )
 443  
     {
 444  
 
 445  0
         Vector files = new Vector();
 446  
 
 447  0
         java.io.File currentDir = new java.io.File( directory );
 448  
 
 449  0
         String[] unknownFiles = currentDir.list();
 450  
 
 451  0
         if ( unknownFiles == null )
 452  
         {
 453  0
             return new String[0];
 454  
         }
 455  
 
 456  0
         for ( int i = 0; i < unknownFiles.length; ++i )
 457  
         {
 458  0
             String currentFileName = directory + System.getProperty( "file.separator" ) + unknownFiles[i];
 459  0
             java.io.File currentFile = new java.io.File( currentFileName );
 460  
 
 461  0
             if ( currentFile.isDirectory() )
 462  
             {
 463  
 
 464  
                 //ignore all CVS directories...
 465  0
                 if ( currentFile.getName().equals( "CVS" ) )
 466  
                 {
 467  0
                     continue;
 468  
                 }
 469  
 
 470  
                 //ok... transverse into this directory and get all the files... then combine
 471  
                 //them with the current list.
 472  
 
 473  0
                 String[] fetchFiles = getFilesFromExtension( currentFileName, extensions );
 474  0
                 files = blendFilesToVector( files, fetchFiles );
 475  
 
 476  0
             }
 477  
             else
 478  
             {
 479  
                 //ok... add the file
 480  
 
 481  0
                 String add = currentFile.getAbsolutePath();
 482  0
                 if ( isValidFile( add, extensions ) )
 483  
                 {
 484  0
                     files.addElement( add );
 485  
 
 486  
                 }
 487  
 
 488  
             }
 489  
         }
 490  
 
 491  
         //ok... move the Vector into the files list...
 492  
 
 493  0
         String[] foundFiles = new String[files.size()];
 494  0
         files.copyInto( foundFiles );
 495  
 
 496  0
         return foundFiles;
 497  
 
 498  
     }
 499  
 
 500  
 
 501  
     /**
 502  
      * Private hepler method for getFilesFromExtension()
 503  
      */
 504  
     private static Vector blendFilesToVector( Vector v, String[] files )
 505  
     {
 506  
 
 507  0
         for ( int i = 0; i < files.length; ++i )
 508  
         {
 509  0
             v.addElement( files[i] );
 510  
         }
 511  
 
 512  0
         return v;
 513  
     }
 514  
 
 515  
     /**
 516  
      * Checks to see if a file is of a particular type(s).
 517  
      * Note that if the file does not have an extension, an empty string
 518  
      * (&quot;&quot;) is matched for.
 519  
      */
 520  
     private static boolean isValidFile( String file, String[] extensions )
 521  
     {
 522  
 
 523  0
         String extension = extension( file );
 524  0
         if ( extension == null )
 525  
         {
 526  0
             extension = "";
 527  
         }
 528  
 
 529  
         //ok.. now that we have the "extension" go through the current know
 530  
         //excepted extensions and determine if this one is OK.
 531  
 
 532  0
         for ( int i = 0; i < extensions.length; ++i )
 533  
         {
 534  0
             if ( extensions[i].equals( extension ) )
 535  
             {
 536  0
                 return true;
 537  
             }
 538  
         }
 539  
 
 540  0
         return false;
 541  
 
 542  
     }
 543  
 
 544  
     /**
 545  
      * Simple way to make a directory
 546  
      */
 547  
     public static void mkdir( String dir )
 548  
     {
 549  0
         File file = new File( dir );
 550  0
         if ( !file.exists() )
 551  
         {
 552  0
             file.mkdirs();
 553  
         }
 554  0
     }
 555  
 
 556  
     /**
 557  
      * Compare the contents of two files to determine if they are equal or not.
 558  
      *
 559  
      * @param file1 the first file
 560  
      * @param file2 the second file
 561  
      * @return true if the content of the files are equal or they both don't exist, false otherwise
 562  
      */
 563  
     public static boolean contentEquals( final File file1, final File file2 )
 564  
         throws IOException
 565  
     {
 566  0
         final boolean file1Exists = file1.exists();
 567  0
         if ( file1Exists != file2.exists() )
 568  
         {
 569  0
             return false;
 570  
         }
 571  
 
 572  0
         if ( !file1Exists )
 573  
         {
 574  
             // two not existing files are equal
 575  0
             return true;
 576  
         }
 577  
 
 578  0
         if ( file1.isDirectory() || file2.isDirectory() )
 579  
         {
 580  
             // don't want to compare directory contents
 581  0
             return false;
 582  
         }
 583  
 
 584  0
         InputStream input1 = null;
 585  0
         InputStream input2 = null;
 586  
         try
 587  
         {
 588  0
             input1 = new FileInputStream( file1 );
 589  0
             input2 = new FileInputStream( file2 );
 590  0
             return IOUtil.contentEquals( input1, input2 );
 591  
 
 592  
         }
 593  
         finally
 594  
         {
 595  0
             IOUtil.close( input1 );
 596  0
             IOUtil.close( input2 );
 597  
         }
 598  
     }
 599  
 
 600  
     /**
 601  
      * Convert from a <code>URL</code> to a <code>File</code>.
 602  
      *
 603  
      * @param url File URL.
 604  
      * @return The equivalent <code>File</code> object, or <code>null</code> if the URL's protocol
 605  
      *         is not <code>file</code>
 606  
      */
 607  
     public static File toFile( final URL url )
 608  
     {
 609  0
         if ( url.getProtocol().equals( "file" ) == false )
 610  
         {
 611  0
             return null;
 612  
         }
 613  
         else
 614  
         {
 615  0
             final String filename = url.getFile().replace( '/', File.separatorChar );
 616  0
             return new File( filename );
 617  
         }
 618  
     }
 619  
 
 620  
     /**
 621  
      * Convert the array of Files into a list of URLs.
 622  
      *
 623  
      * @param files the array of files
 624  
      * @return the array of URLs
 625  
      * @throws IOException if an error occurs
 626  
      */
 627  
     public static URL[] toURLs( final File[] files )
 628  
         throws IOException
 629  
     {
 630  0
         final URL[] urls = new URL[files.length];
 631  
 
 632  0
         for ( int i = 0; i < urls.length; i++ )
 633  
         {
 634  0
             urls[i] = files[i].toURL();
 635  
         }
 636  
 
 637  0
         return urls;
 638  
     }
 639  
 
 640  
     /**
 641  
      * Remove extension from filename.
 642  
      * ie
 643  
      * <pre>
 644  
      * foo.txt    --> foo
 645  
      * a\b\c.jpg --> a\b\c
 646  
      * a\b\c     --> a\b\c
 647  
      * </pre>
 648  
      *
 649  
      * @param filename the filename
 650  
      * @return the filename minus extension
 651  
      */
 652  
     public static String removeExtension( final String filename )
 653  
     {
 654  0
         final int index = filename.lastIndexOf( '.' );
 655  
 
 656  0
         if ( -1 == index )
 657  
         {
 658  0
             return filename;
 659  
         }
 660  
         else
 661  
         {
 662  0
             return filename.substring( 0, index );
 663  
         }
 664  
     }
 665  
 
 666  
     /**
 667  
      * Get extension from filename.
 668  
      * ie
 669  
      * <pre>
 670  
      * foo.txt    --> "txt"
 671  
      * a\b\c.jpg --> "jpg"
 672  
      * a\b\c     --> ""
 673  
      * </pre>
 674  
      *
 675  
      * @param filename the filename
 676  
      * @return the extension of filename or "" if none
 677  
      */
 678  
     public static String getExtension( final String filename )
 679  
     {
 680  0
         final int index = filename.lastIndexOf( '.' );
 681  
 
 682  0
         if ( -1 == index )
 683  
         {
 684  0
             return "";
 685  
         }
 686  
         else
 687  
         {
 688  0
             return filename.substring( index + 1 );
 689  
         }
 690  
     }
 691  
 
 692  
     /**
 693  
      * Remove path from filename. Equivalent to the unix command <code>basename</code>
 694  
      * ie.
 695  
      * <pre>
 696  
      * a/b/c.txt --> c.txt
 697  
      * a.txt     --> a.txt
 698  
      * </pre>
 699  
      *
 700  
      * @param filepath the filepath
 701  
      * @return the filename minus path
 702  
      */
 703  
     public static String removePath( final String filepath )
 704  
     {
 705  0
         return removePath( filepath, File.separatorChar );
 706  
     }
 707  
 
 708  
     /**
 709  
      * Remove path from filename.
 710  
      * ie.
 711  
      * <pre>
 712  
      * a/b/c.txt --> c.txt
 713  
      * a.txt     --> a.txt
 714  
      * </pre>
 715  
      *
 716  
      * @param filepath the filepath
 717  
      * @return the filename minus path
 718  
      */
 719  
     public static String removePath( final String filepath, final char fileSeparatorChar )
 720  
     {
 721  0
         final int index = filepath.lastIndexOf( fileSeparatorChar );
 722  
 
 723  0
         if ( -1 == index )
 724  
         {
 725  0
             return filepath;
 726  
         }
 727  
         else
 728  
         {
 729  0
             return filepath.substring( index + 1 );
 730  
         }
 731  
     }
 732  
 
 733  
     /**
 734  
      * Get path from filename. Roughly equivalent to the unix command <code>dirname</code>.
 735  
      * ie.
 736  
      * <pre>
 737  
      * a/b/c.txt --> a/b
 738  
      * a.txt     --> ""
 739  
      * </pre>
 740  
      *
 741  
      * @param filepath the filepath
 742  
      * @return the filename minus path
 743  
      */
 744  
     public static String getPath( final String filepath )
 745  
     {
 746  0
         return getPath( filepath, File.separatorChar );
 747  
     }
 748  
 
 749  
     /**
 750  
      * Get path from filename.
 751  
      * ie.
 752  
      * <pre>
 753  
      * a/b/c.txt --> a/b
 754  
      * a.txt     --> ""
 755  
      * </pre>
 756  
      *
 757  
      * @param filepath the filepath
 758  
      * @return the filename minus path
 759  
      */
 760  
     public static String getPath( final String filepath, final char fileSeparatorChar )
 761  
     {
 762  0
         final int index = filepath.lastIndexOf( fileSeparatorChar );
 763  0
         if ( -1 == index )
 764  
         {
 765  0
             return "";
 766  
         }
 767  
         else
 768  
         {
 769  0
             return filepath.substring( 0, index );
 770  
         }
 771  
     }
 772  
 
 773  
     /**
 774  
      * Copy file from source to destination. If <code>destinationDirectory</code> does not exist, it
 775  
      * (and any parent directories) will be created. If a file <code>source</code> in
 776  
      * <code>destinationDirectory</code> exists, it will be overwritten.
 777  
      *
 778  
      * @param source               An existing <code>File</code> to copy.
 779  
      * @param destinationDirectory A directory to copy <code>source</code> into.
 780  
      * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
 781  
      * @throws IllegalArgumentException      if <code>destinationDirectory</code> isn't a directory.
 782  
      * @throws IOException                   if <code>source</code> does not exist, the file in
 783  
      *                                       <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
 784  
      */
 785  
     public static void copyFileToDirectory( final String source, final String destinationDirectory )
 786  
         throws IOException
 787  
     {
 788  0
         copyFileToDirectory( new File( source ), new File( destinationDirectory ) );
 789  0
     }
 790  
 
 791  
     /**
 792  
      * Copy file from source to destination only if source is newer than the target file.
 793  
      * If <code>destinationDirectory</code> does not exist, it
 794  
      * (and any parent directories) will be created. If a file <code>source</code> in
 795  
      * <code>destinationDirectory</code> exists, it will be overwritten.
 796  
      *
 797  
      * @param source               An existing <code>File</code> to copy.
 798  
      * @param destinationDirectory A directory to copy <code>source</code> into.
 799  
      * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
 800  
      * @throws IllegalArgumentException      if <code>destinationDirectory</code> isn't a directory.
 801  
      * @throws IOException                   if <code>source</code> does not exist, the file in
 802  
      *                                       <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
 803  
      */
 804  
     public static void copyFileToDirectoryIfModified( final String source, final String destinationDirectory )
 805  
         throws IOException
 806  
     {
 807  0
         copyFileToDirectoryIfModified( new File( source ), new File( destinationDirectory ) );
 808  0
     }
 809  
 
 810  
     /**
 811  
      * Copy file from source to destination. If <code>destinationDirectory</code> does not exist, it
 812  
      * (and any parent directories) will be created. If a file <code>source</code> in
 813  
      * <code>destinationDirectory</code> exists, it will be overwritten.
 814  
      *
 815  
      * @param source               An existing <code>File</code> to copy.
 816  
      * @param destinationDirectory A directory to copy <code>source</code> into.
 817  
      * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
 818  
      * @throws IllegalArgumentException      if <code>destinationDirectory</code> isn't a directory.
 819  
      * @throws IOException                   if <code>source</code> does not exist, the file in
 820  
      *                                       <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
 821  
      */
 822  
     public static void copyFileToDirectory( final File source, final File destinationDirectory )
 823  
         throws IOException
 824  
     {
 825  0
         if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() )
 826  
         {
 827  0
             throw new IllegalArgumentException( "Destination is not a directory" );
 828  
         }
 829  
 
 830  0
         copyFile( source, new File( destinationDirectory, source.getName() ) );
 831  0
     }
 832  
 
 833  
     /**
 834  
      * Copy file from source to destination only if source is newer than the target file.
 835  
      * If <code>destinationDirectory</code> does not exist, it
 836  
      * (and any parent directories) will be created. If a file <code>source</code> in
 837  
      * <code>destinationDirectory</code> exists, it will be overwritten.
 838  
      *
 839  
      * @param source               An existing <code>File</code> to copy.
 840  
      * @param destinationDirectory A directory to copy <code>source</code> into.
 841  
      * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
 842  
      * @throws IllegalArgumentException      if <code>destinationDirectory</code> isn't a directory.
 843  
      * @throws IOException                   if <code>source</code> does not exist, the file in
 844  
      *                                       <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
 845  
      */
 846  
     public static void copyFileToDirectoryIfModified( final File source, final File destinationDirectory )
 847  
         throws IOException
 848  
     {
 849  0
         if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() )
 850  
         {
 851  0
             throw new IllegalArgumentException( "Destination is not a directory" );
 852  
         }
 853  
 
 854  0
         copyFileIfModified( source, new File( destinationDirectory, source.getName() ) );
 855  0
     }
 856  
 
 857  
 
 858  
     /**
 859  
      * Copy file from source to destination. The directories up to <code>destination</code> will be
 860  
      * created if they don't already exist. <code>destination</code> will be overwritten if it
 861  
      * already exists.
 862  
      *
 863  
      * @param source      An existing non-directory <code>File</code> to copy bytes from.
 864  
      * @param destination A non-directory <code>File</code> to write bytes to (possibly
 865  
      *                    overwriting).
 866  
      * @throws IOException                   if <code>source</code> does not exist, <code>destination</code> cannot be
 867  
      *                                       written to, or an IO error occurs during copying.
 868  
      * @throws java.io.FileNotFoundException if <code>destination</code> is a directory
 869  
      *                                       (use {@link #copyFileToDirectory}).
 870  
      */
 871  
     public static void copyFile( final File source, final File destination )
 872  
         throws IOException
 873  
     {
 874  
         //check source exists
 875  0
         if ( !source.exists() )
 876  
         {
 877  0
             final String message = "File " + source + " does not exist";
 878  0
             throw new IOException( message );
 879  
         }
 880  
 
 881  
         //does destinations directory exist ?
 882  0
         if ( destination.getParentFile() != null && !destination.getParentFile().exists() )
 883  
         {
 884  0
             destination.getParentFile().mkdirs();
 885  
         }
 886  
 
 887  
         //make sure we can write to destination
 888  0
         if ( destination.exists() && !destination.canWrite() )
 889  
         {
 890  0
             final String message = "Unable to open file " + destination + " for writing.";
 891  0
             throw new IOException( message );
 892  
         }
 893  
 
 894  0
         FileInputStream input = null;
 895  0
         FileOutputStream output = null;
 896  
         try
 897  
         {
 898  0
             input = new FileInputStream( source );
 899  0
             output = new FileOutputStream( destination );
 900  0
             IOUtil.copy( input, output );
 901  
         }
 902  
         finally
 903  
         {
 904  0
             IOUtil.close( input );
 905  0
             IOUtil.close( output );
 906  0
         }
 907  
 
 908  0
         if ( source.length() != destination.length() )
 909  
         {
 910  0
             final String message = "Failed to copy full contents from " + source + " to " + destination;
 911  0
             throw new IOException( message );
 912  
         }
 913  0
     }
 914  
 
 915  
     /**
 916  
      * Copy file from source to destination only if source timestamp is later than the destination timestamp.
 917  
      * The directories up to <code>destination</code> will be created if they don't already exist.
 918  
      * <code>destination</code> will be overwritten if it already exists.
 919  
      *
 920  
      * @param source      An existing non-directory <code>File</code> to copy bytes from.
 921  
      * @param destination A non-directory <code>File</code> to write bytes to (possibly
 922  
      *                    overwriting).
 923  
      * @throws IOException                   if <code>source</code> does not exist, <code>destination</code> cannot be
 924  
      *                                       written to, or an IO error occurs during copying.
 925  
      * @throws java.io.FileNotFoundException if <code>destination</code> is a directory
 926  
      *                                       (use {@link #copyFileToDirectory}).
 927  
      */
 928  
     public static boolean copyFileIfModified( final File source, final File destination )
 929  
         throws IOException
 930  
     {
 931  0
         if ( destination.lastModified() < source.lastModified() )
 932  
         {
 933  0
             copyFile( source, destination );
 934  
 
 935  0
             return true;
 936  
         }
 937  
 
 938  0
         return false;
 939  
     }
 940  
 
 941  
     /**
 942  
      * Copies bytes from the URL <code>source</code> to a file <code>destination</code>.
 943  
      * The directories up to <code>destination</code> will be created if they don't already exist.
 944  
      * <code>destination</code> will be overwritten if it already exists.
 945  
      *
 946  
      * @param source      A <code>URL</code> to copy bytes from.
 947  
      * @param destination A non-directory <code>File</code> to write bytes to (possibly
 948  
      *                    overwriting).
 949  
      * @throws IOException if
 950  
      *                     <ul>
 951  
      *                     <li><code>source</code> URL cannot be opened</li>
 952  
      *                     <li><code>destination</code> cannot be written to</li>
 953  
      *                     <li>an IO error occurs during copying</li>
 954  
      *                     </ul>
 955  
      */
 956  
     public static void copyURLToFile( final URL source, final File destination )
 957  
         throws IOException
 958  
     {
 959  
         //does destination directory exist ?
 960  0
         if ( destination.getParentFile() != null && !destination.getParentFile().exists() )
 961  
         {
 962  0
             destination.getParentFile().mkdirs();
 963  
         }
 964  
 
 965  
         //make sure we can write to destination
 966  0
         if ( destination.exists() && !destination.canWrite() )
 967  
         {
 968  0
             final String message = "Unable to open file " + destination + " for writing.";
 969  0
             throw new IOException( message );
 970  
         }
 971  
 
 972  0
         InputStream input = null;
 973  0
         FileOutputStream output = null;
 974  
         try
 975  
         {
 976  0
             input = source.openStream();
 977  0
             output = new FileOutputStream( destination );
 978  0
             IOUtil.copy( input, output );
 979  
         }
 980  
         finally
 981  
         {
 982  0
             IOUtil.close( input );
 983  0
             IOUtil.close( output );
 984  0
         }
 985  0
     }
 986  
 
 987  
     /**
 988  
      * Normalize a path.
 989  
      * Eliminates "/../" and "/./" in a string. Returns <code>null</code> if the ..'s went past the
 990  
      * root.
 991  
      * Eg:
 992  
      * <pre>
 993  
      * /foo//               -->     /foo/
 994  
      * /foo/./              -->     /foo/
 995  
      * /foo/../bar          -->     /bar
 996  
      * /foo/../bar/         -->     /bar/
 997  
      * /foo/../bar/../baz   -->     /baz
 998  
      * //foo//./bar         -->     /foo/bar
 999  
      * /../                 -->     null
 1000  
      * </pre>
 1001  
      *
 1002  
      * @param path the path to normalize
 1003  
      * @return the normalized String, or <code>null</code> if too many ..'s.
 1004  
      */
 1005  
     public static String normalize( final String path )
 1006  
     {
 1007  0
         String normalized = path;
 1008  
         // Resolve occurrences of "//" in the normalized path
 1009  
         while ( true )
 1010  
         {
 1011  0
             int index = normalized.indexOf( "//" );
 1012  0
             if ( index < 0 )
 1013  
             {
 1014  0
                 break;
 1015  
             }
 1016  0
             normalized = normalized.substring( 0, index ) + normalized.substring( index + 1 );
 1017  0
         }
 1018  
 
 1019  
         // Resolve occurrences of "/./" in the normalized path
 1020  
         while ( true )
 1021  
         {
 1022  0
             int index = normalized.indexOf( "/./" );
 1023  0
             if ( index < 0 )
 1024  
             {
 1025  0
                 break;
 1026  
             }
 1027  0
             normalized = normalized.substring( 0, index ) + normalized.substring( index + 2 );
 1028  0
         }
 1029  
 
 1030  
         // Resolve occurrences of "/../" in the normalized path
 1031  
         while ( true )
 1032  
         {
 1033  0
             int index = normalized.indexOf( "/../" );
 1034  0
             if ( index < 0 )
 1035  
             {
 1036  0
                 break;
 1037  
             }
 1038  0
             if ( index == 0 )
 1039  
             {
 1040  0
                 return null;  // Trying to go outside our context
 1041  
             }
 1042  0
             int index2 = normalized.lastIndexOf( '/', index - 1 );
 1043  0
             normalized = normalized.substring( 0, index2 ) + normalized.substring( index + 3 );
 1044  0
         }
 1045  
 
 1046  
         // Return the normalized path that we have completed
 1047  0
         return normalized;
 1048  
     }
 1049  
 
 1050  
     /**
 1051  
      * Will concatenate 2 paths.  Paths with <code>..</code> will be
 1052  
      * properly handled.
 1053  
      * <p>Eg.,<br />
 1054  
      * <code>/a/b/c</code> + <code>d</code> = <code>/a/b/d</code><br />
 1055  
      * <code>/a/b/c</code> + <code>../d</code> = <code>/a/d</code><br />
 1056  
      * </p>
 1057  
      * <p/>
 1058  
      * Thieved from Tomcat sources...
 1059  
      *
 1060  
      * @return The concatenated paths, or null if error occurs
 1061  
      */
 1062  
     public static String catPath( final String lookupPath, final String path )
 1063  
     {
 1064  
         // Cut off the last slash and everything beyond
 1065  0
         int index = lookupPath.lastIndexOf( "/" );
 1066  0
         String lookup = lookupPath.substring( 0, index );
 1067  0
         String pth = path;
 1068  
 
 1069  
         // Deal with .. by chopping dirs off the lookup path
 1070  0
         while ( pth.startsWith( "../" ) )
 1071  
         {
 1072  0
             if ( lookup.length() > 0 )
 1073  
             {
 1074  0
                 index = lookup.lastIndexOf( "/" );
 1075  0
                 lookup = lookup.substring( 0, index );
 1076  
             }
 1077  
             else
 1078  
             {
 1079  
                 // More ..'s than dirs, return null
 1080  0
                 return null;
 1081  
             }
 1082  
 
 1083  0
             index = pth.indexOf( "../" ) + 3;
 1084  0
             pth = pth.substring( index );
 1085  
         }
 1086  
 
 1087  0
         return new StringBuffer( lookup ).append( "/" ).append( pth ).toString();
 1088  
     }
 1089  
 
 1090  
     /**
 1091  
      * Resolve a file <code>filename</code> to it's canonical form. If <code>filename</code> is
 1092  
      * relative (doesn't start with <code>/</code>), it will be resolved relative to
 1093  
      * <code>baseFile</code>, otherwise it is treated as a normal root-relative path.
 1094  
      *
 1095  
      * @param baseFile Where to resolve <code>filename</code> from, if <code>filename</code> is
 1096  
      *                 relative.
 1097  
      * @param filename Absolute or relative file path to resolve.
 1098  
      * @return The canonical <code>File</code> of <code>filename</code>.
 1099  
      */
 1100  
     public static File resolveFile( final File baseFile, String filename )
 1101  
     {
 1102  0
         String filenm = filename;
 1103  0
         if ( '/' != File.separatorChar )
 1104  
         {
 1105  0
             filenm = filename.replace( '/', File.separatorChar );
 1106  
         }
 1107  
 
 1108  0
         if ( '\\' != File.separatorChar )
 1109  
         {
 1110  0
             filenm = filename.replace( '\\', File.separatorChar );
 1111  
         }
 1112  
 
 1113  
         // deal with absolute files
 1114  0
         if ( filenm.startsWith( File.separator ) || ( Os.isFamily( "windows" ) && filenm.indexOf( ":" ) > 0 ) )
 1115  
         {
 1116  0
             File file = new File( filenm );
 1117  
 
 1118  
             try
 1119  
             {
 1120  0
                 file = file.getCanonicalFile();
 1121  
             }
 1122  0
             catch ( final IOException ioe )
 1123  
             {
 1124  0
             }
 1125  
 
 1126  0
             return file;
 1127  
         }
 1128  
         // FIXME: I'm almost certain this // removal is unnecessary, as getAbsoluteFile() strips
 1129  
         // them. However, I'm not sure about this UNC stuff. (JT)
 1130  0
         final char[] chars = filename.toCharArray();
 1131  0
         final StringBuffer sb = new StringBuffer();
 1132  
 
 1133  
         //remove duplicate file separators in succession - except
 1134  
         //on win32 at start of filename as UNC filenames can
 1135  
         //be \\AComputer\AShare\myfile.txt
 1136  0
         int start = 0;
 1137  0
         if ( '\\' == File.separatorChar )
 1138  
         {
 1139  0
             sb.append( filenm.charAt( 0 ) );
 1140  0
             start++;
 1141  
         }
 1142  
 
 1143  0
         for ( int i = start; i < chars.length; i++ )
 1144  
         {
 1145  0
             final boolean doubleSeparator = File.separatorChar == chars[i] && File.separatorChar == chars[i - 1];
 1146  
 
 1147  0
             if ( !doubleSeparator )
 1148  
             {
 1149  0
                 sb.append( chars[i] );
 1150  
             }
 1151  
         }
 1152  
 
 1153  0
         filenm = sb.toString();
 1154  
 
 1155  
         //must be relative
 1156  0
         File file = ( new File( baseFile, filenm ) ).getAbsoluteFile();
 1157  
 
 1158  
         try
 1159  
         {
 1160  0
             file = file.getCanonicalFile();
 1161  
         }
 1162  0
         catch ( final IOException ioe )
 1163  
         {
 1164  0
         }
 1165  
 
 1166  0
         return file;
 1167  
     }
 1168  
 
 1169  
     /**
 1170  
      * Delete a file. If file is directory delete it and all sub-directories.
 1171  
      */
 1172  
     public static void forceDelete( final String file )
 1173  
         throws IOException
 1174  
     {
 1175  0
         forceDelete( new File( file ) );
 1176  0
     }
 1177  
 
 1178  
     /**
 1179  
      * Delete a file. If file is directory delete it and all sub-directories.
 1180  
      */
 1181  
     public static void forceDelete( final File file )
 1182  
         throws IOException
 1183  
     {
 1184  0
         if ( file.isDirectory() )
 1185  
         {
 1186  0
             deleteDirectory( file );
 1187  
         }
 1188  
         else
 1189  
         {
 1190  
             /*
 1191  
              * NOTE: Always try to delete the file even if it appears to be non-existent. This will ensure that a
 1192  
              * symlink whose target does not exist is deleted, too.
 1193  
              */
 1194  0
             boolean filePresent = file.getCanonicalFile().exists();
 1195  0
             if ( !deleteFile( file ) && filePresent )
 1196  
             {
 1197  0
                 final String message = "File " + file + " unable to be deleted.";
 1198  0
                 throw new IOException( message );
 1199  
             }
 1200  
         }
 1201  0
     }
 1202  
 
 1203  
     /**
 1204  
      * Accommodate Windows bug encountered in both Sun and IBM JDKs.
 1205  
      * Others possible. If the delete does not work, call System.gc(),
 1206  
      * wait a little and try again.
 1207  
      */
 1208  
     private static boolean deleteFile( File file )
 1209  
         throws IOException
 1210  
     {
 1211  0
         if ( file.isDirectory() )
 1212  
         {
 1213  0
             throw new IOException( "File " + file + " isn't a file." );
 1214  
         }
 1215  
 
 1216  0
         if ( !file.delete() )
 1217  
         {
 1218  0
             if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
 1219  
             {
 1220  0
                 System.gc();
 1221  
             }
 1222  
 
 1223  
             try
 1224  
             {
 1225  0
                 Thread.sleep( 10 );
 1226  0
                 return file.delete();
 1227  
             }
 1228  0
             catch ( InterruptedException ex )
 1229  
             {
 1230  0
                 return file.delete();
 1231  
             }
 1232  
         }
 1233  
 
 1234  0
         return true;
 1235  
     }
 1236  
 
 1237  
     /**
 1238  
      * Schedule a file to be deleted when JVM exits.
 1239  
      * If file is directory delete it and all sub-directories.
 1240  
      */
 1241  
     public static void forceDeleteOnExit( final File file )
 1242  
         throws IOException
 1243  
     {
 1244  0
         if ( !file.exists() )
 1245  
         {
 1246  0
             return;
 1247  
         }
 1248  
 
 1249  0
         if ( file.isDirectory() )
 1250  
         {
 1251  0
             deleteDirectoryOnExit( file );
 1252  
         }
 1253  
         else
 1254  
         {
 1255  0
             file.deleteOnExit();
 1256  
         }
 1257  0
     }
 1258  
 
 1259  
     /**
 1260  
      * Recursively schedule directory for deletion on JVM exit.
 1261  
      */
 1262  
     private static void deleteDirectoryOnExit( final File directory )
 1263  
         throws IOException
 1264  
     {
 1265  0
         if ( !directory.exists() )
 1266  
         {
 1267  0
             return;
 1268  
         }
 1269  
 
 1270  0
         cleanDirectoryOnExit( directory );
 1271  0
         directory.deleteOnExit();
 1272  0
     }
 1273  
 
 1274  
     /**
 1275  
      * Clean a directory without deleting it.
 1276  
      */
 1277  
     private static void cleanDirectoryOnExit( final File directory )
 1278  
         throws IOException
 1279  
     {
 1280  0
         if ( !directory.exists() )
 1281  
         {
 1282  0
             final String message = directory + " does not exist";
 1283  0
             throw new IllegalArgumentException( message );
 1284  
         }
 1285  
 
 1286  0
         if ( !directory.isDirectory() )
 1287  
         {
 1288  0
             final String message = directory + " is not a directory";
 1289  0
             throw new IllegalArgumentException( message );
 1290  
         }
 1291  
 
 1292  0
         IOException exception = null;
 1293  
 
 1294  0
         final File[] files = directory.listFiles();
 1295  0
         for ( int i = 0; i < files.length; i++ )
 1296  
         {
 1297  0
             final File file = files[i];
 1298  
             try
 1299  
             {
 1300  0
                 forceDeleteOnExit( file );
 1301  
             }
 1302  0
             catch ( final IOException ioe )
 1303  
             {
 1304  0
                 exception = ioe;
 1305  0
             }
 1306  
         }
 1307  
 
 1308  0
         if ( null != exception )
 1309  
         {
 1310  0
             throw exception;
 1311  
         }
 1312  0
     }
 1313  
 
 1314  
 
 1315  
     /**
 1316  
      * Make a directory. If there already exists a file with specified name or
 1317  
      * the directory is unable to be created then an exception is thrown.
 1318  
      */
 1319  
     public static void forceMkdir( final File file )
 1320  
         throws IOException
 1321  
     {
 1322  0
         if ( file.exists() )
 1323  
         {
 1324  0
             if ( file.isFile() )
 1325  
             {
 1326  0
                 final String message =
 1327  
                     "File " + file + " exists and is " + "not a directory. Unable to create directory.";
 1328  0
                 throw new IOException( message );
 1329  
             }
 1330  
         }
 1331  
         else
 1332  
         {
 1333  0
             if ( false == file.mkdirs() )
 1334  
             {
 1335  0
                 final String message = "Unable to create directory " + file;
 1336  0
                 throw new IOException( message );
 1337  
             }
 1338  
         }
 1339  0
     }
 1340  
 
 1341  
     /**
 1342  
      * Recursively delete a directory.
 1343  
      */
 1344  
     public static void deleteDirectory( final String directory )
 1345  
         throws IOException
 1346  
     {
 1347  0
         deleteDirectory( new File( directory ) );
 1348  0
     }
 1349  
 
 1350  
     /**
 1351  
      * Recursively delete a directory.
 1352  
      */
 1353  
     public static void deleteDirectory( final File directory )
 1354  
         throws IOException
 1355  
     {
 1356  0
         if ( !directory.exists() )
 1357  
         {
 1358  0
             return;
 1359  
         }
 1360  
 
 1361  0
         cleanDirectory( directory );
 1362  0
         if ( !directory.delete() )
 1363  
         {
 1364  0
             final String message = "Directory " + directory + " unable to be deleted.";
 1365  0
             throw new IOException( message );
 1366  
         }
 1367  0
     }
 1368  
 
 1369  
     /**
 1370  
      * Clean a directory without deleting it.
 1371  
      */
 1372  
     public static void cleanDirectory( final String directory )
 1373  
         throws IOException
 1374  
     {
 1375  0
         cleanDirectory( new File( directory ) );
 1376  0
     }
 1377  
 
 1378  
     /**
 1379  
      * Clean a directory without deleting it.
 1380  
      */
 1381  
     public static void cleanDirectory( final File directory )
 1382  
         throws IOException
 1383  
     {
 1384  0
         if ( !directory.exists() )
 1385  
         {
 1386  0
             final String message = directory + " does not exist";
 1387  0
             throw new IllegalArgumentException( message );
 1388  
         }
 1389  
 
 1390  0
         if ( !directory.isDirectory() )
 1391  
         {
 1392  0
             final String message = directory + " is not a directory";
 1393  0
             throw new IllegalArgumentException( message );
 1394  
         }
 1395  
 
 1396  0
         IOException exception = null;
 1397  
 
 1398  0
         final File[] files = directory.listFiles();
 1399  
 
 1400  0
         if ( files == null )
 1401  
         {
 1402  0
             return;
 1403  
         }
 1404  
 
 1405  0
         for ( int i = 0; i < files.length; i++ )
 1406  
         {
 1407  0
             final File file = files[i];
 1408  
             try
 1409  
             {
 1410  0
                 forceDelete( file );
 1411  
             }
 1412  0
             catch ( final IOException ioe )
 1413  
             {
 1414  0
                 exception = ioe;
 1415  0
             }
 1416  
         }
 1417  
 
 1418  0
         if ( null != exception )
 1419  
         {
 1420  0
             throw exception;
 1421  
         }
 1422  0
     }
 1423  
 
 1424  
     /**
 1425  
      * Recursively count size of a directory.
 1426  
      *
 1427  
      * @return size of directory in bytes.
 1428  
      */
 1429  
     public static long sizeOfDirectory( final String directory )
 1430  
     {
 1431  0
         return sizeOfDirectory( new File( directory ) );
 1432  
     }
 1433  
 
 1434  
     /**
 1435  
      * Recursively count size of a directory.
 1436  
      *
 1437  
      * @return size of directory in bytes.
 1438  
      */
 1439  
     public static long sizeOfDirectory( final File directory )
 1440  
     {
 1441  0
         if ( !directory.exists() )
 1442  
         {
 1443  0
             final String message = directory + " does not exist";
 1444  0
             throw new IllegalArgumentException( message );
 1445  
         }
 1446  
 
 1447  0
         if ( !directory.isDirectory() )
 1448  
         {
 1449  0
             final String message = directory + " is not a directory";
 1450  0
             throw new IllegalArgumentException( message );
 1451  
         }
 1452  
 
 1453  0
         long size = 0;
 1454  
 
 1455  0
         final File[] files = directory.listFiles();
 1456  0
         for ( int i = 0; i < files.length; i++ )
 1457  
         {
 1458  0
             final File file = files[i];
 1459  
 
 1460  0
             if ( file.isDirectory() )
 1461  
             {
 1462  0
                 size += sizeOfDirectory( file );
 1463  
             }
 1464  
             else
 1465  
             {
 1466  0
                 size += file.length();
 1467  
             }
 1468  
         }
 1469  
 
 1470  0
         return size;
 1471  
     }
 1472  
 
 1473  
     /**
 1474  
      * Return the files contained in the directory, using inclusion and exclusion Ant patterns,
 1475  
      * including the directory name in each of the files
 1476  
      *
 1477  
      * @param directory the directory to scan
 1478  
      * @param includes  the includes pattern, comma separated
 1479  
      * @param excludes  the excludes pattern, comma separated
 1480  
      * @return a list of File objects
 1481  
      * @throws IOException
 1482  
      */
 1483  
     public static List getFiles( File directory, String includes, String excludes )
 1484  
         throws IOException
 1485  
     {
 1486  0
         return getFiles( directory, includes, excludes, true );
 1487  
     }
 1488  
 
 1489  
     /**
 1490  
      * Return the files contained in the directory, using inclusion and exclusion Ant patterns
 1491  
      *
 1492  
      * @param directory      the directory to scan
 1493  
      * @param includes       the includes pattern, comma separated
 1494  
      * @param excludes       the excludes pattern, comma separated
 1495  
      * @param includeBasedir true to include the base dir in each file
 1496  
      * @return a list of File objects
 1497  
      * @throws IOException
 1498  
      */
 1499  
     public static List getFiles( File directory, String includes, String excludes, boolean includeBasedir )
 1500  
         throws IOException
 1501  
     {
 1502  0
         List fileNames = getFileNames( directory, includes, excludes, includeBasedir );
 1503  
 
 1504  0
         List files = new ArrayList();
 1505  
 
 1506  0
         for ( Iterator i = fileNames.iterator(); i.hasNext(); )
 1507  
         {
 1508  0
             files.add( new File( (String) i.next() ) );
 1509  
         }
 1510  
 
 1511  0
         return files;
 1512  
     }
 1513  
 
 1514  
     /**
 1515  
      * Return a list of files as String depending options.
 1516  
      * This method use case sensitive file name.
 1517  
      *
 1518  
      * @param directory      the directory to scan
 1519  
      * @param includes       the includes pattern, comma separated
 1520  
      * @param excludes       the excludes pattern, comma separated
 1521  
      * @param includeBasedir true to include the base dir in each String of file
 1522  
      * @return a list of files as String
 1523  
      * @throws IOException
 1524  
      */
 1525  
     public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir )
 1526  
         throws IOException
 1527  
     {
 1528  0
         return getFileNames( directory, includes, excludes, includeBasedir, true );
 1529  
     }
 1530  
 
 1531  
     /**
 1532  
      * Return a list of files as String depending options.
 1533  
      *
 1534  
      * @param directory       the directory to scan
 1535  
      * @param includes        the includes pattern, comma separated
 1536  
      * @param excludes        the excludes pattern, comma separated
 1537  
      * @param includeBasedir  true to include the base dir in each String of file
 1538  
      * @param isCaseSensitive true if case sensitive
 1539  
      * @return a list of files as String
 1540  
      * @throws IOException
 1541  
      */
 1542  
     public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir,
 1543  
                                      boolean isCaseSensitive )
 1544  
         throws IOException
 1545  
     {
 1546  0
         return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, true, false );
 1547  
     }
 1548  
 
 1549  
     /**
 1550  
      * Return a list of directories as String depending options.
 1551  
      * This method use case sensitive file name.
 1552  
      *
 1553  
      * @param directory      the directory to scan
 1554  
      * @param includes       the includes pattern, comma separated
 1555  
      * @param excludes       the excludes pattern, comma separated
 1556  
      * @param includeBasedir true to include the base dir in each String of file
 1557  
      * @return a list of directories as String
 1558  
      * @throws IOException
 1559  
      */
 1560  
     public static List getDirectoryNames( File directory, String includes, String excludes, boolean includeBasedir )
 1561  
         throws IOException
 1562  
     {
 1563  0
         return getDirectoryNames( directory, includes, excludes, includeBasedir, true );
 1564  
     }
 1565  
 
 1566  
     /**
 1567  
      * Return a list of directories as String depending options.
 1568  
      *
 1569  
      * @param directory       the directory to scan
 1570  
      * @param includes        the includes pattern, comma separated
 1571  
      * @param excludes        the excludes pattern, comma separated
 1572  
      * @param includeBasedir  true to include the base dir in each String of file
 1573  
      * @param isCaseSensitive true if case sensitive
 1574  
      * @return a list of directories as String
 1575  
      * @throws IOException
 1576  
      */
 1577  
     public static List getDirectoryNames( File directory, String includes, String excludes, boolean includeBasedir,
 1578  
                                           boolean isCaseSensitive )
 1579  
         throws IOException
 1580  
     {
 1581  0
         return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, false, true );
 1582  
     }
 1583  
 
 1584  
     /**
 1585  
      * Return a list of files as String depending options.
 1586  
      *
 1587  
      * @param directory       the directory to scan
 1588  
      * @param includes        the includes pattern, comma separated
 1589  
      * @param excludes        the excludes pattern, comma separated
 1590  
      * @param includeBasedir  true to include the base dir in each String of file
 1591  
      * @param isCaseSensitive true if case sensitive
 1592  
      * @param getFiles        true if get files
 1593  
      * @param getDirectories  true if get directories
 1594  
      * @return a list of files as String
 1595  
      * @throws IOException
 1596  
      */
 1597  
     public static List getFileAndDirectoryNames( File directory, String includes, String excludes,
 1598  
                                                  boolean includeBasedir, boolean isCaseSensitive, boolean getFiles,
 1599  
                                                  boolean getDirectories )
 1600  
         throws IOException
 1601  
     {
 1602  0
         DirectoryScanner scanner = new DirectoryScanner();
 1603  
 
 1604  0
         scanner.setBasedir( directory );
 1605  
 
 1606  0
         if ( includes != null )
 1607  
         {
 1608  0
             scanner.setIncludes( StringUtils.split( includes, "," ) );
 1609  
         }
 1610  
 
 1611  0
         if ( excludes != null )
 1612  
         {
 1613  0
             scanner.setExcludes( StringUtils.split( excludes, "," ) );
 1614  
         }
 1615  
 
 1616  0
         scanner.setCaseSensitive( isCaseSensitive );
 1617  
 
 1618  0
         scanner.scan();
 1619  
 
 1620  0
         List list = new ArrayList();
 1621  
 
 1622  0
         if ( getFiles )
 1623  
         {
 1624  0
             String[] files = scanner.getIncludedFiles();
 1625  
 
 1626  0
             for ( int i = 0; i < files.length; i++ )
 1627  
             {
 1628  0
                 if ( includeBasedir )
 1629  
                 {
 1630  0
                     list.add( directory + FileUtils.FS + files[i] );
 1631  
                 }
 1632  
                 else
 1633  
                 {
 1634  0
                     list.add( files[i] );
 1635  
                 }
 1636  
             }
 1637  
         }
 1638  
 
 1639  0
         if ( getDirectories )
 1640  
         {
 1641  0
             String[] directories = scanner.getIncludedDirectories();
 1642  
 
 1643  0
             for ( int i = 0; i < directories.length; i++ )
 1644  
             {
 1645  0
                 if ( includeBasedir )
 1646  
                 {
 1647  0
                     list.add( directory + FileUtils.FS + directories[i] );
 1648  
                 }
 1649  
                 else
 1650  
                 {
 1651  0
                     list.add( directories[i] );
 1652  
                 }
 1653  
             }
 1654  
         }
 1655  
 
 1656  0
         return list;
 1657  
     }
 1658  
 
 1659  
     public static void copyDirectory( File sourceDirectory, File destinationDirectory )
 1660  
         throws IOException
 1661  
     {
 1662  0
         copyDirectory( sourceDirectory, destinationDirectory, "**", null );
 1663  0
     }
 1664  
 
 1665  
     public static void copyDirectory( File sourceDirectory, File destinationDirectory, String includes,
 1666  
                                       String excludes )
 1667  
         throws IOException
 1668  
     {
 1669  0
         if ( !sourceDirectory.exists() )
 1670  
         {
 1671  0
             return;
 1672  
         }
 1673  
 
 1674  0
         List files = getFiles( sourceDirectory, includes, excludes );
 1675  
 
 1676  0
         for ( Iterator i = files.iterator(); i.hasNext(); )
 1677  
         {
 1678  0
             File file = (File) i.next();
 1679  
 
 1680  0
             copyFileToDirectory( file, destinationDirectory );
 1681  0
         }
 1682  0
     }
 1683  
 
 1684  
     /**
 1685  
      * Copies a entire directory structure.
 1686  
      * <p/>
 1687  
      * Note:
 1688  
      * <ul>
 1689  
      * <li>It will include empty directories.
 1690  
      * <li>The <code>sourceDirectory</code> must exists.
 1691  
      * </ul>
 1692  
      *
 1693  
      * @param sourceDirectory
 1694  
      * @param destinationDirectory
 1695  
      * @throws IOException
 1696  
      */
 1697  
     public static void copyDirectoryStructure( File sourceDirectory, File destinationDirectory )
 1698  
         throws IOException
 1699  
     {
 1700  0
         copyDirectoryStructure( sourceDirectory, destinationDirectory, destinationDirectory, false );
 1701  0
     }
 1702  
 
 1703  
     /**
 1704  
      * Copies an entire directory structure but only source files with timestamp later than the destinations'.
 1705  
      * <p/>
 1706  
      * Note:
 1707  
      * <ul>
 1708  
      * <li>It will include empty directories.
 1709  
      * <li>The <code>sourceDirectory</code> must exists.
 1710  
      * </ul>
 1711  
      *
 1712  
      * @param sourceDirectory
 1713  
      * @param destinationDirectory
 1714  
      * @throws IOException
 1715  
      */
 1716  
     public static void copyDirectoryStructureIfModified( File sourceDirectory, File destinationDirectory )
 1717  
         throws IOException
 1718  
     {
 1719  0
         copyDirectoryStructure( sourceDirectory, destinationDirectory, destinationDirectory, true );
 1720  0
     }
 1721  
 
 1722  
     private static void copyDirectoryStructure( File sourceDirectory, File destinationDirectory,
 1723  
                                                 File rootDestinationDirectory, boolean onlyModifiedFiles )
 1724  
         throws IOException
 1725  
     {
 1726  0
         if ( sourceDirectory == null )
 1727  
         {
 1728  0
             throw new IOException( "source directory can't be null." );
 1729  
         }
 1730  
 
 1731  0
         if ( destinationDirectory == null )
 1732  
         {
 1733  0
             throw new IOException( "destination directory can't be null." );
 1734  
         }
 1735  
 
 1736  0
         if ( sourceDirectory.equals( destinationDirectory ) )
 1737  
         {
 1738  0
             throw new IOException( "source and destination are the same directory." );
 1739  
         }
 1740  
 
 1741  0
         if ( !sourceDirectory.exists() )
 1742  
         {
 1743  0
             throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." );
 1744  
         }
 1745  
 
 1746  0
         File[] files = sourceDirectory.listFiles();
 1747  
 
 1748  0
         String sourcePath = sourceDirectory.getAbsolutePath();
 1749  
 
 1750  0
         for ( int i = 0; i < files.length; i++ )
 1751  
         {
 1752  0
             File file = files[i];
 1753  
 
 1754  0
             if ( file.equals( rootDestinationDirectory ) )
 1755  
             {
 1756  
                 // We don't copy the destination directory in itself
 1757  0
                 continue;
 1758  
             }
 1759  
 
 1760  0
             String dest = file.getAbsolutePath();
 1761  
 
 1762  0
             dest = dest.substring( sourcePath.length() + 1 );
 1763  
 
 1764  0
             File destination = new File( destinationDirectory, dest );
 1765  
 
 1766  0
             if ( file.isFile() )
 1767  
             {
 1768  0
                 destination = destination.getParentFile();
 1769  
 
 1770  0
                 if ( onlyModifiedFiles )
 1771  
                 {
 1772  0
                     copyFileToDirectoryIfModified( file, destination );
 1773  
                 }
 1774  
                 else
 1775  
                 {
 1776  0
                     copyFileToDirectory( file, destination );
 1777  
                 }
 1778  
             }
 1779  0
             else if ( file.isDirectory() )
 1780  
             {
 1781  0
                 if ( !destination.exists() && !destination.mkdirs() )
 1782  
                 {
 1783  0
                     throw new IOException(
 1784  
                         "Could not create destination directory '" + destination.getAbsolutePath() + "'." );
 1785  
                 }
 1786  
 
 1787  0
                 copyDirectoryStructure( file, destination, rootDestinationDirectory, onlyModifiedFiles );
 1788  
             }
 1789  
             else
 1790  
             {
 1791  0
                 throw new IOException( "Unknown file type: " + file.getAbsolutePath() );
 1792  
             }
 1793  
         }
 1794  0
     }
 1795  
 
 1796  
     /**
 1797  
      * Renames a file, even if that involves crossing file system boundaries.
 1798  
      * <p/>
 1799  
      * <p>This will remove <code>to</code> (if it exists), ensure that
 1800  
      * <code>to</code>'s parent directory exists and move
 1801  
      * <code>from</code>, which involves deleting <code>from</code> as
 1802  
      * well.</p>
 1803  
      *
 1804  
      * @param from the file to move
 1805  
      * @param to   the new file name
 1806  
      * @throws IOException if anything bad happens during this
 1807  
      *                     process.  Note that <code>to</code> may have been deleted
 1808  
      *                     already when this happens.
 1809  
      */
 1810  
     public static void rename( File from, File to )
 1811  
         throws IOException
 1812  
     {
 1813  0
         if ( to.exists() && !to.delete() )
 1814  
         {
 1815  0
             throw new IOException( "Failed to delete " + to + " while trying to rename " + from );
 1816  
         }
 1817  
 
 1818  0
         File parent = to.getParentFile();
 1819  0
         if ( parent != null && !parent.exists() && !parent.mkdirs() )
 1820  
         {
 1821  0
             throw new IOException( "Failed to create directory " + parent + " while trying to rename " + from );
 1822  
         }
 1823  
 
 1824  0
         if ( !from.renameTo( to ) )
 1825  
         {
 1826  0
             copyFile( from, to );
 1827  0
             if ( !from.delete() )
 1828  
             {
 1829  0
                 throw new IOException( "Failed to delete " + from + " while trying to rename it." );
 1830  
             }
 1831  
         }
 1832  0
     }
 1833  
 
 1834  
     /**
 1835  
      * Create a temporary file in a given directory.
 1836  
      * <p/>
 1837  
      * <p>The file denoted by the returned abstract pathname did not
 1838  
      * exist before this method was invoked, any subsequent invocation
 1839  
      * of this method will yield a different file name.</p>
 1840  
      * <p/>
 1841  
      * The filename is prefixNNNNNsuffix where NNNN is a random number
 1842  
      * </p>
 1843  
      * <p>This method is different to File.createTempFile of JDK 1.2
 1844  
      * as it doesn't create the file itself.
 1845  
      * It uses the location pointed to by java.io.tmpdir
 1846  
      * when the parentDir attribute is
 1847  
      * null.</p>
 1848  
      *
 1849  
      * @param prefix    prefix before the random number
 1850  
      * @param suffix    file extension; include the '.'
 1851  
      * @param parentDir Directory to create the temporary file in -
 1852  
      *                  java.io.tmpdir used if not specificed
 1853  
      * @return a File reference to the new temporary file.
 1854  
      */
 1855  
     public static File createTempFile( String prefix, String suffix, File parentDir )
 1856  
     {
 1857  
 
 1858  0
         File result = null;
 1859  0
         String parent = System.getProperty( "java.io.tmpdir" );
 1860  0
         if ( parentDir != null )
 1861  
         {
 1862  0
             parent = parentDir.getPath();
 1863  
         }
 1864  0
         DecimalFormat fmt = new DecimalFormat( "#####" );
 1865  0
         Random rand = new Random( System.currentTimeMillis() + Runtime.getRuntime().freeMemory() );
 1866  0
         synchronized ( rand )
 1867  
         {
 1868  
             do
 1869  
             {
 1870  0
                 result = new File( parent, prefix + fmt.format( Math.abs( rand.nextInt() ) ) + suffix );
 1871  
             }
 1872  0
             while ( result.exists() );
 1873  0
         }
 1874  0
         return result;
 1875  
     }
 1876  
 
 1877  
     public static void copyFile( File from, File to, String encoding, FilterWrapper[] wrappers )
 1878  
         throws IOException
 1879  
     {
 1880  0
         if ( wrappers != null && wrappers.length > 0 )
 1881  
         {
 1882  
             // buffer so it isn't reading a byte at a time!
 1883  0
             Reader fileReader = null;
 1884  0
             Writer fileWriter = null;
 1885  
             try
 1886  
             {
 1887  0
                 if ( encoding == null || encoding.length() < 1 )
 1888  
                 {
 1889  0
                     fileReader = new BufferedReader( new FileReader( from ) );
 1890  0
                     fileWriter = new FileWriter( to );
 1891  
                 }
 1892  
                 else
 1893  
                 {
 1894  0
                     FileInputStream instream = new FileInputStream( from );
 1895  
 
 1896  0
                     FileOutputStream outstream = new FileOutputStream( to );
 1897  
 
 1898  0
                     fileReader = new BufferedReader( new InputStreamReader( instream, encoding ) );
 1899  
 
 1900  0
                     fileWriter = new OutputStreamWriter( outstream, encoding );
 1901  
                 }
 1902  
 
 1903  0
                 Reader reader = fileReader;
 1904  0
                 for ( int i = 0; i < wrappers.length; i++ )
 1905  
                 {
 1906  0
                     FilterWrapper wrapper = wrappers[i];
 1907  0
                     reader = wrapper.getReader( reader );
 1908  
                 }
 1909  
 
 1910  0
                 IOUtil.copy( reader, fileWriter );
 1911  
             }
 1912  
             finally
 1913  
             {
 1914  0
                 IOUtil.close( fileReader );
 1915  0
                 IOUtil.close( fileWriter );
 1916  0
             }
 1917  0
         }
 1918  
         else
 1919  
         {
 1920  0
             if ( to.lastModified() < from.lastModified() )
 1921  
             {
 1922  0
                 copyFile( from, to );
 1923  
             }
 1924  
         }
 1925  0
     }
 1926  
 
 1927  0
     public static abstract class FilterWrapper
 1928  
     {
 1929  
         public abstract Reader getReader( Reader fileReader );
 1930  
     }
 1931  
 
 1932  
     public static List loadFile( File file ) throws IOException
 1933  
     {
 1934  0
         List lines = new ArrayList();
 1935  
 
 1936  0
         if ( file.exists() )
 1937  
         {
 1938  0
             BufferedReader reader = new BufferedReader( new FileReader( file ) );
 1939  
 
 1940  0
             String line = reader.readLine();
 1941  
 
 1942  0
             while ( line != null )
 1943  
             {
 1944  0
                 line = line.trim();
 1945  
 
 1946  0
                 if ( !line.startsWith( "#" ) && line.length() != 0 )
 1947  
                 {
 1948  0
                     lines.add ( line );
 1949  
                 }
 1950  0
                 line = reader.readLine();
 1951  
             }
 1952  
 
 1953  0
             reader.close();
 1954  
         }
 1955  
 
 1956  0
         return lines;
 1957  
     }
 1958  
 }