Skip to content

Commit 4a298b7

Browse files
committed
Add AbstractStreamBuilder.setBufferSizeMax(int).
Add IntToIntFunction Add AbstractStreamBuilder.setBufferSizeChecker(IntToIntFunction)
1 parent b57c42a commit 4a298b7

4 files changed

Lines changed: 191 additions & 6 deletions

File tree

src/changes/changes.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ The <action> type attribute can be add,update,fix,remove.
107107
<action dev="ggregory" type="add" due-to="Gary Gregory">
108108
Add DeferredFileOutputStream.Builder.setDirectory(Path).
109109
</action>
110+
<action dev="ggregory" type="add" due-to="Gary Gregory">
111+
Add IntToIntFunction.
112+
</action>
113+
<action dev="ggregory" type="add" due-to="Gary Gregory">
114+
Add AbstractStreamBuilder.setBufferSizeChecker(IntToIntFunction).
115+
</action>
116+
<action dev="ggregory" type="add" due-to="Gary Gregory">
117+
Add AbstractStreamBuilder.setBufferSizeMax(int).
118+
</action>
110119
<!-- UPDATE -->
111120
<action dev="ggregory" type="update" due-to="Dependabot">
112121
Bump jimfs from 1.2 to 1.3.0 #465 (tests).

src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
import java.nio.charset.Charset;
2525
import java.nio.file.OpenOption;
2626
import java.nio.file.Path;
27-
2827
import org.apache.commons.io.Charsets;
2928
import org.apache.commons.io.IOUtils;
3029
import org.apache.commons.io.file.PathUtils;
30+
import org.apache.commons.io.function.IntToIntFunction;
3131

