Method that allocates should release resources.
Use try-with-resources with Tailer as an AutoCloseable.
All tests now manage its own resource.
MODIFY
src/main/java/org/apache/commons/io/input/Tailer.java
src/main/java/org/apache/commons/io/input/Tailer.java
* alternative libraries such as jCIFS or <a href="https://commons.apache.org/proper/commons-vfs/">Apache Commons
* VFS</a>.
*/
-public class Tailer implements Runnable {
+public class Tailer implements Runnable, AutoCloseable {
/**
* Builds a {@link Tailer} with default values.
@@ -768,6 +768,14 @@ private Tailer(final Tailable tailable, final Charset charset, final TailerListe
this.charset = charset;
}
+ /**
+ * Requests the tailer to complete its current loop and return.
+ */
+ @Override
+ public void close() {
+ this.run = false;
+ }
+
/**
* Gets the delay in milliseconds.
*
@@ -963,14 +971,17 @@ public void run() {
} catch (final IOException e) {
listener.handle(e);
}
- stop();
+ close();
}
}
/**
* Requests the tailer to complete its current loop and return.
+ *
+ * @deprecated Use {@link #close()}.
*/
+ @Deprecated
public void stop() {
- this.run = false;
+ close();
}
}

MODIFY
src/test/java/org/apache/commons/io/input/TailerTest.java
src/test/java/org/apache/commons/io/input/TailerTest.java
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.TestResources;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import com.google.common.collect.Lists;
+
/**
* Test for {@link Tailer}.
*/
@@ -143,7 +144,7 @@ public TestTailerListener(final int expectedLines) {
latch = new CountDownLatch(expectedLines);
}
- public boolean awaitExpectedLines(long timeout, TimeUnit timeUnit) throws InterruptedException {
+ public boolean awaitExpectedLines(final long timeout, final TimeUnit timeUnit) throws InterruptedException {
return latch.await(timeout, timeUnit);
}
@@ -190,8 +191,6 @@ public void init(final Tailer tailer) {
@TempDir
public static File temporaryFolder;
- private Tailer tailer;
-
protected void createFile(final File file, final long size) throws IOException {
assertTrue(file.getParentFile().exists(), () -> "Cannot create file " + file + " as the parent directory does not exist");
try (final BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()))) {
@@ -215,13 +214,6 @@ protected void createFile(final File file, final long size) throws IOException {
}
}
- @AfterEach
- public void tearDown() {
- if (tailer != null) {
- tailer.stop();
- }
- }
-
@Test
@SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
public void testBufferBreak() throws Exception {
@@ -232,8 +224,7 @@ public void testBufferBreak() throws Exception {
writeString(file, "SBTOURIST\n");
final TestTailerListener listener = new TestTailerListener();
- tailer = new Tailer(file, listener, delay, false, 1);
-
+ try (Tailer tailer = new Tailer(file, listener, delay, false, 1)) {
final Thread thread = new Thread(tailer);
thread.start();
@@ -244,79 +235,88 @@ public void testBufferBreak() throws Exception {
listener.clear();
}
+ }
@Test
public void testBuilderWithNonStandardTailable() throws Exception {
final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen-and-buffersize-and-charset.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer.Builder(new NonStandardTailable(file), listener).build();
+ try (final Tailer tailer = new Tailer.Builder(new NonStandardTailable(file), listener).build()) {
assertTrue(tailer.getTailable() instanceof NonStandardTailable);
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testCreate() throws Exception {
final File file = new File(temporaryFolder, "tailer-create.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = Tailer.create(file, listener);
+ try (final Tailer tailer = Tailer.create(file, listener)) {
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testCreaterWithDelayAndFromStartWithReopen() throws Exception {
final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, false);
+ try (final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, false)) {
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testCreateWithDelay() throws Exception {
final File file = new File(temporaryFolder, "tailer-create-with-delay.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS);
+ try (final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS)) {
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testCreateWithDelayAndFromStart() throws Exception {
final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false);
+ try (final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false)) {
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testCreateWithDelayAndFromStartWithBufferSize() throws Exception {
final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-buffersize.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, TEST_BUFFER_SIZE);
+ try (final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, TEST_BUFFER_SIZE)) {
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testCreateWithDelayAndFromStartWithReopenAndBufferSize() throws Exception {
final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen-and-buffersize.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE);
+ try (final Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testCreateWithDelayAndFromStartWithReopenAndBufferSizeAndCharset() throws Exception {
final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen-and-buffersize-and-charset.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = Tailer.create(file, StandardCharsets.UTF_8, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE);
+ try (final Tailer tailer = Tailer.create(file, StandardCharsets.UTF_8, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
validateTailer(listener, tailer, file);
}
+ }
/*
* Tests [IO-357][Tailer] InterruptedException while the thead is sleeping is silently ignored.
@@ -329,7 +329,7 @@ public void testInterrupt() throws Exception {
// Use a long delay to try to make sure the test thread calls interrupt() while the tailer thread is sleeping.
final int delay = 1000;
final int idle = 50; // allow time for thread to work
- tailer = new Tailer(file, listener, delay, false, IOUtils.DEFAULT_BUFFER_SIZE);
+ try (Tailer tailer = new Tailer(file, listener, delay, false, IOUtils.DEFAULT_BUFFER_SIZE)) {
final Thread thread = new Thread(tailer);
thread.setDaemon(true);
thread.start();
@@ -343,6 +343,7 @@ public void testInterrupt() throws Exception {
assertEquals(0, listener.rotated, "fileRotated should be not be called");
assertEquals(0, listener.reachedEndOfFile, "end of file never reached");
}
+ }
@Test
public void testIO335() throws Exception { // test CR behavior
@@ -351,7 +352,7 @@ public void testIO335() throws Exception { // test CR behavior
final File file = new File(temporaryFolder, "tailer-testio334.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener();
- tailer = new Tailer(file, listener, delayMillis, false);
+ try (Tailer tailer = new Tailer(file, listener, delayMillis, false)) {
final Thread thread = new Thread(tailer);
thread.start();
@@ -366,6 +367,7 @@ public void testIO335() throws Exception { // test CR behavior
assertEquals("CR", lines.get(2), "line 3");
assertEquals("CRCR\r", lines.get(3), "line 4");
}
+ }
@Test
@SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
@@ -382,7 +384,7 @@ public void testLongFile() throws Exception {
}
final TestTailerListener listener = new TestTailerListener();
- tailer = new Tailer(file, listener, delay, false);
+ try (Tailer tailer = new Tailer(file, listener, delay, false)) {
// final long start = System.currentTimeMillis();
@@ -397,6 +399,7 @@ public void testLongFile() throws Exception {
listener.clear();
}
+ }
@Test
public void testMultiByteBreak() throws Exception {
@@ -410,7 +413,7 @@ public void testMultiByteBreak() throws Exception {
final boolean isWindows = osname.startsWith("Windows");
// Need to use UTF-8 to read & write the file otherwise it can be corrupted (depending on the default charset)
final Charset charsetUTF8 = StandardCharsets.UTF_8;
- tailer = new Tailer(file, charsetUTF8, listener, delay, false, isWindows, IOUtils.DEFAULT_BUFFER_SIZE);
+ try (Tailer tailer = new Tailer(file, charsetUTF8, listener, delay, false, isWindows, IOUtils.DEFAULT_BUFFER_SIZE)) {
final Thread thread = new Thread(tailer);
thread.start();
@@ -438,83 +441,91 @@ public void testMultiByteBreak() throws Exception {
}
}
}
+ }
@Test
public void testSimpleConstructor() throws Exception {
final File file = new File(temporaryFolder, "tailer-simple-constructor.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer(file, listener);
+ try (final Tailer tailer = new Tailer(file, listener)) {
final Thread thread = new Thread(tailer);
thread.start();
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testSimpleConstructorWithDelay() throws Exception {
final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS);
+ try (final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS)) {
final Thread thread = new Thread(tailer);
thread.start();
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testSimpleConstructorWithDelayAndFromStart() throws Exception {
final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false);
+ try (final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false)) {
final Thread thread = new Thread(tailer);
thread.start();
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testSimpleConstructorWithDelayAndFromStartWithBufferSize() throws Exception {
final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-buffersize.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, TEST_BUFFER_SIZE);
+ try (final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, TEST_BUFFER_SIZE)) {
final Thread thread = new Thread(tailer);
thread.start();
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testSimpleConstructorWithDelayAndFromStartWithReopen() throws Exception {
final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-reopen.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, false);
+ try (final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, false)) {
final Thread thread = new Thread(tailer);
thread.start();
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testSimpleConstructorWithDelayAndFromStartWithReopenAndBufferSize() throws Exception {
final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-reopen-and-buffersize.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE);
+ try (final Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
final Thread thread = new Thread(tailer);
thread.start();
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testSimpleConstructorWithDelayAndFromStartWithReopenAndBufferSizeAndCharset() throws Exception {
final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-reopen-and-buffersize-and-charset.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener(1);
- final Tailer tailer = new Tailer(file, StandardCharsets.UTF_8, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE);
+ try (final Tailer tailer = new Tailer(file, StandardCharsets.UTF_8, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
final Thread thread = new Thread(tailer);
thread.start();
validateTailer(listener, tailer, file);
}
+ }
@Test
public void testStopWithNoFile() throws Exception {
@@ -523,9 +534,9 @@ public void testStopWithNoFile() throws Exception {
final TestTailerListener listener = new TestTailerListener();
final int delay = 100;
final int idle = 50; // allow time for thread to work
- tailer = Tailer.create(file, listener, delay, false);
+ try (Tailer tailer = Tailer.create(file, listener, delay, false)) {
TestUtils.sleep(idle);
- tailer.stop();
+ }
TestUtils.sleep(delay + idle);
assertNull(listener.exception, "Should not generate Exception");
assertEquals(1, listener.initialized, "Expected init to be called");
@@ -541,11 +552,11 @@ public void testStopWithNoFileUsingExecutor() throws Exception {
final TestTailerListener listener = new TestTailerListener();
final int delay = 100;
final int idle = 50; // allow time for thread to work
- tailer = new Tailer(file, listener, delay, false);
+ try (Tailer tailer = new Tailer(file, listener, delay, false)) {
final Executor exec = new ScheduledThreadPoolExecutor(1);
exec.execute(tailer);
TestUtils.sleep(idle);
- tailer.stop();
+ }
TestUtils.sleep(delay + idle);
assertNull(listener.exception, "Should not generate Exception");
assertEquals(1, listener.initialized, "Expected init to be called");
@@ -564,7 +575,7 @@ public void testTailer() throws Exception {
final TestTailerListener listener = new TestTailerListener();
final String osname = System.getProperty("os.name");
final boolean isWindows = osname.startsWith("Windows");
- tailer = new Tailer(file, listener, delayMillis, false, isWindows);
+ try (Tailer tailer = new Tailer(file, listener, delayMillis, false, isWindows)) {
final Thread thread = new Thread(tailer);
thread.start();
@@ -620,6 +631,7 @@ public void testTailer() throws Exception {
// called
assertEquals(1, listener.rotated, "fileRotated should be be called");
}
+ }
@Test
public void testTailerEndOfFileReached() throws Exception {
@@ -631,7 +643,7 @@ public void testTailerEndOfFileReached() throws Exception {
final TestTailerListener listener = new TestTailerListener();
final String osname = System.getProperty("os.name");
final boolean isWindows = osname.startsWith("Windows");
- tailer = new Tailer(file, listener, delayMillis, false, isWindows);
+ try (Tailer tailer = new Tailer(file, listener, delayMillis, false, isWindows)) {
final Thread thread = new Thread(tailer);
thread.start();
@@ -650,6 +662,7 @@ public void testTailerEndOfFileReached() throws Exception {
// May be > 3 times due to underlying OS behavior wrt streams
assertTrue(listener.reachedEndOfFile >= 3, "end of file reached at least 3 times");
}
+ }
@Test
public void testTailerEof() throws Exception {
@@ -658,7 +671,7 @@ public void testTailerEof() throws Exception {
final File file = new File(temporaryFolder, "tailer2-test.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener();
- tailer = new Tailer(file, listener, delay, false);
+ try (Tailer tailer = new Tailer(file, listener, delay, false)) {
final Thread thread = new Thread(tailer);
thread.start();
@@ -678,17 +691,14 @@ public void testTailerEof() throws Exception {
listener.clear();
}
+ }
private void validateTailer(final TestTailerListener listener, final Tailer tailer, final File file) throws Exception {
- try {
write(file, "foo");
final int timeout = 30;
final TimeUnit timeoutUnit = TimeUnit.SECONDS;
assertTrue(listener.awaitExpectedLines(timeout, timeoutUnit), () -> String.format("await timed out after %s %s", timeout, timeoutUnit));
assertEquals(listener.getLines(), Lists.newArrayList("foo"), "lines");
- } finally {
- tailer.stop();
- }
}
/** Appends lines to a file */

Method that allocates should release resources.

Use try-with-resources with Tailer as an AutoCloseable.
All tests now manage its own resource.