Author: scolebourne
Date: Thu Aug 31 16:34:31 2006
New Revision: 439102

URL: http://svn.apache.org/viewvc?rev=439102&view=rev
Log:
IO-56,IO-70 - FileDeleteStrategy / FileCleaner
- FileDeleteStrategy is a strategy for handling file deletion and can be used 
as a calback in FileCleaner
- Together these allow FileCleaner to do a forceDelete to kill directories and 
provide hooks for secure delete

Added:
    
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileDeleteStrategy.java
   (with props)
Modified:
    jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt
    
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileCleaner.java
    
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileCleanerTestCase.java
    
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java

Modified: jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt?rev=439102&r1=439101&r2=439102&view=diff
==============================================================================
--- jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt (original)
+++ jakarta/commons/proper/io/trunk/RELEASE-NOTES.txt Thu Aug 31 16:34:31 2006
@@ -51,6 +51,9 @@
 - FileSystemUtils.freeSpace [IO-91]
   - This is now documented not to work on SunOS 5
 
+- FileCleaner
+  - This now handles the situation where an error occurs when deleting the file
+
 
 Enhancements from 1.2
 ---------------------
@@ -62,6 +65,19 @@
   - wildcardMatch - new method that has IOCase as a parameter
   - equals - new method that has IOCase as a parameter
 
+- FileUtils.isFileOlder
+  - add methods to check if a file is older (i.e. isFileOlder()) - counterparts
+    to the existing isFileNewer() methods.
+
+- FileUtils.checksum, FileUtils.checksumCRC32
+  - add methods to create a checksum of a file
+
+- FileDeleteStrategy
+- FileCleaner    [IO-56,IO-70]
+  - FileDeleteStrategy is a strategy for handling file deletion
+  - This can be used as a calback in FileCleaner
+  - Together these allow FileCleaner to do a forceDelete to kill directories
+
 - WildcardFileFilter
   - Replacement for WildcardFilter
   - Accepts both files and directories
@@ -105,13 +121,6 @@
 - FileFilterUtils
   - new sizeRangeFileFilter(long minimumSize, long maximumSize) method which 
     creates a filter that accepts files within the specified size range.
-
-- FileUtils
-  - add methods to check if a file is older (i.e. isFileOlder()) - counterparts
-    to the existing isFileNewer() methods.
-
-- FileUtils.checksum, FileUtils.checksumCRC32
-  - add methods to create a checksum of a file
 
 
 Feedback

Modified: 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileCleaner.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileCleaner.java?rev=439102&r1=439101&r2=439102&view=diff
==============================================================================
--- 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileCleaner.java 
(original)
+++ 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileCleaner.java 
Thu Aug 31 16:34:31 2006
@@ -81,69 +81,104 @@
         reaper.start();
     }
 
+    //-----------------------------------------------------------------------
     /**
      * Track the specified file, using the provided marker, deleting the file
      * when the marker instance is garbage collected.
+     * The [EMAIL PROTECTED] FileDeleteStrategy#NORMAL normal} deletion 
strategy will be used.
      *
-     * @param file   The file to be tracked.
-     * @param marker The marker object used to track the file.
+     * @param file  the file to be tracked, not null
+     * @param marker  the marker object used to track the file, not null
+     * @throws NullPointerException if the file is null
      */
     public static void track(File file, Object marker) {
-        trackers.add(new Tracker(file, marker, q));
+        track(file, marker, (FileDeleteStrategy) null);
     }
 
     /**
      * Track the specified file, using the provided marker, deleting the file
      * when the marker instance is garbage collected.
+     * The speified deletion strategy is used.
      *
-     * @param path   The full path to the file to be tracked.
-     * @param marker The marker object used to track the file.
+     * @param file  the file to be tracked, not null
+     * @param marker  the marker object used to track the file, not null
+     * @param deleteStrategy  the strategy to delete the file, null means 
normal
+     * @throws NullPointerException if the file is null
+     */
+    public static void track(File file, Object marker, FileDeleteStrategy 
deleteStrategy) {
+        if (file == null) {
+            throw new NullPointerException("The file must not be null");
+        }
+        trackers.add(new Tracker(file.getPath(), deleteStrategy, marker, q));
+    }
+
+    /**
+     * Track the specified file, using the provided marker, deleting the file
+     * when the marker instance is garbage collected.
+     * The [EMAIL PROTECTED] FileDeleteStrategy#NORMAL normal} deletion 
strategy will be used.
+     *
+     * @param path  the full path to the file to be tracked, not null
+     * @param marker  the marker object used to track the file, not null
+     * @throws NullPointerException if the path is null
      */
     public static void track(String path, Object marker) {
-        trackers.add(new Tracker(path, marker, q));
+        track(path, marker, (FileDeleteStrategy) null);
+    }
+
+    /**
+     * Track the specified file, using the provided marker, deleting the file
+     * when the marker instance is garbage collected.
+     * The speified deletion strategy is used.
+     *
+     * @param path  the full path to the file to be tracked, not null
+     * @param marker  the marker object used to track the file, not null
+     * @param deleteStrategy  the strategy to delete the file, null means 
normal
+     * @throws NullPointerException if the path is null
+     */
+    public static void track(String path, Object marker, FileDeleteStrategy 
deleteStrategy) {
+        if (path == null) {
+            throw new NullPointerException("The path must not be null");
+        }
+        trackers.add(new Tracker(path, deleteStrategy, marker, q));
     }
 
     /**
      * Retrieve the number of files currently being tracked, and therefore
      * awaiting deletion.
      *
-     * @return the number of files being tracked.
+     * @return the number of files being tracked
      */
     public static int getTrackCount() {
         return trackers.size();
     }
 
