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 587a0354f0581fb6e32dda0ef14ca8f07c945c2d
Author: Gary Gregory <gardgreg...@gmail.com>
AuthorDate: Sun May 16 09:51:34 2021 -0400

    Add constructor ThresholdingOutputStream(int, IOConsumer, IOFunction)
    and make the class concrete.
---
 src/changes/changes.xml                            |  3 ++
 .../io/output/ThresholdingOutputStream.java        | 43 +++++++++++++++--
 .../io/output/ThresholdingOutputStreamTest.java    | 56 +++++++++++++++++++++-
 3 files changed, 97 insertions(+), 5 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1ae6fdd..3bdcbbb 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -210,6 +210,9 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         Add IOConsumer.noop().
       </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add constructor ThresholdingOutputStream(int, IOConsumer, IOFunction) 
and make the class concrete.
+      </action>
       <!-- UPDATES -->
       <action dev="ggregory" type="update" due-to="Dependabot">
         Update junit-jupiter from 5.6.2 to 5.7.0 #153.
diff --git 
a/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java 
b/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java
index e432cd4..876b8fd 100644
--- a/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java
+++ b/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java
@@ -19,6 +19,9 @@ package org.apache.commons.io.output;
 import java.io.IOException;
 import java.io.OutputStream;
 
+import org.apache.commons.io.function.IOConsumer;
+import org.apache.commons.io.function.IOFunction;
+
 /**
  * An output stream which triggers an event when a specified number of bytes 
of data have been written to it. The event
  * can be used, for example, to throw an exception if a maximum has been 
reached, or to switch the underlying stream
@@ -32,7 +35,12 @@ import java.io.OutputStream;
  * when a pending write operation would cause the threshold to be exceeded.
  * </p>
  */
-public abstract class ThresholdingOutputStream extends OutputStream {
+public class ThresholdingOutputStream extends OutputStream {
+
+    /**
+     * Noop output stream getter function.
+     */
+    private static IOFunction<ThresholdingOutputStream, OutputStream> 
NOOP_OS_GETTER = os -> NullOutputStream.NULL_OUTPUT_STREAM;
 
     /**
      * The threshold at which the event will be triggered.
@@ -40,6 +48,16 @@ public abstract class ThresholdingOutputStream extends 
OutputStream {
     private final int threshold;
 
     /**
+     * Accepts reaching the threshold.
+     */
+    private final IOConsumer<ThresholdingOutputStream> thresholdConsumer;
+
+    /**
+     * Gets the output stream.
+     */
+    private final IOFunction<ThresholdingOutputStream, OutputStream> 
outputStreamGetter;
+
+    /**
      * The number of bytes written to the output stream.
      */
     private long written;
@@ -55,7 +73,22 @@ public abstract class ThresholdingOutputStream extends 
OutputStream {
      * @param threshold The number of bytes at which to trigger an event.
      */
     public ThresholdingOutputStream(final int threshold) {
+        this(threshold, IOConsumer.noop(), NOOP_OS_GETTER);
+    }
+
+    /**
+     * Constructs an instance of this class which will trigger an event at the 
specified threshold.
+     *
+     * @param threshold The number of bytes at which to trigger an event.
+     * @param thresholdConsumer Accepts reaching the threshold.
+     * @param outputStreamGetter Gets the output stream.
+     * @since 2.9.0
+     */
+    public ThresholdingOutputStream(final int threshold, final 
IOConsumer<ThresholdingOutputStream> thresholdConsumer,
+        final IOFunction<ThresholdingOutputStream, OutputStream> 
outputStreamGetter) {
         this.threshold = threshold;
+        this.thresholdConsumer = thresholdConsumer == null ? IOConsumer.noop() 
: thresholdConsumer;
+        this.outputStreamGetter = outputStreamGetter == null ? NOOP_OS_GETTER 
: outputStreamGetter;
     }
 
     /**
@@ -116,7 +149,9 @@ public abstract class ThresholdingOutputStream extends 
OutputStream {
      *
      * @throws IOException if an error occurs.
      */
-    protected abstract OutputStream getStream() throws IOException;
+    protected OutputStream getStream() throws IOException {
+        return outputStreamGetter.apply(this);
+    }
 
     /**
      * Returns the threshold, in bytes, at which an event will be triggered.
@@ -162,7 +197,9 @@ public abstract class ThresholdingOutputStream extends 
OutputStream {
      *
      * @throws IOException if an error occurs.
      */
-    protected abstract void thresholdReached() throws IOException;
+    protected void thresholdReached() throws IOException {
+        thresholdConsumer.accept(this);
+    }
 
     /**
      * Writes {@code b.length} bytes from the specified byte array to this 
output stream.
diff --git 
a/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java 
b/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java
index 4de8e4b..1bcfc12 100644
--- 
a/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java
+++ 
b/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java
@@ -18,6 +18,7 @@
 package org.apache.commons.io.output;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.IOException;
@@ -46,10 +47,61 @@ public class ThresholdingOutputStreamTest {
                 reached.set(true);
             }
         }) {
-            tos.write(12);
+            tos.write('a');
             assertFalse(reached.get());
-            tos.write(12);
+            tos.write('a');
             assertTrue(reached.get());
         }
     }
+
+    @Test
+    public void testThresholdIOConsumer() throws Exception {
+        final AtomicBoolean reached = new AtomicBoolean();
+        // Null threshold consumer
+        reached.set(false);
+        try (final ThresholdingOutputStream tos = new 
ThresholdingOutputStream(1, null,
+            os -> new ByteArrayOutputStream(4))) {
+            tos.write('a');
+            assertFalse(reached.get());
+            tos.write('a');
+            assertFalse(reached.get());
+        }
+        // Null output stream function
+        reached.set(false);
+        try (final ThresholdingOutputStream tos = new 
ThresholdingOutputStream(1, os -> reached.set(true), null)) {
+            tos.write('a');
+            assertFalse(reached.get());
+            tos.write('a');
+            assertTrue(reached.get());
+        }
+        // non-null inputs.
+        reached.set(false);
+        try (final ThresholdingOutputStream tos = new 
ThresholdingOutputStream(1, os -> reached.set(true),
+            os -> new ByteArrayOutputStream(4))) {
+            tos.write('a');
+            assertFalse(reached.get());
+            tos.write('a');
+            assertTrue(reached.get());
+        }
+    }
+
+    @Test
+    public void testThresholdIOConsumerIOException() throws Exception {
+        try (final ThresholdingOutputStream tos = new 
ThresholdingOutputStream(1, os -> {
+            throw new IOException("Threshold reached.");
+        }, os -> new ByteArrayOutputStream(4))) {
+            tos.write('a');
+            assertThrows(IOException.class, () -> tos.write('a'));
+        }
+    }
+
+    @Test
+    public void testThresholdIOConsumerUncheckedException() throws Exception {
+        try (final ThresholdingOutputStream tos = new 
ThresholdingOutputStream(1, os -> {
+            throw new IllegalStateException("Threshold reached.");
+        }, os -> new ByteArrayOutputStream(4))) {
+            tos.write('a');
+            assertThrows(IllegalStateException.class, () -> tos.write('a'));
+        }
+    }
 }
\ No newline at end of file

Reply via email to