This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-io.git
commit 0671c86b0af8a4e604ad3da465ef1a88576a0fb5 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Tue Jun 13 09:59:28 2023 -0400 Add FileCleaningTracker.track(Path, Object[, FileDeleteStrategy]). --- src/changes/changes.xml | 3 + .../org/apache/commons/io/FileCleaningTracker.java | 31 ++++++ .../apache/commons/io/FileCleaningTrackerTest.java | 115 ++++++++++++++++----- .../java/org/apache/commons/io/test/TestUtils.java | 18 ++-- 4 files changed, 133 insertions(+), 34 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ad806944..ec5c285d 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -52,6 +52,9 @@ The <action> type attribute can be add,update,fix,remove. <action dev="ggregory" type="add" due-to="Gary Gregory"> Add DeferredFileOutputStream.getPath(). </action> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add FileCleaningTracker.track(Path, Object[, FileDeleteStrategy]). + </action> <!-- FIX --> <action dev="ggregory" type="fix" issue="IO-799" due-to="Jeroen van der Vegt, Gary Gregory"> ReaderInputStream.read() throws an exception instead of returning -1 when called again after returning -1. diff --git a/src/main/java/org/apache/commons/io/FileCleaningTracker.java b/src/main/java/org/apache/commons/io/FileCleaningTracker.java index 95363645..98c33b0d 100644 --- a/src/main/java/org/apache/commons/io/FileCleaningTracker.java +++ b/src/main/java/org/apache/commons/io/FileCleaningTracker.java @@ -19,6 +19,7 @@ package org.apache.commons.io; import java.io.File; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -255,6 +256,36 @@ public class FileCleaningTracker { addTracker(file.getPath(), marker, deleteStrategy); } + /** + * Tracks the specified file, using the provided marker, deleting the file + * when the marker instance is garbage collected. + * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. + * + * @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 + * @since 2.14.0 + */ + public void track(final Path file, final Object marker) { + track(file, marker, null); + } + + /** + * Tracks the specified file, using the provided marker, deleting the file + * when the marker instance is garbage collected. + * The specified deletion strategy is used. + * + * @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 + * @since 2.14.0 + */ + public void track(final Path file, final Object marker, final FileDeleteStrategy deleteStrategy) { + Objects.requireNonNull(file, "file"); + addTracker(file.toAbsolutePath().toString(), marker, deleteStrategy); + } + /** * Tracks the specified file, using the provided marker, deleting the file * when the marker instance is garbage collected. diff --git a/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java b/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java index bb47ae23..01c9d35d 100644 --- a/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java +++ b/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java @@ -29,6 +29,8 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.lang.ref.ReferenceQueue; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -44,6 +46,7 @@ import org.junit.jupiter.api.Test; public class FileCleaningTrackerTest extends AbstractTempDirTest { private File testFile; + private Path testPath; private FileCleaningTracker theInstance; @@ -63,9 +66,18 @@ public class FileCleaningTrackerTest extends AbstractTempDirTest { } } + private void pauseForDeleteToComplete(Path file) { + int count = 0; + while (Files.exists(file) && count++ < 40) { + TestUtils.sleepQuietly(500L); + file = Paths.get(file.toAbsolutePath().toString()); + } + } + @BeforeEach public void setUp() { testFile = new File(tempDirFile, "file-test.txt"); + testPath = testFile.toPath(); theInstance = newInstance(); } @@ -100,51 +112,59 @@ public class FileCleaningTrackerTest extends AbstractTempDirTest { } @Test - public void testFileCleanerDirectory() throws Exception { - TestUtils.createFile(testFile, 100); + public void testFileCleanerDirectory_ForceStrategy_FileSource() throws Exception { + if (!testFile.getParentFile().exists()) { + throw new IOException("Cannot create file " + testFile + + " as the parent directory does not exist"); + } + try (BufferedOutputStream output = + new BufferedOutputStream(Files.newOutputStream(testFile.toPath()))) { + TestUtils.generateTestData(output, 100); + } assertTrue(testFile.exists()); assertTrue(tempDirFile.exists()); Object obj = new Object(); assertEquals(0, theInstance.getTrackCount()); - theInstance.track(tempDirFile, obj); + theInstance.track(tempDirFile, obj, FileDeleteStrategy.FORCE); assertEquals(1, theInstance.getTrackCount()); obj = null; waitUntilTrackCount(); + pauseForDeleteToComplete(testFile.getParentFile()); assertEquals(0, theInstance.getTrackCount()); - assertTrue(testFile.exists()); // not deleted, as dir not empty - assertTrue(testFile.getParentFile().exists()); // not deleted, as dir not empty + assertFalse(new File(testFile.getPath()).exists(), showFailures()); + assertFalse(testFile.getParentFile().exists(), showFailures()); } @Test - public void testFileCleanerDirectory_ForceStrategy() throws Exception { - if (!testFile.getParentFile().exists()) { - throw new IOException("Cannot create file " + testFile + public void testFileCleanerDirectory_ForceStrategy_PathSource() throws Exception { + if (!Files.exists(testPath.getParent())) { + throw new IOException("Cannot create file " + testPath + " as the parent directory does not exist"); } try (BufferedOutputStream output = - new BufferedOutputStream(Files.newOutputStream(testFile.toPath()))) { + new BufferedOutputStream(Files.newOutputStream(testPath))) { TestUtils.generateTestData(output, 100); } - assertTrue(testFile.exists()); - assertTrue(tempDirFile.exists()); + assertTrue(Files.exists(testPath)); + assertTrue(Files.exists(tempDirPath)); Object obj = new Object(); assertEquals(0, theInstance.getTrackCount()); - theInstance.track(tempDirFile, obj, FileDeleteStrategy.FORCE); + theInstance.track(tempDirPath, obj, FileDeleteStrategy.FORCE); assertEquals(1, theInstance.getTrackCount()); obj = null; waitUntilTrackCount(); - pauseForDeleteToComplete(testFile.getParentFile()); + pauseForDeleteToComplete(testPath.getParent()); assertEquals(0, theInstance.getTrackCount()); - assertFalse(new File(testFile.getPath()).exists(), showFailures()); - assertFalse(testFile.getParentFile().exists(), showFailures()); + assertFalse(Files.exists(testPath), showFailures()); + assertFalse(Files.exists(testPath.getParent()), showFailures()); } @Test @@ -167,6 +187,46 @@ public class FileCleaningTrackerTest extends AbstractTempDirTest { assertTrue(testFile.getParentFile().exists()); // not deleted, as dir not empty } + @Test + public void testFileCleanerDirectoryFileSource() throws Exception { + TestUtils.createFile(testFile, 100); + assertTrue(testFile.exists()); + assertTrue(tempDirFile.exists()); + + Object obj = new Object(); + assertEquals(0, theInstance.getTrackCount()); + theInstance.track(tempDirFile, obj); + assertEquals(1, theInstance.getTrackCount()); + + obj = null; + + waitUntilTrackCount(); + + assertEquals(0, theInstance.getTrackCount()); + assertTrue(testFile.exists()); // not deleted, as dir not empty + assertTrue(testFile.getParentFile().exists()); // not deleted, as dir not empty + } + + @Test + public void testFileCleanerDirectoryPathSource() throws Exception { + TestUtils.createFile(testPath, 100); + assertTrue(Files.exists(testPath)); + assertTrue(Files.exists(tempDirPath)); + + Object obj = new Object(); + assertEquals(0, theInstance.getTrackCount()); + theInstance.track(tempDirPath, obj); + assertEquals(1, theInstance.getTrackCount()); + + obj = null; + + waitUntilTrackCount(); + + assertEquals(0, theInstance.getTrackCount()); + assertTrue(Files.exists(testPath)); // not deleted, as dir not empty + assertTrue(Files.exists(testPath.getParent())); // not deleted, as dir not empty + } + @Test public void testFileCleanerExitWhenFinished_NoTrackAfter() { assertFalse(theInstance.exitWhenFinished); @@ -187,23 +247,22 @@ public class FileCleaningTrackerTest extends AbstractTempDirTest { final String path = testFile.getPath(); assertFalse(testFile.exists(), "1-testFile exists: " + testFile); - RandomAccessFile r = createRandomAccessFile(); - assertTrue(testFile.exists(), "2-testFile exists"); + try (RandomAccessFile raf = createRandomAccessFile()) { + assertTrue(testFile.exists(), "2-testFile exists"); - assertEquals(0, theInstance.getTrackCount(), "3-Track Count"); - theInstance.track(path, r); - assertEquals(1, theInstance.getTrackCount(), "4-Track Count"); - assertFalse(theInstance.exitWhenFinished, "5-exitWhenFinished"); - assertTrue(theInstance.reaper.isAlive(), "6-reaper.isAlive"); + assertEquals(0, theInstance.getTrackCount(), "3-Track Count"); + theInstance.track(path, raf); + assertEquals(1, theInstance.getTrackCount(), "4-Track Count"); + assertFalse(theInstance.exitWhenFinished, "5-exitWhenFinished"); + assertTrue(theInstance.reaper.isAlive(), "6-reaper.isAlive"); - assertFalse(theInstance.exitWhenFinished, "7-exitWhenFinished"); - theInstance.exitWhenFinished(); - assertTrue(theInstance.exitWhenFinished, "8-exitWhenFinished"); - assertTrue(theInstance.reaper.isAlive(), "9-reaper.isAlive"); + assertFalse(theInstance.exitWhenFinished, "7-exitWhenFinished"); + theInstance.exitWhenFinished(); + assertTrue(theInstance.exitWhenFinished, "8-exitWhenFinished"); + assertTrue(theInstance.reaper.isAlive(), "9-reaper.isAlive"); - r.close(); + } testFile = null; - r = null; waitUntilTrackCount(); pauseForDeleteToComplete(new File(path)); diff --git a/src/test/java/org/apache/commons/io/test/TestUtils.java b/src/test/java/org/apache/commons/io/test/TestUtils.java index 8ace275e..cc9d7ff8 100644 --- a/src/test/java/org/apache/commons/io/test/TestUtils.java +++ b/src/test/java/org/apache/commons/io/test/TestUtils.java @@ -164,14 +164,20 @@ public abstract class TestUtils { } } - public static void createFile(final File file, final long size) - throws IOException { + public static void createFile(final File file, final long size) throws IOException { if (!file.getParentFile().exists()) { - throw new IOException("Cannot create file " + file - + " as the parent directory does not exist"); + throw new IOException("Cannot create file " + file + " as the parent directory does not exist"); + } + try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()))) { + generateTestData(output, size); + } + } + + public static void createFile(final Path file, final long size) throws IOException { + if (!Files.exists(file.getParent())) { + throw new IOException("Cannot create file " + file + " as the parent directory does not exist"); } - try (BufferedOutputStream output = - new BufferedOutputStream(Files.newOutputStream(file.toPath()))) { + try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file))) { generateTestData(output, size); } }