+    //-----------------------------------------------------------------------
     /**
      * Inner class which acts as the reference for a file pending deletion.
      */
-    private static class Tracker extends PhantomReference {
+    static class Tracker extends PhantomReference {
 
         /**
          * The full path to the file being tracked.
          */
-        private String path;
-
+        private final String path;
         /**
-         * Constructs an instance of this class from the supplied parameters.
-         *
-         * @param file   The file to be tracked.
-         * @param marker The marker object used to track the file.
-         * @param queue  The queue on to which the tracker will be pushed.
+         * The strategy for deleting files.
          */
-        public Tracker(File file, Object marker, ReferenceQueue queue) {
-            this(file.getPath(), marker, queue);
-        }
+        private final FileDeleteStrategy deleteStrategy;
 
         /**
          * Constructs an instance of this class from the supplied parameters.
          *
-         * @param path   The full path to the file to be tracked.
-         * @param marker The marker object used to track the file.
-         * @param queue  The queue on to which the tracker will be pushed.
+         * @param path  the full path to the file to be tracked, not null
+         * @param deleteStrategy  the strategy to delete the file, null means 
normal
+         * @param marker  the marker object used to track the file, not null
+         * @param queue  the queue on to which the tracker will be pushed, not 
null
          */
-        public Tracker(String path, Object marker, ReferenceQueue queue) {
+        Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, 
ReferenceQueue queue) {
             super(marker, queue);
             this.path = path;
+            this.deleteStrategy = (deleteStrategy == null ? 
FileDeleteStrategy.NORMAL : deleteStrategy);
         }
 
         /**
@@ -153,7 +188,8 @@
          *         <code>false</code> otherwise.
          */
         public boolean delete() {
-            return new File(path).delete();
+            return deleteStrategy.deleteQuietly(new File(path));
         }
     }
+
 }

Added: 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileDeleteStrategy.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileDeleteStrategy.java?rev=439102&view=auto
==============================================================================
--- 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileDeleteStrategy.java
 (added)
