KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > util > io > FileUtils


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * FileUtils.java
26  *
27  * Created on November 16, 2001, 6:44 PM
28  *
29  * @author bnevins
30  *
31  * Copyright 2000-2001 by iPlanet/Sun Microsystems, Inc.,
32  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
33  * All rights reserved.
34  *
35  * This software is the confidential and proprietary information
36  * of iPlanet/Sun Microsystems, Inc. ("Confidential Information").
37  * You shall not disclose such Confidential Information and shall
38  * use it only in accordance with the terms of the license
39  * agreement you entered into with iPlanet/Sun Microsystems.
40  *
41  */

42
43 /*
44  * KEDAR/MURALI has made some changes to this class
45  * so that it works with installer(LogDomains esp.).
46 */

47
48 package com.sun.enterprise.util.io;
49
50 import java.io.*;
51 import java.text.MessageFormat JavaDoc;
52 import java.util.*;
53 //import com.sun.enterprise.util.diagnostics.Reporter;
54
//import com.sun.enterprise.util.StringUtils;
55
import com.sun.enterprise.util.OS;
56 //Bug 4677074 begin
57
import java.util.logging.Logger JavaDoc;
58 import java.util.logging.Level JavaDoc;
59 //import com.sun.logging.LogDomains;
60
//Bug 4677074 end
61

