View Javadoc
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 java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.io.Reader;
24  import java.io.Writer;
25  import java.nio.charset.Charset;
26  import java.nio.file.OpenOption;
27  import java.nio.file.Path;
28  import java.util.function.IntUnaryOperator;
29  
30  import org.apache.commons.io.Charsets;
31  import org.apache.commons.io.IOUtils;
32  import org.apache.commons.io.file.PathUtils;
33  
34  /**
35   * Abstracts building a typed instance of {@code T}.
36   *
37   * @param <T> the type of instances to build.
38   * @param <B> the type of builder subclass.
39   * @since 2.12.0
40   */
41  public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T, B>> extends AbstractOriginSupplier<T, B> {
42  
43      private static final int DEFAULT_MAX_VALUE = Integer.MAX_VALUE;
44  
45      private static final OpenOption[] DEFAULT_OPEN_OPTIONS = PathUtils.EMPTY_OPEN_OPTION_ARRAY;
46  
47      /**
48       * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
49       */
50      private int bufferSize = IOUtils.DEFAULT_BUFFER_SIZE;
51  
52      /**
53       * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
54       */
55      private int bufferSizeDefault = IOUtils.DEFAULT_BUFFER_SIZE;
56  
57      /**
58       * The maximum buffer size.
59       */
60      private int bufferSizeMax = DEFAULT_MAX_VALUE;
61  
62      /**
63       * The Charset, defaults to {@link Charset#defaultCharset()}.
64       */
65      private Charset charset = Charset.defaultCharset();
66  
67      /**
68       * The Charset, defaults to {@link Charset#defaultCharset()}.
69       */
70      private Charset charsetDefault = Charset.defaultCharset();
71  
72      private OpenOption[] openOptions = DEFAULT_OPEN_OPTIONS;
73  
74      /**
75       * The default checking behavior for a buffer size request. Throws a {@link IllegalArgumentException} by default.
76       */
77      private final IntUnaryOperator defaultSizeChecker = size -> size > bufferSizeMax ? throwIae(size, bufferSizeMax) : size;
78  
79      /**
80       * The checking behavior for a buffer size request.
81       */
82      private IntUnaryOperator bufferSizeChecker = defaultSizeChecker;
83  
84      /**
85       * Applies the buffer size request.
86       *
87       * @param size the size request.
88       * @return the size to use, usually the input, or can throw an unchecked exception, like {@link IllegalArgumentException}.
89       */
90      private int checkBufferSize(final int size) {
91          return bufferSizeChecker.applyAsInt(size);
92      }
93  
94      /**
95       * Gets the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
96       *
97       * @return the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
98       */
99      protected int getBufferSize() {
100         return bufferSize;
101     }
102 
103     /**
104      * Gets the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
105      *
106      * @return the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
107      */
108     protected int getBufferSizeDefault() {
109         return bufferSizeDefault;
110     }
111 
112     /**
113      * Gets a CharSequence from the origin with a Charset.
114      *
115      * @return An input stream
116      * @throws IllegalStateException         if the {@code origin} is {@code null}.
117      * @throws UnsupportedOperationException if the origin cannot be converted to a CharSequence.
118      * @throws IOException                   if an I/O error occurs.
119      * @see AbstractOrigin#getCharSequence(Charset)
120      * @since 2.13.0
121      */
122     protected CharSequence getCharSequence() throws IOException {
123         return checkOrigin().getCharSequence(getCharset());
124     }
125 
126     /**
127      * Gets the Charset, defaults to {@link Charset#defaultCharset()}.
128      *
129      * @return the Charset, defaults to {@link Charset#defaultCharset()}.
130      */
131     public Charset getCharset() {
132         return charset;
133     }
134 
135     /**
136      * Gets the Charset default, defaults to {@link Charset#defaultCharset()}.
137      *
138      * @return the Charset default, defaults to {@link Charset#defaultCharset()}.
139      */
140     protected Charset getCharsetDefault() {
141         return charsetDefault;
142     }
143 
144     /**
145      * Gets an InputStream from the origin with OpenOption[].
146      *
147      * @return An input stream
148      * @throws IllegalStateException         if the {@code origin} is {@code null}.
149      * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}.
150      * @throws IOException                   if an I/O error occurs.
151      * @see AbstractOrigin#getInputStream(OpenOption...)
152      * @see #getOpenOptions()
153      * @since 2.13.0
154      */
155     protected InputStream getInputStream() throws IOException {
156         return checkOrigin().getInputStream(getOpenOptions());
157     }
158 
159     /**
160      * Gets the OpenOption array.
161      *
162      * @return the OpenOption array.
163      */
164     protected OpenOption[] getOpenOptions() {
165         return openOptions;
166     }
167 
168     /**
169      * Gets an OutputStream from the origin with OpenOption[].
170      *
171      * @return An OutputStream
172      * @throws IllegalStateException         if the {@code origin} is {@code null}.
173      * @throws UnsupportedOperationException if the origin cannot be converted to an {@link OutputStream}.
174      * @throws IOException                   if an I/O error occurs.
175      * @see AbstractOrigin#getOutputStream(OpenOption...)
176      * @see #getOpenOptions()
177      * @since 2.13.0
178      */
179     protected OutputStream getOutputStream() throws IOException {
180         return checkOrigin().getOutputStream(getOpenOptions());
181     }
182 
183     /**
184      * Gets a Path from the origin.
185      *
186      * @return A Path
187      * @throws IllegalStateException         if the {@code origin} is {@code null}.
188      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Path}.
189      * @see AbstractOrigin#getPath()
190      * @since 2.13.0
191      */
192     protected Path getPath() {
193         return checkOrigin().getPath();
194     }
195 
196     /**
197      * Gets a Reader from the origin with a Charset.
198      *
199      * @return A Reader
200      * @throws IllegalStateException         if the {@code origin} is {@code null}.
201      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Reader}.
202      * @throws IOException                   if an I/O error occurs.
203      * @see AbstractOrigin#getReader(Charset)
204      * @see #getCharset()
205      * @since 2.16.0
206      */
207     protected Reader getReader() throws IOException {
208         return checkOrigin().getReader(getCharset());
209     }
210 
211     /**
212      * Gets a Writer from the origin with an OpenOption[].
213      *
214      * @return An writer.
215      * @throws IllegalStateException         if the {@code origin} is {@code null}.
216      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Writer}.
217      * @throws IOException                   if an I/O error occurs.
218      * @see AbstractOrigin#getOutputStream(OpenOption...)
219      * @see #getOpenOptions()
220      * @since 2.13.0
221      */
222     protected Writer getWriter() throws IOException {
223         return checkOrigin().getWriter(getCharset(), getOpenOptions());
224     }
225 
226     /**
227      * Sets the buffer size. Invalid input (bufferSize &lt;= 0) resets the value to its default.
228      * <p>
229      * Subclasses may ignore this setting.
230      * </p>
231      *
232      * @param bufferSize the buffer size.
233      * @return this.
234      */
235     public B setBufferSize(final int bufferSize) {
236         this.bufferSize = checkBufferSize(bufferSize > 0 ? bufferSize : bufferSizeDefault);
237         return asThis();
238     }
239 
240     /**
241      * Sets the buffer size.
242      * <p>
243      * Subclasses may ignore this setting.
244      * </p>
245      *
246      * @param bufferSize the buffer size, null resets to the default.
247      * @return this.
248      */
249     public B setBufferSize(final Integer bufferSize) {
250         setBufferSize(bufferSize != null ? bufferSize : bufferSizeDefault);
251         return asThis();
252     }
253 
254     /**
255      * Sets the buffer size checker function. Throws a {@link IllegalArgumentException} by default.
256      *
257      * @param bufferSizeChecker the buffer size checker function. null resets to the default behavior.
258      * @return this
259      * @since 2.14.0
260      */
261     public B setBufferSizeChecker(final IntUnaryOperator bufferSizeChecker) {
262         this.bufferSizeChecker = bufferSizeChecker != null ? bufferSizeChecker : defaultSizeChecker;
263         return asThis();
264     }
265 
266     /**
267      * Sets the buffer size for subclasses to initialize.
268      * <p>
269      * Subclasses may ignore this setting.
270      * </p>
271      *
272      * @param bufferSizeDefault the buffer size, null resets to the default.
273      * @return this.
274      */
275     protected B setBufferSizeDefault(final int bufferSizeDefault) {
276         this.bufferSizeDefault = bufferSizeDefault;
277         return asThis();
278     }
279 
280     /**
281      * 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
282      * exceeded, this methods throws an {@link IllegalArgumentException}.
283      *
284      * @param bufferSizeMax maximum buffer size checked by the buffer size checker.
285      * @return this.
286      * @since 2.14.0
287      */
288     public B setBufferSizeMax(final int bufferSizeMax) {
289         this.bufferSizeMax = bufferSizeMax > 0 ? bufferSizeMax : DEFAULT_MAX_VALUE;
290         return asThis();
291     }
292 
293     /**
294      * Sets the Charset.
295      * <p>
296      * Subclasses may ignore this setting.
297      * </p>
298      *
299      * @param charset the Charset, null resets to the default.
300      * @return this.
301      */
302     public B setCharset(final Charset charset) {
303         this.charset = Charsets.toCharset(charset, charsetDefault);
304         return asThis();
305     }
306 
307     /**
308      * Sets the Charset.
309      * <p>
310      * Subclasses may ignore this setting.
311      * </p>
312      *
313      * @param charset the Charset name, null resets to the default.
314      * @return this.
315      */
316     public B setCharset(final String charset) {
317         return setCharset(Charsets.toCharset(charset, charsetDefault));
318     }
319 
320     /**
321      * Sets the Charset default for subclasses to initialize.
322      * <p>
323      * Subclasses may ignore this setting.
324      * </p>
325      *
326      * @param defaultCharset the Charset name, null resets to the default.
327      * @return this.
328      */
329     protected B setCharsetDefault(final Charset defaultCharset) {
330         this.charsetDefault = defaultCharset;
331         return asThis();
332     }
333 
334     /**
335      * Sets the OpenOption[].
336      * <p>
337      * Normally used with InputStream, OutputStream, and Writer.
338      * </p>
339      * <p>
340      * Subclasses may ignore this setting.
341      * </p>
342      *
343      * @param openOptions the OpenOption[] name, null resets to the default.
344      * @return this.
345      * @since 2.13.0
346      * @see #setInputStream(InputStream)
347      * @see #setOutputStream(OutputStream)
348      * @see #setWriter(Writer)
349      */
350     public B setOpenOptions(final OpenOption... openOptions) {
351         this.openOptions = openOptions != null ? openOptions : DEFAULT_OPEN_OPTIONS;
352         return asThis();
353     }
354 
355     private int throwIae(final int size, final int max) {
356         throw new IllegalArgumentException(String.format("Request %,d exceeds maximum %,d", size, max));
357     }
358 }