+++ 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileDeleteStrategy.java
 Thu Aug 31 16:34:31 2006
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Strategy for deleting files.
+ * <p>
+ * There is more than one way to delete a file.
+ * You may want to limit access to certain directories, to only delete
+ * directories if they are empty, or maybe to force deletion.
+ * <p>
+ * This class captures the strategy to use and is designed for user 
subclassing.
+ *
+ * @author Stephen Colebourne
+ * @version $Id $
+ * @since Commons IO 1.3
+ */
+public class FileDeleteStrategy {
+
+    /**
+     * The singleton instance for normal file deletion, which does not permit
+     * the deletion of directories that are not empty.
+     */
+    public static final FileDeleteStrategy NORMAL = new 
FileDeleteStrategy("Normal");
+    /**
+     * The singleton instance for forced file deletion, which always deletes,
+     * even if the file represents a non-empty directory.
+     */
+    public static final FileDeleteStrategy FORCE = new 
ForceFileDeleteStrategy();
+
+    /** The name of the strategy. */
+    private final String name;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restricted constructor.
+     *
+     * @param name  the name by which the strategy is known
+     */
+    protected FileDeleteStrategy(String name) {
+        this.name = name;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Deletes the file object, which may be a file or a directory.
+     * All <code>IOException</code>s are caught and false returned instead.
+     * If the file does not exist or is null, true is returned.
+     * <p>
+     * Subclass writers should override [EMAIL PROTECTED] #doDelete(File)}, 
not this method.
+     *
+     * @param fileToDelete  the file to delete, null returns true
+     * @return true if the file was deleted, or there was no such file
+     */
+    public boolean deleteQuietly(File fileToDelete) {
+        if (fileToDelete == null) {
+            return true;
+        }
+        try {
+            return doDelete(fileToDelete);
+        } catch (IOException ex) {
+            return false;
+        }
+    }
+
+    /**
+     * Deletes the file object, which may be a file or a directory.
+     * If the file does not exist, the method just returns.
+     * <p>
+     * Subclass writers should override [EMAIL PROTECTED] #doDelete(File)}, 
not this method.
+     *
+     * @param fileToDelete  the file to delete, not null
+     * @throws NullPointerException if the file is null
+     * @throws IOException if an error occurs during file deletion
+     */
+    public void delete(File fileToDelete) throws IOException {
+        if (doDelete(fileToDelete) == false) {
+            throw new IOException("Deletion failed: " + fileToDelete);
+        }
+    }
+
+    /**
+     * Actually deletes the file object, which may be a file or a directory.
+     * <p>
+     * This method is designed for subclasses to override.
+     * The implementation may return either false or an 
<code>IOException</code>
+     * when deletion fails. The [EMAIL PROTECTED] #delete(File)} and [EMAIL 
PROTECTED] #deleteQuietly(File)}
+     * methods will handle either response appropriately.
+     * If the file does not exist, the implementation must return true.
+     * <p>
+     * This implementation uses [EMAIL PROTECTED] File#delete()}.
+     *
+     * @param fileToDelete  the file to delete, not null
+     * @return true if the file was deleted, or there was no such file
+     * @throws NullPointerException if the file is null
+     * @throws IOException if an error occurs during file deletion
+     */
+    protected boolean doDelete(File fileToDelete) throws IOException {
+        return fileToDelete.delete();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets a string describing the delete strategy.
+     * 
+     * @return a string describing the delete strategy
+     */
+    public String toString() {
+        return "FileDelete[" + name + "]";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Force file deletion strategy.
+     */
+    static class ForceFileDeleteStrategy extends FileDeleteStrategy {
+        ForceFileDeleteStrategy() {
+            super("Force");
+        }
+        protected boolean doDelete(File fileToDelete) throws IOException {
+            if (fileToDelete.exists()) {
+                FileUtils.forceDelete(fileToDelete);
+            }
+            return true;
+        }
+    }
+
+}

Propchange: 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileDeleteStrategy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/commons/proper/io/trunk/src/java/org/apache/commons/io/FileDeleteStrategy.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision

Modified: 
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileCleanerTestCase.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileCleanerTestCase.java?rev=439102&r1=439101&r2=439102&view=diff
==============================================================================
--- 
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileCleanerTestCase.java
 (original)
+++ 
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/FileCleanerTestCase.java
 Thu Aug 31 16:34:31 2006
@@ -64,29 +64,114 @@
         FileUtils.deleteDirectory(getTestDirectory());
     }
 
-    /**
-     *  Test the FileCleaner implementation.
-     */
-    public void testFileCleaner() throws Exception {
+    //-----------------------------------------------------------------------
+    public void testFileCleanerFile() throws Exception {
         String path = testFile.getPath();
-
-        assertFalse("File does not exist", testFile.exists());
+        
+        assertEquals(false, testFile.exists());
         RandomAccessFile r = new RandomAccessFile(testFile, "rw");
-        assertTrue("File exists", testFile.exists());
-
-        assertTrue("No files tracked", FileCleaner.getTrackCount() == 0);
+        assertEquals(true, testFile.exists());
+        
+        assertEquals(0, FileCleaner.getTrackCount());
         FileCleaner.track(path, r);
-        assertTrue("One file tracked", FileCleaner.getTrackCount() == 1);
-
+        assertEquals(1, FileCleaner.getTrackCount());
+        
         r.close();
         testFile = null;
         r = null;
+        while (FileCleaner.getTrackCount() != 0) {
+            System.gc();
+        }
+        
+        assertEquals(0, FileCleaner.getTrackCount());
+        assertEquals(false, new File(path).exists());
+    }
 
+    public void testFileCleanerDirectory() throws Exception {
+        createFile(testFile, 100);
+        assertEquals(true, testFile.exists());
+        assertEquals(true, getTestDirectory().exists());
+        
+        Object obj = new Object();
+        assertEquals(0, FileCleaner.getTrackCount());
+        FileCleaner.track(getTestDirectory(), obj);
+        assertEquals(1, FileCleaner.getTrackCount());
+        
+        obj = null;
         while (FileCleaner.getTrackCount() != 0) {
             System.gc();
         }
+        
+        assertEquals(0, FileCleaner.getTrackCount());
+        assertEquals(true, testFile.exists());  // not deleted, as dir not 
empty
+        assertEquals(true, testFile.getParentFile().exists());  // not 
deleted, as dir not empty
+    }
 
-        assertTrue("No files tracked", FileCleaner.getTrackCount() == 0);
-        assertFalse("File does not exist", new File(path).exists());
+    public void testFileCleanerDirectory_NullStrategy() throws Exception {
+        createFile(testFile, 100);
+        assertEquals(true, testFile.exists());
+        assertEquals(true, getTestDirectory().exists());
+        
+        Object obj = new Object();
+        assertEquals(0, FileCleaner.getTrackCount());
+        FileCleaner.track(getTestDirectory(), obj, (FileDeleteStrategy) null);
+        assertEquals(1, FileCleaner.getTrackCount());
+        
+        obj = null;
+        while (FileCleaner.getTrackCount() != 0) {
+            System.gc();
+        }
+        
+        assertEquals(0, FileCleaner.getTrackCount());
+        assertEquals(true, testFile.exists());  // not deleted, as dir not 
empty
+        assertEquals(true, testFile.getParentFile().exists());  // not 
deleted, as dir not empty
     }
+
+    public void testFileCleanerDirectory_ForceStrategy() throws Exception {
+        createFile(testFile, 100);
+        assertEquals(true, testFile.exists());
+        assertEquals(true, getTestDirectory().exists());
+        
+        Object obj = new Object();
+        assertEquals(0, FileCleaner.getTrackCount());
+        FileCleaner.track(getTestDirectory(), obj, FileDeleteStrategy.FORCE);
+        assertEquals(1, FileCleaner.getTrackCount());
+        
+        obj = null;
+        while (FileCleaner.getTrackCount() != 0) {
+            System.gc();
+        }
+        
+        assertEquals(0, FileCleaner.getTrackCount());
+        assertEquals(false, testFile.exists());
+        assertEquals(false, testFile.getParentFile().exists());
+    }
+
+    public void testFileCleanerNull() throws Exception {
+        try {
+            FileCleaner.track((File) null, new Object());
+            fail();
+        } catch (NullPointerException ex) {
+            // expected
+        }
+        try {
+            FileCleaner.track((File) null, new Object(), 
FileDeleteStrategy.NORMAL);
+            fail();
+        } catch (NullPointerException ex) {
+            // expected
+        }
+        try {
+            FileCleaner.track((String) null, new Object());
+            fail();
+        } catch (NullPointerException ex) {
+            // expected
+        }
+        try {
+            FileCleaner.track((String) null, new Object(), 
FileDeleteStrategy.NORMAL);
+            fail();
+        } catch (NullPointerException ex) {
+            // expected
+        }
+    }
+
 }

Modified: 
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java?rev=439102&r1=439101&r2=439102&view=diff
==============================================================================
--- 
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java
 (original)
+++ 
jakarta/commons/proper/io/trunk/src/test/org/apache/commons/io/PackageTestSuite.java
 Thu Aug 31 16:34:31 2006
@@ -38,6 +38,7 @@
         suite.addTest(new TestSuite(CopyUtilsTest.class));
         suite.addTest(new TestSuite(DemuxTestCase.class));
         suite.addTest(new TestSuite(EndianUtilsTest.class));
+        suite.addTest(new TestSuite(FileCleanerTestCase.class));
         suite.addTest(new TestSuite(FilenameUtilsTestCase.class));
         suite.addTest(new TestSuite(FilenameUtilsWildcardTestCase.class));
         suite.addTest(new TestSuite(FileSystemUtilsTestCase.class));



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to