62 public class FileUtils
63 {
64     public static native int recursiveChownNative(String JavaDoc dirOrFile, String JavaDoc user);
65     public static native int recursiveChownNative(String JavaDoc dirOrFile);
66     public static native int recursiveChmodNative(String JavaDoc dirOrFile, String JavaDoc permissions);
67 //Bug 4677074 begin
68
//static Logger _logger=LogDomains.getLogger(LogDomains.UTIL_LOGGER);
69
//static Logger _logger=Logger.getLogger("javax.enterprise.system.util");
70
static Logger JavaDoc _logger=IOLogger.getLogger();
71     static Logger JavaDoc _utillogger=com.sun.logging.LogDomains.getLogger(com.sun.logging.LogDomains.UTIL_LOGGER);
72 //Bug 4677074 end
73
private FileUtils()
74     {
75     }
76
77     ///////////////////////////////////////////////////////////////////////////
78

79     public static boolean safeIsDirectory(File f)
80     {
81         if(f == null || !f.exists() || !f.isDirectory())
82             return false;
83     
84         return true;
85     }
86
87     
88     ///////////////////////////////////////////////////////////////////////////
89

90     public static boolean safeIsRealDirectory(String JavaDoc s)
91     {
92         return safeIsRealDirectory(new File(s));
93     }
94     
95     ///////////////////////////////////////////////////////////////////////////
96

97     public static boolean safeIsRealDirectory(File f)
98     {
99         if(safeIsDirectory(f) == false)
100             return false;
101         
102         
103         
104         // these 2 values while be different for symbolic links
105
String JavaDoc canonical = safeGetCanonicalPath(f);
106         String JavaDoc absolute = f.getAbsolutePath();
107         
108         if(canonical.equals(absolute))
109             return true;
110
111         /* Bug 4715043 -- WHOA -- Bug Obscura!!
112          * In Windows, if you create the File object with, say, "d:/foo", then the
113          * absolute path will be "d:\foo" and the canonical path will be "D:\foo"
114          * and they won't match!!!
115          **/

116         if(OS.isWindows() && canonical.equalsIgnoreCase(absolute))
117             return true;
118         
119         return false;
120     }
121     
122     ///////////////////////////////////////////////////////////////////////////
123

124     public static boolean safeIsDirectory(String JavaDoc s)
125     {
126         return safeIsDirectory(new File(s));
127     }
128     
129     ///////////////////////////////////////////////////////////////////////////
130

131     public static String JavaDoc safeGetCanonicalPath(File f)
132     {
133         if(f == null)
134             return null;
135         
136         try
137         {
138             return f.getCanonicalPath();
139         }
140         catch(IOException e)
141         {
142             return f.getAbsolutePath();
143         }
144     }
145     
146     ///////////////////////////////////////////////////////////////////////////
147

148     public static File safeGetCanonicalFile(File f)
149     {
150         if(f == null)
151             return null;
152         
153         try
154         {
155             return f.getCanonicalFile();
156         }
157         catch(IOException e)
158         {
159             return f.getAbsoluteFile();
160         }
161     }
162     
163     ///////////////////////////////////////////////////////////////////////////
164

165     public static boolean isEar(String JavaDoc filename)
166     {
167         return hasExtension(filename, ".ear");
168     }
169     
170     ///////////////////////////////////////////////////////////////////////////
171

172     public static boolean isJar(String JavaDoc filename)
173     {
174         return hasExtension(filename, ".jar");
175     }
176     
177     ///////////////////////////////////////////////////////////////////////////
178

179     public static boolean isZip(String JavaDoc filename)
180     {
181         return hasExtensionIgnoreCase(filename, ".zip");
182     }
183     
184     ///////////////////////////////////////////////////////////////////////////
185

186     public static boolean isArchive(String JavaDoc filename)
187     {
188         return isWar(filename) || isRar(filename) || isJar(filename) || isZip(filename) || isEar(filename);
189     }
190     
191     ///////////////////////////////////////////////////////////////////////////
192

193     public static boolean isArchive(File f)
194     {
195         return isWar(f) || isRar(f) || isJar(f) || isZip(f) || isEar(f);
196     }
197     
198     ///////////////////////////////////////////////////////////////////////////
199

200     public static boolean isWar(String JavaDoc filename)
201     {
202         return hasExtension(filename, ".war");
203     }
204     
205     ///////////////////////////////////////////////////////////////////////////
206

207     public static boolean isRar(String JavaDoc filename)
208     {
209         return hasExtension(filename, ".rar");
210     }
211     
212     ///////////////////////////////////////////////////////////////////////////
213

214     public static boolean isEar(File f)
215     {
216         return hasExtension(f, ".ear");
217     }
218     
219     ///////////////////////////////////////////////////////////////////////////
220

221     public static boolean isJar(File f)
222     {
223         return hasExtension(f, ".jar");
224     }
225     
226     ///////////////////////////////////////////////////////////////////////////
227
public static boolean isZip(File f)
228     {
229         return hasExtensionIgnoreCase(f, ".zip");
230     }
231     
232     ///////////////////////////////////////////////////////////////////////////
233

234     public static boolean isWar(File f)
235     {
236         return hasExtension(f, ".war");
237     }
238     
239     ///////////////////////////////////////////////////////////////////////////
240

241     public static boolean isRar(File f)
242     {
243         return hasExtension(f, ".rar");
244     }
245     
246     ///////////////////////////////////////////////////////////////////////////
247

248     public static boolean hasExtension(String JavaDoc filename, String JavaDoc ext)
249     {
250         if(filename == null || filename.length() <= 0)
251             return false;
252         
253         return filename.endsWith(ext);
254     }
255     
256     ///////////////////////////////////////////////////////////////////////////
257

258     public static boolean hasExtension(File f, String JavaDoc ext)
259     {
260         if(f == null || !f.exists())
261             return false;
262         
263         return f.getName().endsWith(ext);
264     }
265     
266     ///////////////////////////////////////////////////////////////////////////
267

268     public static boolean hasExtensionIgnoreCase(String JavaDoc filename, String JavaDoc ext)
269     {
270         if(filename == null || filename.length() <= 0)
271             return false;
272         
273         return filename.toLowerCase().endsWith(ext.toLowerCase());
274     }
275     
276     ///////////////////////////////////////////////////////////////////////////
277

278     public static boolean hasExtensionIgnoreCase(File f, String JavaDoc ext)
279     {
280         if(f == null || !f.exists())
281             return false;
282         
283         return f.getName().toLowerCase().endsWith(ext.toLowerCase());
284     }
285     
286     ///////////////////////////////////////////////////////////////////////////
287

288     public static boolean isLegalFilename(String JavaDoc filename)
289     {
290                 if(!isValidString(filename))
291                         return false;
292
293         for(int i = 0; i < ILLEGAL_FILENAME_CHARS.length; i++)
294             if(filename.indexOf(ILLEGAL_FILENAME_CHARS[i]) >= 0)
295                 return false;
296
297         return true;
298     }
299     
300     ///////////////////////////////////////////////////////////////////////////
301

302     public static boolean isFriendlyFilename(String JavaDoc filename)
303     {
304                 if(!isValidString(filename))
305                         return false;
306
307         if(filename.indexOf(BLANK) >= 0 || filename.indexOf(DOT) >= 0)
308             return false;
309
310         return isLegalFilename(filename);
311     }
312     
313     ///////////////////////////////////////////////////////////////////////////
314

315     public static String JavaDoc makeLegalFilename(String JavaDoc filename)
316     {
317         if(isLegalFilename(filename))
318             return filename;
319         
320         for(int i = 0; i < ILLEGAL_FILENAME_CHARS.length; i++)
321             filename = filename.replace(ILLEGAL_FILENAME_CHARS[i], REPLACEMENT_CHAR);
322         
323         return filename;
324     }
325     
326     ///////////////////////////////////////////////////////////////////////////
327

328     public static String JavaDoc makeFriendlyFileName(String JavaDoc filename)
329     {
330         // OK -- I hate having to go back in here to see if the 'N'
331
// is uppercase or lowercase. Let's have both!!
332
return makeFriendlyFilename(filename);
333     }
334     
335     ///////////////////////////////////////////////////////////////////////////
336

337     public static String JavaDoc makeFriendlyFilename(String JavaDoc filename)
338     {
339         if(isFriendlyFilename(filename))
340             return filename;
341         
342         String JavaDoc ret = makeLegalFilename(filename).replace(BLANK, REPLACEMENT_CHAR);
343         ret = ret.replace(DOT, REPLACEMENT_CHAR);
344         return ret;
345     }
346     
347     ///////////////////////////////////////////////////////////////////////////
348

349     public static String JavaDoc makeFriendlyFilenameNoExtension(String JavaDoc filename)
350     {
351         int index = filename.lastIndexOf('.');
352         
353         if(index > 0)
354             filename = filename.substring(0, index);
355         
356         return(makeFriendlyFilename(filename));
357     }
358
359         ///////////////////////////////////////////////////////////////////////////
360

361         public static String JavaDoc revertFriendlyFilenameExtension(String JavaDoc filename)
362         {
363                 if (filename == null ||
364                    !(filename.endsWith("_ear") || filename.endsWith("_war") ||
365                      filename.endsWith("_jar") || filename.endsWith("_rar")) ) {
366                     return filename;
367                 }
368
369                 String JavaDoc extension = "";
370                 if (filename.endsWith("_ear")) {
371                     filename = filename.substring(0, filename.indexOf("_ear"));
372                     extension = ".ear";
373                 } else if (filename.endsWith("_war")) {
374                     filename = filename.substring(0, filename.indexOf("_war"));
375                     extension = ".war";
376                 } else if (filename.endsWith("_jar")) {
377                     filename = filename.substring(0, filename.indexOf("_jar"));
378                     extension = ".jar";
379                 } else if (filename.endsWith("_rar")) {
380                     filename = filename.substring(0, filename.indexOf("_rar"));
381                     extension = ".rar";
382                 }
383                 return filename + extension;
384         }
385
386         public static String JavaDoc revertFriendlyFilename(String JavaDoc filename) {
387             
388             //first, revert the file extension
389
String JavaDoc name = revertFriendlyFilenameExtension(filename);
390
391             //then, revert the rest of the string
392
return name.replace(REPLACEMENT_CHAR, '/');
393         }
394
395
396     
397     ///////////////////////////////////////////////////////////////////////////
398

399     public static String JavaDoc makeFriendlyFileNameNoExtension(String JavaDoc filename)
400     {
401         // OK -- I hate having to go back in here to see if the 'N'
402
// is uppercase or lowercase. Let's have both!!
403
return makeFriendlyFilenameNoExtension(filename);
404     }
405
406     /////////////////////////////////////////////////////////
407

408     public static void liquidate(File parent)
409     {
410         whack(parent);
411     }
412
413     /////////////////////////////////////////////////////////
414

415     /**
416      *Deletes a directory and its contents.
417      *<p>
418      *If this method encounters a symbolic link in the subtree below "parent"
419      *then it deletes the link but not any of the files pointed to by the link.
420      *Note that whack will delete files if a symbolic link appears in the
421      *path above the specified parent directory in the path.
422      *@param parent the File at the top of the subtree to delete
423      *@return success or failure of deleting the directory
424      */

425     public static boolean whack(File parent)
426     {
427         try {
428             /*
429              *Resolve any links up-stream from this parent directory and
430              *then whack the resulting resolved directory.
431              */

432             return whackResolvedDirectory(parent.getCanonicalFile());
433         } catch (IOException ioe) {
434             _utillogger.log(Level.SEVERE, "iplanet_util.io_exception", ioe);
435             return false;
436         }
437     }
438
439     /**
440      *Deletes a directory and its contents.
441      *<p>
442      *The whackResolvedDirectory method is invoked with a File argument
443      *in which any upstream file system links have already been resolved.
444      *This method will treate Any file passed in that does not have the same
445      *absolute and canonical path - as evaluated in safeIsRealDirectory -
446      *as a link and will delete the link without deleting any files in the
447      *linked directory.
448      *
449      *@param parent the File at the top of the subtree to delete
450      *@return success or failure of deleting the directory
451      */

452     private static boolean whackResolvedDirectory(File parent)
453     {
454         /*
455          *Do not recursively delete the contents if the current parent
456          *is a symbolic link.
457          */

458         if (safeIsRealDirectory(parent))
459         {
460             File[] kids = parent.listFiles();
461
462             for(int i = 0; i < kids.length; i++)
463             {
464                 File f = kids[i];
465
466                 if(f.isDirectory())
467                     whackResolvedDirectory(f);
468                 else
469                     deleteFile(f);
470
471             }
472         }
473                 
474         /*
475          *Delete the directory or symbolic link.
476          */

477         return deleteFile(parent);
478     }
479         /**
480          *Delete a file. If on Windows and the delete fails, run the gc and retry the deletion.
481          *@param file to delete
482          *@return boolean indicating success or failure of the deletion atttempt; returns true if file is absent
483          */

484         public static boolean deleteFile(File f) {
485             /*
486              *The operation succeeds immediately if the file is deleted
487              *successfully. On systems that support symbolic links, the file
488              *will be reported as non-existent if the file is a sym link to a
489              *non-existent directory. In that case invoke delete to remove
490              *the link before checking for existence, since File.exists on
491              *a symlink checks for the existence of the linked-to directory or
492              *file rather than of the link itself.
493              */

494             if (f.delete()) {
495                 return true;
496             }
497             
498             boolean log = _utillogger.isLoggable(FILE_OPERATION_LOG_LEVEL);
499             String JavaDoc filePath = f.getAbsolutePath();;
500
501             /*
502              *The deletion failed. This could be simply because the file
503              *does not exist. In that case, log an appropriate message and
504              *return.
505              */

506             if ( ! f.exists()) {
507                 if (log) {
508                     _utillogger.log(Level.FINE, "enterprise_util.delete_failed_absent", filePath);
509                 }
510                 return true;
511             } else {
512                 /*
513                  *If the current platform is Windows, retry the deletion.
514                  */

515                 if (log) {
516                     _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.error_deleting_file", filePath);
517                 }
518
519                 boolean deleteOK = false;
520                 /*
521                  *Try triggering garbage collection in an attempt to force finalizers to
522                  *close their streams, allowing the next attempt at deletion to succeed.
523                  */

524                 if (OS.isWindows()) {
525                     if (log && (FILE_OPERATION_MAX_RETRIES > 0)) {
526                         _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.perform_gc");
527                     }
528                     int retries = 0;
529                     for (retries = 0; retries < FILE_OPERATION_MAX_RETRIES && ! deleteOK; retries++) {
530                         try {
531                             Thread.currentThread().sleep(FILE_OPERATION_SLEEP_DELAY_MS);
532                         } catch (InterruptedException JavaDoc ie) {
533                         }
534                         System.gc();
535                         deleteOK = f.delete();
536                     }
537                     if (log) {
538                         if (deleteOK) {
539                             _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.retry_delete_success", new Object JavaDoc [] {
540                                 filePath, new Integer JavaDoc(retries) } );
541                         } else {
542                             _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.retry_delete_failure", new Object JavaDoc [] {
543                                 filePath, new Integer JavaDoc(retries) } );
544                         }
545                     }
546                 }
547
548                 /*
549                  *If the single deletion attempt (on non-Windows systems) or the retry attempts (on Windows)
550                  *failed, mark the file for deletion on exit in hopes of having it removed then.
551                  */

