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 4a298b781b5d6b007f39f5ff5661991ed6c9b889
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Mon Jul 10 09:46:18 2023 -0400

    Add AbstractStreamBuilder.setBufferSizeMax(int).
    
    Add IntToIntFunction
    Add AbstractStreamBuilder.setBufferSizeChecker(IntToIntFunction)
---
 src/changes/changes.xml                            |  9 +++
 .../commons/io/build/AbstractStreamBuilder.java    | 68 ++++++++++++++++++++--
 .../commons/io/function/IntToIntFunction.java      | 52 +++++++++++++++++
 .../io/build/AbstractStreamBuilderTest.java        | 68 ++++++++++++++++++++++
 4 files changed, 191 insertions(+), 6 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 79aa9a53..4e713b8a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -107,6 +107,15 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         Add DeferredFileOutputStream.Builder.setDirectory(Path).
       </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add IntToIntFunction.
+      </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add AbstractStreamBuilder.setBufferSizeChecker(IntToIntFunction).
+      </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add AbstractStreamBuilder.setBufferSizeMax(int).
+      </action>
       <!-- UPDATE -->
       <action dev="ggregory" type="update" due-to="Dependabot">
         Bump jimfs from 1.2 to 1.3.0 #465 (tests).
diff --git 
a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java 
b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java
index 8beccd93..d7c2fc3c 100644
--- a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java
+++ b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java
@@ -24,10 +24,10 @@ import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.file.OpenOption;
 import java.nio.file.Path;
-
 import org.apache.commons.io.Charsets;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.file.PathUtils;
+import org.apache.commons.io.function.IntToIntFunction;
 
 /**
  * Abstracts building a typed instance of {@code T}.
@@ -38,6 +38,8 @@ import org.apache.commons.io.file.PathUtils;
  */
 public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T, B>> extends AbstractOriginSupplier<T, B> {
 
+    private static final int DEFAULT_MAX_VALUE = Integer.MAX_VALUE;
+
     private static final OpenOption[] DEFAULT_OPEN_OPTIONS = 
PathUtils.EMPTY_OPEN_OPTION_ARRAY;
 
     /**
@@ -50,6 +52,11 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
      */
     private int bufferSizeDefault = IOUtils.DEFAULT_BUFFER_SIZE;
 
+    /**
+     * The maximum buffer size.
+     */
+    private int bufferSizeMax = DEFAULT_MAX_VALUE;
+
     /**
      * The Charset, defaults to {@link Charset#defaultCharset()}.
      */
@@ -62,6 +69,26 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
 
     private OpenOption[] openOptions = DEFAULT_OPEN_OPTIONS;
 
+    /**
+     * The default checking behavior for a buffer size request. Throws a 
{@link IllegalArgumentException} by default.
+     */
+    private final IntToIntFunction defaultSizeChecker = size -> size > 
bufferSizeMax ? throwIae(size, bufferSizeMax) : size;
+
+    /**
+     * The checking behavior for a buffer size request.
+     */
+    private IntToIntFunction bufferSizeChecker = defaultSizeChecker;
+
+    /**
+     * Applies the buffer size request.
+     *
+     * @param size the size request.
+     * @return the size to use, usually the input, or can throw an unchecked 
exception, like {@link IllegalArgumentException}.
+     */
+    private int checkBufferSize(final int size) {
+        return bufferSizeChecker.applyAsInt(size);
+    }
+
     /**
      * Gets the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} 
({@value IOUtils#DEFAULT_BUFFER_SIZE}).
      *
@@ -86,7 +113,7 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
      * @return An input stream
      * @throws IOException                   if an I/O error occurs.
      * @throws UnsupportedOperationException if the origin cannot be converted 
to a CharSequence.
-     * @throws IllegalStateException if the {@code origin} is {@code null}.
+     * @throws IllegalStateException         if the {@code origin} is {@code 
null}.
      * @see AbstractOrigin#getCharSequence(Charset)
      * @since 2.13.0
      */
@@ -136,7 +163,7 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
      * @return An OutputStream
      * @throws IOException                   if an I/O error occurs.
      * @throws UnsupportedOperationException if the origin cannot be converted 
to an OututStream.
-     * @throws IllegalStateException if the {@code origin} is {@code null}.
+     * @throws IllegalStateException         if the {@code origin} is {@code 
null}.
      * @see AbstractOrigin#getOutputStream(OpenOption...)
      * @since 2.13.0
      */
@@ -149,7 +176,7 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
      *
      * @return A Path
      * @throws UnsupportedOperationException if the origin cannot be converted 
to a Path.
-     * @throws IllegalStateException if the {@code origin} is {@code null}.
+     * @throws IllegalStateException         if the {@code origin} is {@code 
null}.
      * @see AbstractOrigin#getPath()
      * @since 2.13.0
      */
@@ -163,7 +190,7 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
      * @return An writer.
      * @throws IOException                   if an I/O error occurs.
      * @throws UnsupportedOperationException if the origin cannot be converted 
to a Writer.
-     * @throws IllegalStateException if the {@code origin} is {@code null}.
+     * @throws IllegalStateException         if the {@code origin} is {@code 
null}.
      * @see AbstractOrigin#getOutputStream(OpenOption...)
      * @since 2.13.0
      */
@@ -181,7 +208,7 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
      * @return this.
      */
     public B setBufferSize(final int bufferSize) {
-        this.bufferSize = bufferSize > 0 ? bufferSize : bufferSizeDefault;
+        this.bufferSize = checkBufferSize(bufferSize > 0 ? bufferSize : 
bufferSizeDefault);
         return asThis();
     }
 
@@ -199,6 +226,18 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
         return asThis();
     }
 
