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