552                 if ( ! deleteOK) {
553                     f.deleteOnExit();
554                     _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.delete_failed_now_deleteonexit", f.getAbsolutePath());
555                 }
556                 return deleteOK;
557             }
558          }
559          
560     ///////////////////////////////////////////////////////////////////////////
561

562     public static File getDirectory(File f)
563     {
564         String JavaDoc filename = f.getAbsolutePath();
565         return new File((new File(filename)).getParent());
566     }
567     
568     ///////////////////////////////////////////////////////////////////////////
569

570     public static File createTempFile(File directory)
571     {
572         File f = null;
573         
574         try
575         {
576             f = File.createTempFile(TMPFILENAME, "jar", directory);
577         }
578         catch (IOException ioe)
579         {
580 //Bug 4677074 ioe.printStackTrace();
581
//Bug 4677074 begin
582
_logger.log(Level.SEVERE,"iplanet_util.io_exception",ioe);
583 //Bug 4677074 end
584
}
585         
586         f.deleteOnExit(); // just in case
587
return f;
588     }
589
590     /**
591      * Returns an array of abstract pathnames that matches with the given
592      * file extension. If the given abstract pathname does not denote a
593      * directory, then this method returns null. If there is no matching
594      * file under the given directory and its sub directories,
595      * it returns null;
596      *
597      * @param dirName dir name under which search will begin
598                 
599      * @param ext file extension to look for
600      *
601      * @return an array of abstract pathnames that matches with the extension
602      */