+    /**
+     * Sets the buffer size checker function. Throws a {@link 
IllegalArgumentException} by default.
+     *
+     * @param bufferSizeChecker the buffer size checker function. null resets 
to the default behavior.
+     * @return this
+     * @since 2.14.0
+     */
+    public B setBufferSizeChecker(final IntToIntFunction bufferSizeChecker) {
+        this.bufferSizeChecker = bufferSizeChecker != null ? bufferSizeChecker 
: defaultSizeChecker;
+        return asThis();
+    }
+
     /**
      * Sets the buffer size for subclasses to initialize.
      * <p>
@@ -213,6 +252,19 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
         return asThis();
     }
 
+    /**
+     * The maximum buffer size checked by the buffer size checker. Values less 
or equal to 0, resets to the int max value. By default, if this value is
+     * exceeded, this methods throws an {@link IllegalArgumentException}.
+     *
+     * @param bufferSizeMax maximum buffer size checked by the buffer size 
checker.
+     * @return this.
+     * @since 2.14.0
+     */
+    public B setBufferSizeMax(final int bufferSizeMax) {
+        this.bufferSizeMax = bufferSizeMax > 0 ? bufferSizeMax : 
DEFAULT_MAX_VALUE;
+        return asThis();
+    }
+
     /**
      * Sets the Charset.
      * <p>
@@ -274,4 +326,8 @@ public abstract class AbstractStreamBuilder<T, B extends 
AbstractStreamBuilder<T
         this.openOptions = openOptions != null ? openOptions : 
DEFAULT_OPEN_OPTIONS;
         return asThis();
     }
+
+    private int throwIae(final int size, final int max) {
+        throw new IllegalArgumentException(String.format("Request %,d exceeds 
maximum %,d", size, max));
+    }
 }
diff --git a/src/main/java/org/apache/commons/io/function/IntToIntFunction.java 
b/src/main/java/org/apache/commons/io/function/IntToIntFunction.java
new file mode 100644
index 00000000..57cea6c0
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/function/IntToIntFunction.java
@@ -0,0 +1,52 @@
+/*
+ * 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.function;
+
+import java.util.function.Function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces an 
int-valued result. This is the {@code int}-to-{@code int} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>
+ * This is a <a href="package-summary.html">functional interface</a> whose 
functional method is {@link #applyAsInt(int)}.
+ * </p>
+ *
+ * @see Function
+ * @since 2.14.0
+ */
+@FunctionalInterface
+public interface IntToIntFunction {
+
+    /**
+     * Returns a function that always returns its input argument.
+     *
+     * @return a function that always returns its input argument
+     */
+    static IntToIntFunction identity() {
+        return i -> i;
+    }
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(int value);
+}
\ No newline at end of file
diff --git 
a/src/test/java/org/apache/commons/io/build/AbstractStreamBuilderTest.java 
b/src/test/java/org/apache/commons/io/build/AbstractStreamBuilderTest.java
new file mode 100644
index 00000000..425ba4a5
--- /dev/null
+++ b/src/test/java/org/apache/commons/io/build/AbstractStreamBuilderTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.build;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link AbstractStreamBuilder}.
+ */
+public class AbstractStreamBuilderTest {
+
+    public static class Builder extends AbstractStreamBuilder<char[], Builder> 
{
+
+        @Override
+        public char[] get() {
+            final char[] arr = new char[getBufferSize()];
+            Arrays.fill(arr, 'a');
+            return arr;
+        }
+
+    }
+
+    private void assertResult(final char[] arr, final int size) {
+        assertNotNull(arr);
+        assertEquals(size, arr.length);
+        for (final char c : arr) {
+            assertEquals('a', c);
+        }
+    }
+
+    protected Builder builder() {
+        return new Builder();
+    }
+
+    @Test
+    public void testBufferSizeChecker() {
+        // sanity
+        final Builder builder = builder();
+        assertResult(builder.get(), builder.getBufferSize());
+        // basic failure
+        assertThrows(IllegalArgumentException.class, () -> 
builder().setBufferSizeMax(2).setBufferSize(3));
+        // reset
+        
assertResult(builder.setBufferSizeMax(2).setBufferSizeMax(0).setBufferSize(3).get(),
 3);
+        // resize
+        assertResult(builder().setBufferSizeMax(2).setBufferSizeChecker(i -> 
100).setBufferSize(3).get(), 100);
+    }
+}

Reply via email to