3232
/**
3333
* Abstracts building a typed instance of {@code T}.
@@ -38,6 +38,8 @@
3838
*/
3939
public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T, B>> extends AbstractOriginSupplier<T, B> {
4040

41+
private static final int DEFAULT_MAX_VALUE = Integer.MAX_VALUE;
42+
4143
private static final OpenOption[] DEFAULT_OPEN_OPTIONS = PathUtils.EMPTY_OPEN_OPTION_ARRAY;
4244

4345
/**
@@ -50,6 +52,11 @@ public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T
5052
*/
5153
private int bufferSizeDefault = IOUtils.DEFAULT_BUFFER_SIZE;
5254

55+
/**
56+
* The maximum buffer size.
57+
*/
58+
private int bufferSizeMax = DEFAULT_MAX_VALUE;
59+
5360
/**
5461
* The Charset, defaults to {@link Charset#defaultCharset()}.
5562
*/
@@ -62,6 +69,26 @@ public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T
6269

6370
private OpenOption[] openOptions = DEFAULT_OPEN_OPTIONS;
6471

72+
/**
73+
* The default checking behavior for a buffer size request. Throws a {@link IllegalArgumentException} by default.
74+
*/
75+
private final IntToIntFunction defaultSizeChecker = size -> size > bufferSizeMax ? throwIae(size, bufferSizeMax) : size;
76+
77+
/**
78+
* The checking behavior for a buffer size request.
79+
*/
80+
private IntToIntFunction bufferSizeChecker = defaultSizeChecker;
81+
82+
/**
83+
* Applies the buffer size request.
84+
*
85+
* @param size the size request.
86+
* @return the size to use, usually the input, or can throw an unchecked exception, like {@link IllegalArgumentException}.
87+
*/
88+
private int checkBufferSize(final int size) {
89+
return bufferSizeChecker.applyAsInt(size);
90+
}
91+
6592
/**
6693
* Gets the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
6794
*
@@ -86,7 +113,7 @@ protected int getBufferSizeDefault() {
86113
* @return An input stream
87114
* @throws IOException if an I/O error occurs.
88115
* @throws UnsupportedOperationException if the origin cannot be converted to a CharSequence.
89-
* @throws IllegalStateException if the {@code origin} is {@code null}.
116+
* @throws IllegalStateException if the {@code origin} is {@code null}.
90117
* @see AbstractOrigin#getCharSequence(Charset)
91118
* @since 2.13.0
92119
*/
@@ -136,7 +163,7 @@ protected OpenOption[] getOpenOptions() {
136163
* @return An OutputStream
137164
* @throws IOException if an I/O error occurs.
138165
* @throws UnsupportedOperationException if the origin cannot be converted to an OututStream.
139-
* @throws IllegalStateException if the {@code origin} is {@code null}.
166+
* @throws IllegalStateException if the {@code origin} is {@code null}.
140167
* @see AbstractOrigin#getOutputStream(OpenOption...)
141168
* @since 2.13.0
142169
*/
@@ -149,7 +176,7 @@ protected OutputStream getOutputStream() throws IOException {
149176
*
150177
* @return A Path
151178
* @throws UnsupportedOperationException if the origin cannot be converted to a Path.
152-
* @throws IllegalStateException if the {@code origin} is {@code null}.
179+
* @throws IllegalStateException if the {@code origin} is {@code null}.
153180
* @see AbstractOrigin#getPath()
154181
* @since 2.13.0
155182
*/
@@ -163,7 +190,7 @@ protected Path getPath() {
163190
* @return An writer.
164191
* @throws IOException if an I/O error occurs.
165192
* @throws UnsupportedOperationException if the origin cannot be converted to a Writer.
166-
* @throws IllegalStateException if the {@code origin} is {@code null}.
193+
* @throws IllegalStateException if the {@code origin} is {@code null}.
167194
* @see AbstractOrigin#getOutputStream(OpenOption...)
168195
* @since 2.13.0
169196
*/
@@ -181,7 +208,7 @@ protected Writer getWriter() throws IOException {
181208
* @return this.
182209
*/
183210
public B setBufferSize(final int bufferSize) {
184-
this.bufferSize = bufferSize > 0 ? bufferSize : bufferSizeDefault;
211+
this.bufferSize = checkBufferSize(bufferSize > 0 ? bufferSize : bufferSizeDefault);
185212
return asThis();
186213
}
187214

@@ -199,6 +226,18 @@ public B setBufferSize(final Integer bufferSize) {
199226
return asThis();
200227
}
201228

229+
/**
230+
* Sets the buffer size checker function. Throws a {@link IllegalArgumentException} by default.
231+
*
232+
* @param bufferSizeChecker the buffer size checker function. null resets to the default behavior.
233+
* @return this
234+
* @since 2.14.0
235+
*/
236+
public B setBufferSizeChecker(final IntToIntFunction bufferSizeChecker) {
237+
this.bufferSizeChecker = bufferSizeChecker != null ? bufferSizeChecker : defaultSizeChecker;
238+
return asThis();
239+
}
240+
202241
/**
203242
* Sets the buffer size for subclasses to initialize.
204243
* <p>
@@ -213,6 +252,19 @@ protected B setBufferSizeDefault(final int bufferSizeDefault) {
213252
return asThis();
214253
}
215254

255+
/**
256+
* 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
257+
* exceeded, this methods throws an {@link IllegalArgumentException}.
258+
*
259+
* @param bufferSizeMax maximum buffer size checked by the buffer size checker.
260+
* @return this.
261+
* @since 2.14.0
262+
*/
263+
public B setBufferSizeMax(final int bufferSizeMax) {
264+
this.bufferSizeMax = bufferSizeMax > 0 ? bufferSizeMax : DEFAULT_MAX_VALUE;
265+
return asThis();
266+
}
267+
216268
/**
217269
* Sets the Charset.
218270
* <p>
@@ -274,4 +326,8 @@ public B setOpenOptions(final OpenOption... openOptions) {
274326
this.openOptions = openOptions != null ? openOptions : DEFAULT_OPEN_OPTIONS;
275327
return asThis();
276328
}
329+
330+
private int throwIae(final int size, final int max) {
331+
throw new IllegalArgumentException(String.format("Request %,d exceeds maximum %,d", size, max));
332+
}
277333
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.commons.io.function;
19+
20+
import java.util.function.Function;
21+
22+
/**
23+
* Represents a function that accepts an int-valued argument and produces an int-valued result. This is the {@code int}-to-{@code int} primitive
24+
* specialization for {@link Function}.
25+
*
26+
* <p>
27+
* This is a <a href="package-summary.html">functional interface</a> whose functional method is {@link #applyAsInt(int)}.
28+
* </p>
29+
*
30+
* @see Function
31+
* @since 2.14.0
32+
*/
33+
@FunctionalInterface
34+
public interface IntToIntFunction {
35+
36+
/**
37+
* Returns a function that always returns its input argument.
38+
*
39+
* @return a function that always returns its input argument
40+
*/
41+
static IntToIntFunction identity() {
42+
return i -> i;
43+
}
44+
45+
/**
46+
* Applies this function to the given argument.
47+
*
48+
* @param value the function argument
49+
* @return the function result
50+
*/
51+
int applyAsInt(int value);
52+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.commons.io.build;
19+
20+
import static org.junit.jupiter.api.Assertions.assertEquals;
21+
import static org.junit.jupiter.api.Assertions.assertNotNull;
22+
import static org.junit.jupiter.api.Assertions.assertThrows;
23+
24+
import java.util.Arrays;
25+
26+
import org.junit.jupiter.api.Test;
27+
28+
/**
29+
* Tests {@link AbstractStreamBuilder}.
30+
*/
31+
public class AbstractStreamBuilderTest {
32+
33+
public static class Builder extends AbstractStreamBuilder<char[], Builder> {
34+
35+
@Override
36+
public char[] get() {
37+
final char[] arr = new char[getBufferSize()];
38+
Arrays.fill(arr, 'a');
39+
return arr;
40+
}
41+
42+
}
43+
44+
private void assertResult(final char[] arr, final int size) {
45+
assertNotNull(arr);
46+
assertEquals(size, arr.length);
47+
for (final char c : arr) {
48+
assertEquals('a', c);
49+
}
50+
}
51+
52+
protected Builder builder() {
53+
return new Builder();
54+
}
55+
56+
@Test
57+
public void testBufferSizeChecker() {
58+
// sanity
59+
final Builder builder = builder();
60+
assertResult(builder.get(), builder.getBufferSize());
61+
// basic failure
62+
assertThrows(IllegalArgumentException.class, () -> builder().setBufferSizeMax(2).setBufferSize(3));
63+
// reset
64+
assertResult(builder.setBufferSizeMax(2).setBufferSizeMax(0).setBufferSize(3).get(), 3);
65+
// resize
66+
assertResult(builder().setBufferSizeMax(2).setBufferSizeChecker(i -> 100).setBufferSize(3).get(), 100);
67+
}
68+
}

0 commit comments

Comments
 (0)