603     public static File[] listAllFiles(File dirName, String JavaDoc ext)
604     {
605     File[] target = null;
606     List list = searchDir(dirName, ext);
607
608     if ( (list != null) && (list.size() > 0) )
609     {
610         target = new File[list.size()];
611         target = (File[]) list.toArray(target);
612     }
613
614     return target;
615     }
616
617     /**
618      * Returns a list of abstract pathnames that matches with the given
619      * file extension. If the given abstract pathname does not denote a
620      * directory, then this method returns null. If there is no matching
621      * file under the given directory and its sub directories, it returns
622      * an empty list.
623      *
624      * @param dirName dir name under which search will begin
625      * @param ext file extension to look for
626      *
627      * @return a list of abstract pathnames of type java.io.File
628      * that matches with the given extension
629      */

630     public static List searchDir(File dirName, String JavaDoc ext)
631     {
632     List targetList = null;
633
634     if (dirName.isDirectory())
635     {
636         targetList = new ArrayList();
637
638         File[] list = dirName.listFiles();
639
640         for (int i=0; i<list.length; i++)
641         {
642         if (list[i].isDirectory())
643         {
644             targetList.addAll( searchDir(list[i], ext) );
645         }
646         else
647         {
648             String JavaDoc name = list[i].toString();
649             if ( hasExtension(name, ext) )
650             {
651             targetList.add(list[i]);
652             }
653         }
654         }
655     }
656
657     return targetList;
658     }
659
660     /**
661      * Copies a file.
662      *
663      * @param from Name of file to copy
664      * @param to Name of new file
665      * @exception IOException if an error while copying the content
666      */

