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 <= 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 }