001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.io.build; 019 020import java.io.File; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024import java.io.RandomAccessFile; 025import java.io.Reader; 026import java.io.Writer; 027import java.nio.charset.Charset; 028import java.nio.file.OpenOption; 029import java.nio.file.Path; 030import java.util.function.IntUnaryOperator; 031 032import org.apache.commons.io.Charsets; 033import org.apache.commons.io.IOUtils; 034import org.apache.commons.io.file.PathUtils; 035 036/** 037 * Abstracts building a typed instance of {@code T}. 038 * 039 * @param <T> the type of instances to build. 040 * @param <B> the type of builder subclass. 041 * @since 2.12.0 042 */ 043public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T, B>> extends AbstractOriginSupplier<T, B> { 044 045 private static final int DEFAULT_MAX_VALUE = Integer.MAX_VALUE; 046 047 private static final OpenOption[] DEFAULT_OPEN_OPTIONS = PathUtils.EMPTY_OPEN_OPTION_ARRAY; 048 049 /** 050 * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 051 */ 052 private int bufferSize = IOUtils.DEFAULT_BUFFER_SIZE; 053 054 /** 055 * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 056 */ 057 private int bufferSizeDefault = IOUtils.DEFAULT_BUFFER_SIZE; 058 059 /** 060 * The maximum buffer size. 061 */ 062 private int bufferSizeMax = DEFAULT_MAX_VALUE; 063 064 /** 065 * The Charset, defaults to {@link Charset#defaultCharset()}. 066 */ 067 private Charset charset = Charset.defaultCharset(); 068 069 /** 070 * The Charset, defaults to {@link Charset#defaultCharset()}. 071 */ 072 private Charset charsetDefault = Charset.defaultCharset(); 073 074 private OpenOption[] openOptions = DEFAULT_OPEN_OPTIONS; 075 076 /** 077 * The default checking behavior for a buffer size request. Throws a {@link IllegalArgumentException} by default. 078 */ 079 private final IntUnaryOperator defaultSizeChecker = size -> size > bufferSizeMax ? throwIae(size, bufferSizeMax) : size; 080 081 /** 082 * The checking behavior for a buffer size request. 083 */ 084 private IntUnaryOperator bufferSizeChecker = defaultSizeChecker; 085 086 /** 087 * Constructs a new instance for subclasses. 088 */ 089 public AbstractStreamBuilder() { 090 // empty 091 } 092 093 /** 094 * Applies the buffer size request. 095 * 096 * @param size the size request. 097 * @return the size to use, usually the input, or can throw an unchecked exception, like {@link IllegalArgumentException}. 098 */ 099 private int checkBufferSize(final int size) { 100 return bufferSizeChecker.applyAsInt(size); 101 } 102 103 /** 104 * Gets the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 105 * 106 * @return the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 107 */ 108 public int getBufferSize() { 109 return bufferSize; 110 } 111 112 /** 113 * Gets the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 114 * 115 * @return the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 116 */ 117 public int getBufferSizeDefault() { 118 return bufferSizeDefault; 119 } 120 121 /** 122 * Gets a CharSequence from the origin with a Charset. 123 * 124 * @return An input stream 125 * @throws IllegalStateException if the {@code origin} is {@code null}. 126 * @throws UnsupportedOperationException if the origin cannot be converted to a CharSequence. 127 * @throws IOException if an I/O error occurs. 128 * @see AbstractOrigin#getCharSequence(Charset) 129 * @since 2.13.0 130 */ 131 public CharSequence getCharSequence() throws IOException { 132 return checkOrigin().getCharSequence(getCharset()); 133 } 134 135 /** 136 * Gets the Charset, defaults to {@link Charset#defaultCharset()}. 137 * 138 * @return the Charset, defaults to {@link Charset#defaultCharset()}. 139 */ 140 public Charset getCharset() { 141 return charset; 142 } 143 144 /** 145 * Gets the Charset default, defaults to {@link Charset#defaultCharset()}. 146 * 147 * @return the Charset default, defaults to {@link Charset#defaultCharset()}. 148 */ 149 public Charset getCharsetDefault() { 150 return charsetDefault; 151 } 152 153 /** 154 * Gets a File from the origin. 155 * 156 * @return A File 157 * @throws IllegalStateException if the {@code origin} is {@code null}. 158 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link File}. 159 * @see AbstractOrigin#getPath() 160 * @since 2.18.0 161 */ 162 public File getFile() { 163 return checkOrigin().getFile(); 164 } 165 166 /** 167 * Gets an InputStream from the origin with OpenOption[]. 168 * 169 * @return An input stream 170 * @throws IllegalStateException if the {@code origin} is {@code null}. 171 * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}. 172 * @throws IOException if an I/O error occurs. 173 * @see AbstractOrigin#getInputStream(OpenOption...) 174 * @see #getOpenOptions() 175 * @since 2.13.0 176 */ 177 public InputStream getInputStream() throws IOException { 178 return checkOrigin().getInputStream(getOpenOptions()); 179 } 180 181 /** 182 * Gets the OpenOption array. 183 * 184 * @return the OpenOption array. 185 */ 186 public OpenOption[] getOpenOptions() { 187 return openOptions; 188 } 189 190 /** 191 * Gets an OutputStream from the origin with OpenOption[]. 192 * 193 * @return An OutputStream 194 * @throws IllegalStateException if the {@code origin} is {@code null}. 195 * @throws UnsupportedOperationException if the origin cannot be converted to an {@link OutputStream}. 196 * @throws IOException if an I/O error occurs. 197 * @see AbstractOrigin#getOutputStream(OpenOption...) 198 * @see #getOpenOptions() 199 * @since 2.13.0 200 */ 201 public OutputStream getOutputStream() throws IOException { 202 return checkOrigin().getOutputStream(getOpenOptions()); 203 } 204 205 /** 206 * Gets a Path from the origin. 207 * 208 * @return A Path 209 * @throws IllegalStateException if the {@code origin} is {@code null}. 210 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Path}. 211 * @see AbstractOrigin#getPath() 212 * @since 2.13.0 213 */ 214 public Path getPath() { 215 return checkOrigin().getPath(); 216 } 217 218 /** 219 * Gets a RandomAccessFile from the origin. 220 * 221 * @return A RandomAccessFile 222 * @throws IllegalStateException if the {@code origin} is {@code null}. 223 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link RandomAccessFile}. 224 * @throws IOException if an I/O error occurs. 225 * @since 2.18.0 226 */ 227 public RandomAccessFile getRandomAccessFile() throws IOException { 228 return checkOrigin().getRandomAccessFile(getOpenOptions()); 229 } 230 231 /** 232 * Gets a Reader from the origin with a Charset. 233 * 234 * @return A Reader 235 * @throws IllegalStateException if the {@code origin} is {@code null}. 236 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Reader}. 237 * @throws IOException if an I/O error occurs. 238 * @see AbstractOrigin#getReader(Charset) 239 * @see #getCharset() 240 * @since 2.16.0 241 */ 242 public Reader getReader() throws IOException { 243 return checkOrigin().getReader(getCharset()); 244 } 245 246 /** 247 * Gets a Writer from the origin with an OpenOption[]. 248 * 249 * @return An writer. 250 * @throws IllegalStateException if the {@code origin} is {@code null}. 251 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Writer}. 252 * @throws IOException if an I/O error occurs. 253 * @see AbstractOrigin#getOutputStream(OpenOption...) 254 * @see #getOpenOptions() 255 * @since 2.13.0 256 */ 257 public Writer getWriter() throws IOException { 258 return checkOrigin().getWriter(getCharset(), getOpenOptions()); 259 } 260 261 /** 262 * Sets the buffer size. Invalid input (bufferSize <= 0) resets the value to its default. 263 * <p> 264 * Subclasses may ignore this setting. 265 * </p> 266 * 267 * @param bufferSize the buffer size. 268 * @return {@code this} instance. 269 */ 270 public B setBufferSize(final int bufferSize) { 271 this.bufferSize = checkBufferSize(bufferSize > 0 ? bufferSize : bufferSizeDefault); 272 return asThis(); 273 } 274 275 /** 276 * Sets the buffer size. 277 * <p> 278 * Subclasses may ignore this setting. 279 * </p> 280 * 281 * @param bufferSize the buffer size, null resets to the default. 282 * @return {@code this} instance. 283 */ 284 public B setBufferSize(final Integer bufferSize) { 285 setBufferSize(bufferSize != null ? bufferSize : bufferSizeDefault); 286 return asThis(); 287 } 288 289 /** 290 * Sets the buffer size checker function. Throws a {@link IllegalArgumentException} by default. 291 * 292 * @param bufferSizeChecker the buffer size checker function. null resets to the default behavior. 293 * @return {@code this} instance. 294 * @since 2.14.0 295 */ 296 public B setBufferSizeChecker(final IntUnaryOperator bufferSizeChecker) { 297 this.bufferSizeChecker = bufferSizeChecker != null ? bufferSizeChecker : defaultSizeChecker; 298 return asThis(); 299 } 300 301 /** 302 * Sets the buffer size for subclasses to initialize. 303 * <p> 304 * Subclasses may ignore this setting. 305 * </p> 306 * 307 * @param bufferSizeDefault the buffer size, null resets to the default. 308 * @return {@code this} instance. 309 */ 310 protected B setBufferSizeDefault(final int bufferSizeDefault) { 311 this.bufferSizeDefault = bufferSizeDefault; 312 return asThis(); 313 } 314 315 /** 316 * 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 317 * exceeded, this methods throws an {@link IllegalArgumentException}. 318 * 319 * @param bufferSizeMax maximum buffer size checked by the buffer size checker. 320 * @return {@code this} instance. 321 * @since 2.14.0 322 */ 323 public B setBufferSizeMax(final int bufferSizeMax) { 324 this.bufferSizeMax = bufferSizeMax > 0 ? bufferSizeMax : DEFAULT_MAX_VALUE; 325 return asThis(); 326 } 327 328 /** 329 * Sets the Charset. 330 * <p> 331 * Subclasses may ignore this setting. 332 * </p> 333 * 334 * @param charset the Charset, null resets to the default. 335 * @return {@code this} instance. 336 */ 337 public B setCharset(final Charset charset) { 338 this.charset = Charsets.toCharset(charset, charsetDefault); 339 return asThis(); 340 } 341 342 /** 343 * Sets the Charset. 344 * <p> 345 * Subclasses may ignore this setting. 346 * </p> 347 * 348 * @param charset the Charset name, null resets to the default. 349 * @return {@code this} instance. 350 */ 351 public B setCharset(final String charset) { 352 return setCharset(Charsets.toCharset(charset, charsetDefault)); 353 } 354 355 /** 356 * Sets the Charset default for subclasses to initialize. 357 * <p> 358 * Subclasses may ignore this setting. 359 * </p> 360 * 361 * @param defaultCharset the Charset name, null resets to the default. 362 * @return {@code this} instance. 363 */ 364 protected B setCharsetDefault(final Charset defaultCharset) { 365 this.charsetDefault = defaultCharset; 366 return asThis(); 367 } 368 369 /** 370 * Sets the OpenOption[]. 371 * <p> 372 * Normally used with InputStream, OutputStream, and Writer. 373 * </p> 374 * <p> 375 * Subclasses may ignore this setting. 376 * </p> 377 * 378 * @param openOptions the OpenOption[] name, null resets to the default. 379 * @return {@code this} instance. 380 * @since 2.13.0 381 * @see #setInputStream(InputStream) 382 * @see #setOutputStream(OutputStream) 383 * @see #setWriter(Writer) 384 */ 385 public B setOpenOptions(final OpenOption... openOptions) { 386 this.openOptions = openOptions != null ? openOptions : DEFAULT_OPEN_OPTIONS; 387 return asThis(); 388 } 389 390 private int throwIae(final int size, final int max) { 391 throw new IllegalArgumentException(String.format("Request %,d exceeds maximum %,d", size, max)); 392 } 393}