667     public static void copy(String JavaDoc from, String JavaDoc to) throws IOException
668     {
669         //if(!StringUtils.ok(from) || !StringUtils.ok(to))
670
if(from == null || to == null)
671             throw new IllegalArgumentException JavaDoc("null or empty filename argument");
672         
673         File fin = new File(from);
674         File fout = new File(to);
675         
676         copy(fin, fout);
677     }
678     /**
679      * Copies a file.
680      *
681      * @param from File to copy
682      * @param to New file
683      *
684      * @exception IOException if an error while copying the content
685      */

686     public static void copy(File fin, File fout) throws IOException
687     {
688         if(safeIsDirectory(fin))
689         {
690             copyTree(fin, fout);
691             return;
692         }
693         
694         if(!fin.exists())
695             throw new IllegalArgumentException JavaDoc("File source doesn't exist");
696
697         //if(fout.exists() && overwrite == false)
698
//throw new IOException("File destination exists, overwrite not specified");
699
if(!safeIsDirectory(fout.getParentFile()))
700             fout.getParentFile().mkdirs();
701         
702         copy(new FileInputStream(fin), new FileOutputStream(fout));
703     }
704     /**
705      * Copies the entire tree to a new location.
706      *
707      * @param sourceTree File pointing at root of tree to copy
708      * @param destTree File pointing at root of new tree
709      *
710      * @exception IOException if an error while copying the content
711      */

712     public static void copyTree(File din, File dout)
713         throws IOException
714     {
715         if(!safeIsDirectory(din))
716             throw new IllegalArgumentException JavaDoc("Source isn't a directory");
717         
718         dout.mkdirs();
719         
720         if(!safeIsDirectory(dout))
721             throw new IllegalArgumentException JavaDoc("Can't create destination directory");
722         
723         FileListerRelative flr = new FileListerRelative(din);
724         String JavaDoc[] files = flr.getFiles();
725         
726         for(int i = 0; i < files.length; i++)
727         {
728             File fin = new File(din, files[i]);
729             File fout = new File(dout, files[i]);
730             
731             copy(fin, fout);
732             //System.out.println("Copied " + fin.getPath() + " to " + fout.getPath());
733
//Bug 4677074 System.out.print(".");
734
//Bug 4677074 begin
735
//_logger.log(Level.FINE,"Copied " + fin.getPath() + " to "+ fout.getPath());
736
_logger.log(Level.FINE,".");
737 //Bug 4677074 end
738
}
739     }
740         
741     /**
742      * Copies the bytes from the given input stream to the output stream.
743      * It closes the streams afterwards.
744      *
745      * @param inStream input stream from the src
746      * @param outStream output stream to the destination
747      *
748      * @exception IOException if an error while copying the content
749      */

750     public static void copy(InputStream inStream, OutputStream outStream)
751         throws IOException
752     {
753     copyWithoutClose(inStream, outStream);
754
755     // closes the streams
756
inStream.close();
757     outStream.close();
758     }
759
760     /**
761      * Copies the bytes from the given input stream to the output stream.
762      * It does not close the streams afterwards.
763      *
764      * @param inStream input stream from the src
765      * @param outStream output stream to the destination
766      *
767      * @exception IOException if an error while copying the content
768      */

769     public static void copyWithoutClose(InputStream inStream,
770             OutputStream outStream) throws IOException
771     {
772         BufferedInputStream bis =
773              new BufferedInputStream(inStream, BUFFER_SIZE);
774         BufferedOutputStream bos =
775              new BufferedOutputStream(outStream, BUFFER_SIZE);
776         byte[] buf = new byte[BUFFER_SIZE];
777
778         int len = 0;
779         while (len != -1)
780         {
781             try
782             {
783                 len = bis.read(buf, 0, buf.length);
784             }
785             catch (EOFException eof)
786             {
787                 break;
788             }
789
790             if (len != -1)
791             {
792                 bos.write(buf, 0, len);
793             }
794         }
795         bos.flush();
796     }
797
798     /**
799         Returns a String with uniform slashes such that all the
800         occurances of '\\' are replaced with '/'.
801         In other words, the returned string will have all forward slashes.
802         Accepts non-null strings only.
803         @param a non null String
804         @return a String which <code> does not contain `\\` character </code>
805     */

806     public static String JavaDoc makeForwardSlashes(String JavaDoc inputStr)
807     {
808         if(inputStr == null)
809             throw new IllegalArgumentException JavaDoc("null String FileUtils.makeForwardSlashes");
810         return ( inputStr.replace('\\', '/') );
811     }
812     
813     ///////////////////////////////////////////////////////////////////////////
814

815     public static String JavaDoc getIllegalFilenameCharacters()
816     {
817         return ILLEGAL_FILENAME_STRING;
818     }
819
820     /**
821      * This version will set the owner to the current user
822      * @param dirOrFile - File or Directory to change owner
823      * @throws NativeIOException if there was an error
824      * @return a success String suitable for logging.
825      */

826     public static String JavaDoc recursiveChown(File dirOrFile) throws NativeIOException
827     {
828         return recursiveChown(dirOrFile, null);
829     }
830
831     ///////////////////////////////////////////////////////////////////////////
832

833     /**
834      * This version will set the owner to the specified user
835      * @param dirOrFile - File or Directory to change owner
836      * @throws NativeIOException if there was an error
837      * @return a success String suitable for logging.
838      */

839     public static String JavaDoc recursiveChown(File dirOrFile, String JavaDoc user) throws NativeIOException
840     {
841         if(dirOrFile == null || !dirOrFile.exists())
842             throw new NativeIOException("File doesn't exist: " + dirOrFile);
843         
844         String JavaDoc fname = dirOrFile.getAbsolutePath();
845         int ret = 0;
846         
847         if(!isValidString(user))
848             ret = recursiveChownNative(fname);
849         else
850             ret = recursiveChownNative(fname, user);
851         
852         NativeResults nr = new NativeResults(ret);
853         NativeIOException ne = nr.getResultException();
854         
855         if(ne == null)
856             return nr.getResultString();
857         else
858             throw ne;
859     }
860     /**
861      * Recursively changes the file permissions via native code.
862      * @param dirOrFile the directory or file to chmod (recursively if directory)
863      * @param permissions a String representing permissions.
864      * <p> permissions must be exactly like so:
865      * "rwxrwxrwx" which is user-group-others
866      * put a dash (or anything else) in a position that you don't want the permission set.
867      * e.g. rwx -> user, r -> group, nothing -> others
868      * "rwxr-----"
869      * @throws NativeIOException -- if there was an error
870      * @return String suitable for logging about the success
871      */

872     public static String JavaDoc recursiveChmod(File dirOrFile, String JavaDoc permissions) throws NativeIOException
873     {
874         if(dirOrFile == null || !dirOrFile.exists())
875             throw new NativeIOException("File doesn't exist: " + dirOrFile);
876         
877         if(permissions == null)
878             throw new NativeIOException("null permissions string.");
879
880         permissions = permissions.toLowerCase(); // using R,W,X should not be an error!
881
verifyPermissions(permissions);
882         
883         int ret = recursiveChmodNative(dirOrFile.getAbsolutePath(), permissions);
884         
885         NativeResults nr = new NativeResults(ret);
886         NativeIOException ne = nr.getResultException();
887
888         if(ne == null)
889             return nr.getResultString();
890         else
891             throw ne;
892     }
893
894     ///////////////////////////////////////////////////////////////////////////
895

896     static boolean isValidString(String JavaDoc s)
897     {
898         return ((s != null) && (s.length() != 0));
899     }
900
901     ///////////////////////////////////////////////////////////////////////////
902

903     /**
904      * Windows has BIG issues renaming a directory that is open somnewhere -- e.g. if
905      * a DOS box is opened anywhere in that directory.
906      * This method will try to do a "virtual renaming" if there are problems
907      * I.e. it attempts to do a simple rename, if that fails it will copy everything under
908      * the original directory to the renamed directory. Then it will delete everything
909      * under the original directory that the OS will allow it to.
910      * NOTE: if the proposed new name already exists - I will try to whack it.
911      * bnevins April 2003
912      * @returns the renamed directory-name
913      */

914     
915     public static File smartRename(File original) throws IOException
916     {
917         if(original == null)
918             throw new IllegalArgumentException JavaDoc("null argument");
919         
920         String JavaDoc originalName = original.getAbsolutePath();
921         
922         if(!safeIsDirectory(original))
923             throw new IOException("Directory doesn't exist: " + originalName);
924
925         // let's try to work with "_old" added to name...
926

927         String JavaDoc renamedName = originalName + "_old";
928         File renamed = new File(renamedName);
929         
930         if(renamed.exists())
931         {
932             whack(renamed);
933             
934             // it might have failed:
935
if(renamed.exists())
936             {
937                 for(int i = 0; i < 1000; i++)
938                 {
939                     String JavaDoc name = renamedName + i;
940                     renamed = new File(name);
941                     
942                     try{ whack(renamed); }
943                     catch(Throwable JavaDoc t) { /* ignore!! */ }
944
945                     if(!renamed.exists())
946                     {
947                         // found one!!!
948
renamedName = name;
949                         break;
950                     }
951                 }
952                 // once more in case we went through all 1000!
953
if(renamed.exists())
954                     throw new IOException("Tried 1000 possible rename directory names. None worked!");
955             }
956         }
957         
958         // whew!
959

960         // try a simple rename...
961

962         if(original.renameTo(renamed))
963             return renamed;
964         
965         // OK -- we'return probably in Windows and something is referencing original.
966

967         copyTree(original, renamed);
968         whack(original); // this will delete whatever is possible to delete...
969

970         return renamed;
971     }
972
973     ///////////////////////////////////////////////////////////////////////////
974

975         /**
976          *Rename, running gc on Windows if needed to try to force open streams to close.
977          *@param file to be renamed
978          *@param new name for the renamed file
979          *@return boolean result of the rename attempt
980          */

981         public static boolean renameFile(File fromFile, File toFile) {
982             boolean result = fromFile.renameTo(toFile);
983             boolean log = _utillogger.isLoggable(FILE_OPERATION_LOG_LEVEL);
984
985             if ( ! result ) {
986                 String JavaDoc fromFilePath = null;
987                 String JavaDoc toFilePath = null;
988                 if (log) {
989                     fromFilePath = fromFile.getAbsolutePath();
990                     toFilePath = toFile.getAbsolutePath();
991                     _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.error_renaming_file", new Object JavaDoc []
992                         { fromFilePath, toFilePath } );
993                 }
994                 
995                 /*
996                  *Try triggering garbage collection in an attempt to force finalizers to
997                  *close their streams, allowing the next attempt at renaming to succeed.
998                  */

999                 if (OS.isWindows()) {
1000                    if (log && (FILE_OPERATION_MAX_RETRIES > 0)) {
1001                        _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.perform_gc");
1002                    }
1003                    int retries = 0;
1004                    for (retries = 0; retries < FILE_OPERATION_MAX_RETRIES && ! result; retries++) {
1005                        try {
1006                            Thread.currentThread().sleep(FILE_OPERATION_SLEEP_DELAY_MS);
1007                        } catch (InterruptedException JavaDoc ie) {
1008                        }
1009                        System.gc();
1010                        result = fromFile.renameTo(toFile);
1011                    }
1012                    if (log) {
1013                        if (result) {
1014                            _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.retry_rename_success", new Object JavaDoc []
1015                                { fromFilePath, toFilePath, new Integer JavaDoc(retries) } );
1016                        } else {
1017                            _utillogger.log(FILE_OPERATION_LOG_LEVEL, "enterprise_util.retry_rename_failure", new Object JavaDoc []
1018                                { fromFilePath, toFilePath, new Integer JavaDoc(retries) } );
1019                        }
1020                    }
1021                }
1022            } else {
1023                if (_utillogger.isLoggable(Level.FINE)) {
1024                    _utillogger.log(Level.FINE, "enterprise_util.rename_initial_success", new Object JavaDoc [] {
1025                        fromFile.getAbsolutePath(), toFile.getAbsolutePath() } );
1026                }
1027            }
1028            return result;
1029        }
1030            
1031    ///////////////////////////////////////////////////////////////////////////
1032

1033    private static void verifyPermissions(String JavaDoc per) throws NativeIOException
1034    {
1035        // brace yourself for some involved argument checking.
1036
// It's not pretty but it *is* neccessary.
1037

1038        if(per == null)
1039            throw new NativeIOException("null permissions string.");
1040        if(per.length() != 9)
1041            throw new NativeIOException("permissions string must be exactly" +
1042                " 9 characters long. It is " + per.length() + " characters long.");
1043        
1044        // make sure every character is r, w, x, or -
1045
String JavaDoc err1 = "permissions string has a bad character ('";
1046        String JavaDoc err2 = "') at position #";
1047        String JavaDoc err3 = ". Expected '-' or '";
1048        String JavaDoc err4 = "'";
1049
1050        for(int i = 0; i < 9; i++)
1051        {
1052            
1053            char c = per.charAt(i);
1054            int pos = i % 3; // 0->r, 1->w, 2->x
1055

1056            if(pos == 0)
1057            {
1058                if(c != 'r' && c != '-')
1059                    throw new NativeIOException(err1 + c + err2 + (i + 1) + err3 + 'r' + err4);
1060            }
1061            else if(pos == 1)
1062            {
1063                if(c != 'w' && c != '-')
1064                    throw new NativeIOException(err1 + c + err2 + (i + 1) + err3 + 'w' + err4);
1065            }
1066            else if(pos == 2)
1067            {
1068                if(c != 'x' && c != '-')
1069                    throw new NativeIOException(err1 + c + err2 + (i + 1) + err3 + 'x' + err4);
1070            }
1071        }
1072    }
1073    
1074    /** Appends the given line at the end of given text file. If the given
1075     * file does not exist, an attempt is made to create it.
1076     * Note that this method can handle only text files.
1077     * @param fileName name of the text file that needs to be appended to
1078     * @param line the line to append to
1079     * @throws RuntimeException in case of any error - that makes it callable
1080     * from a code not within try-catch. Note that NPE will be thrown if either
1081     * argument is null.
1082     * Note that this method is not tested with String containing characters
1083     * with 2 bytes.
1084     */

1085    public static void appendText(String JavaDoc fileName, String JavaDoc line) throws
1086        RuntimeException JavaDoc {
1087        RandomAccessFile file = null;
1088        try {
1089            final String JavaDoc MODE = "rw";
1090            file = new RandomAccessFile(fileName, MODE);
1091            file.seek(file.getFilePointer() + file.length());
1092            file.writeBytes(line);
1093        }
1094        catch(Exception JavaDoc e) {
1095            throw new RuntimeException JavaDoc("FileUtils.appendText()", e);
1096        }
1097        finally {
1098            try {
1099                if (file != null)
1100                    file.close();
1101            }
1102            catch(Exception JavaDoc e) {}
1103        }
1104    }
1105    
1106    public static void appendText(String JavaDoc fileName, StringBuffer JavaDoc buffer)
1107        throws IOException, FileNotFoundException {
1108        appendText(fileName, buffer.toString());
1109    }
1110    ///////////////////////////////////////////////////////////////////////////
1111

1112    /** A utility routine to read a <b> text file </b> efficiently and return
1113     * the contents as a String. Sometimes while reading log files of spawned
1114     * processes this kind of facility is handy. Instead of opening files, coding
1115     * FileReaders etc. this method could be employed. It is expected that the
1116     * file to be read is <code> small </code>.
1117     * @param fileName String representing absolute path of the file
1118     * @return String representing the contents of the file, empty String for an empty file
1119     * @throws java.io.IOException if there is an i/o error.
1120     * @throws java.io.FileNotFoundException if the file could not be found
1121     */

1122    public static String JavaDoc readSmallFile(final String JavaDoc fileName) throws IOException, FileNotFoundException {
1123        return (readSmallFile(new File(fileName)) );
1124    }
1125    
1126    public static String JavaDoc readSmallFile(final File file) throws IOException {
1127        final BufferedReader bf = new BufferedReader(new FileReader(file));
1128        final StringBuilder JavaDoc sb = new StringBuilder JavaDoc(); //preferred over StringBuffer, no need to synchronize
1129
String JavaDoc line = null;
1130        try {
1131            while ( (line = bf.readLine()) != null ) {
1132                sb.append(line);
1133                sb.append(System.getProperty("line.separator"));
1134            }
1135        } finally {
1136            try {
1137                bf.close();
1138            } catch (Exception JavaDoc e) {}
1139        }
1140        return ( sb.toString() );
1141    }
1142    
1143    public static void main(String JavaDoc[] args)
1144    {
1145        try
1146        {
1147            System.out.println(smartRename(new File("C:/temp/test")));
1148        }
1149        catch(Throwable JavaDoc t)
1150        {
1151            t.printStackTrace();
1152        }
1153        /*
1154        try
1155        {
1156            String ret = recursiveChmod(new File("c:/temp"), "rwxr-----");
1157            System.out.println("recursiveChmod returned: " + ret);
1158        }
1159        catch(Throwable t)
1160        {
1161            t.printStackTrace();
1162        }
1163        //_logger.log(Level.SEVERE,"iplanet_util.io_exception", new IOException());
1164        //System.out.println("xxxxxxxxxx");
1165         **/

1166        appendText("empty.txt", "text line");
1167    }
1168
1169    /**
1170     * Method to read a file and return it as String
1171     */

1172    public static String JavaDoc getFileContents(String JavaDoc fileName)
1173            throws IOException, FileNotFoundException {
1174
1175        FileReader fr = null;
1176        fr = new FileReader(fileName);
1177        StringWriter sr = new StringWriter();
1178
1179        try {
1180        char[] buf = new char[1024];
1181        int len = 0;
1182        while (len != -1) {
1183            try {
1184                len = fr.read(buf, 0, buf.length);
1185            } catch (EOFException eof) {
1186                break;
1187            }
1188            if (len != -1) {
1189                sr.write(buf, 0, len);
1190            }
1191        }
1192
1193        fr.close();
1194        sr.close();
1195
1196        return sr.toString();
1197
1198    } finally {
1199        if (fr != null) {
1200            try {
1201                fr.close();
1202            } catch (IOException ioe) {
1203            }
1204        }
1205    }
1206    }
1207
1208    /**
1209     *Make sure the specified path is a legal length on Windows.
1210     *@param fullPath the String holding the path to check
1211     *@throws IOException if the path is too long
1212     */

1213    public static void validateWindowsFilePathLength(String JavaDoc fullPath) throws IOException {
1214        /*
1215         *No longer needed because 1.5.0-06 now avoids the Windows file path
1216         *length limitation.
1217         */

1218        return;
1219    }
1220    
1221    /**
1222     *Make sure the specified path is a legal length on Windows.
1223     *@param file the File to check
1224     *@throws IOException if the path is too long
1225     */

1226    public static void validateWindowsFilePathLength(File file) throws IOException {
1227        validateWindowsFilePathLength(file.getAbsolutePath());
1228    }
1229    
1230    ///////////////////////////////////////////////////////////////////////////
1231

1232        private static final int BUFFER_SIZE = 0x10000; // 64k
1233
private final static char[] ILLEGAL_FILENAME_CHARS = {'/', '\\', ':', '*', '?', '"', '<', '>', '|' };
1234    private final static String JavaDoc ILLEGAL_FILENAME_STRING = "\\/:*?\"<>|";
1235    private final static char REPLACEMENT_CHAR = '_';
1236    private final static char BLANK = ' ';
1237    private final static char DOT = '.';
1238    private static String JavaDoc TMPFILENAME = "scratch";
1239        /*
1240         *The following property names are private, unsupported, and unpublished.
1241         */

1242        private static final int FILE_OPERATION_MAX_RETRIES = Integer.getInteger("com.sun.appserv.winFileLockRetryLimit", 4).intValue();
1243        private static final int FILE_OPERATION_SLEEP_DELAY_MS = Integer.getInteger("com.sun.appserv.winFileLockRetryDelay", 100).intValue();
1244        private static final Level JavaDoc FILE_OPERATION_LOG_LEVEL = Level.INFO;
1245}
1246
Popular Tags