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 * Applies the buffer size request. 088 * 089 * @param size the size request. 090 * @return the size to use, usually the input, or can throw an unchecked exception, like {@link IllegalArgumentException}. 091 */ 092 private int checkBufferSize(final int size) { 093 return bufferSizeChecker.applyAsInt(size); 094 } 095 096 /** 097 * Gets the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 098 * 099 * @return the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 100 */ 101 public int getBufferSize() { 102 return bufferSize; 103 } 104 105 /** 106 * Gets the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 107 * 108 * @return the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 109 */ 110 public int getBufferSizeDefault() { 111 return bufferSizeDefault; 112 } 113 114 /** 115 * Gets a CharSequence from the origin with a Charset. 116 * 117 * @return An input stream 118 * @throws IllegalStateException if the {@code origin} is {@code null}. 119 * @throws UnsupportedOperationException if the origin cannot be converted to a CharSequence. 120 * @throws IOException if an I/O error occurs. 121 * @see AbstractOrigin#getCharSequence(Charset) 122 * @since 2.13.0 123 */ 124 public CharSequence getCharSequence() throws IOException { 125 return checkOrigin().getCharSequence(getCharset()); 126 } 127 128 /** 129 * Gets the Charset, defaults to {@link Charset#defaultCharset()}. 130 * 131 * @return the Charset, defaults to {@link Charset#defaultCharset()}. 132 */ 133 public Charset getCharset() { 134 return charset; 135 } 136 137 /** 138 * Gets the Charset default, defaults to {@link Charset#defaultCharset()}. 139 * 140 * @return the Charset default, defaults to {@link Charset#defaultCharset()}. 141 */ 142 public Charset getCharsetDefault() { 143 return charsetDefault; 144 } 145 146 /** 147 * Gets a File from the origin. 148 * 149 * @return A File 150 * @throws IllegalStateException if the {@code origin} is {@code null}. 151 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link File}. 152 * @see AbstractOrigin#getPath() 153 * @since 2.18.0 154 */ 155 public File getFile() { 156 return checkOrigin().getFile(); 157 } 158 159 /** 160 * Gets an InputStream from the origin with OpenOption[]. 161 * 162 * @return An input stream 163 * @throws IllegalStateException if the {@code origin} is {@code null}. 164 * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}. 165 * @throws IOException if an I/O error occurs. 166 * @see AbstractOrigin#getInputStream(OpenOption...) 167 * @see #getOpenOptions() 168 * @since 2.13.0 169 */ 170 public InputStream getInputStream() throws IOException { 171 return checkOrigin().getInputStream(getOpenOptions()); 172 } 173 174 /** 175 * Gets the OpenOption array. 176 * 177 * @return the OpenOption array. 178 */ 179 public OpenOption[] getOpenOptions() { 180 return openOptions; 181 } 182 183 /** 184 * Gets an OutputStream from the origin with OpenOption[]. 185 * 186 * @return An OutputStream 187 * @throws IllegalStateException if the {@code origin} is {@code null}. 188 * @throws UnsupportedOperationException if the origin cannot be converted to an {@link OutputStream}. 189 * @throws IOException if an I/O error occurs. 190 * @see AbstractOrigin#getOutputStream(OpenOption...) 191 * @see #getOpenOptions() 192 * @since 2.13.0 193 */ 194 public OutputStream getOutputStream() throws IOException { 195 return checkOrigin().getOutputStream(getOpenOptions()); 196 } 197 198 /** 199 * Gets a Path from the origin. 200 * 201 * @return A Path 202 * @throws IllegalStateException if the {@code origin} is {@code null}. 203 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Path}. 204 * @see AbstractOrigin#getPath() 205 * @since 2.13.0 206 */ 207 public Path getPath() { 208 return checkOrigin().getPath(); 209 } 210 211 /** 212 * Gets a RandomAccessFile from the origin. 213 * 214 * @return A RandomAccessFile 215 * @throws IllegalStateException if the {@code origin} is {@code null}. 216 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link RandomAccessFile}. 217 * @throws IOException if an I/O error occurs. 218 * @since 2.18.0 219 */ 220 public RandomAccessFile getRandomAccessFile() throws IOException { 221 return checkOrigin().getRandomAccessFile(getOpenOptions()); 222 } 223 224 /** 225 * Gets a Reader from the origin with a Charset. 226 * 227 * @return A Reader 228 * @throws IllegalStateException if the {@code origin} is {@code null}. 229 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Reader}. 230 * @throws IOException if an I/O error occurs. 231 * @see AbstractOrigin#getReader(Charset) 232 * @see #getCharset() 233 * @since 2.16.0 234 */ 235 public Reader getReader() throws IOException { 236 return checkOrigin().getReader(getCharset()); 237 } 238 239 /** 240 * Gets a Writer from the origin with an OpenOption[]. 241 * 242 * @return An writer. 243 * @throws IllegalStateException if the {@code origin} is {@code null}. 244 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Writer}. 245 * @throws IOException if an I/O error occurs. 246 * @see AbstractOrigin#getOutputStream(OpenOption...) 247 * @see #getOpenOptions() 248 * @since 2.13.0 249 */ 250 public Writer getWriter() throws IOException { 251 return checkOrigin().getWriter(getCharset(), getOpenOptions()); 252 } 253 254 /** 255 * Sets the buffer size. Invalid input (bufferSize <= 0) resets the value to its default. 256 * <p> 257 * Subclasses may ignore this setting. 258 * </p> 259 * 260 * @param bufferSize the buffer size. 261 * @return {@code this} instance. 262 */ 263 public B setBufferSize(final int bufferSize) { 264 this.bufferSize = checkBufferSize(bufferSize > 0 ? bufferSize : bufferSizeDefault); 265 return asThis(); 266 } 267 268 /** 269 * Sets the buffer size. 270 * <p> 271 * Subclasses may ignore this setting. 272 * </p> 273 * 274 * @param bufferSize the buffer size, null resets to the default. 275 * @return {@code this} instance. 276 */ 277 public B setBufferSize(final Integer bufferSize) { 278 setBufferSize(bufferSize != null ? bufferSize : bufferSizeDefault); 279 return asThis(); 280 } 281 282 /** 283 * Sets the buffer size checker function. Throws a {@link IllegalArgumentException} by default. 284 * 285 * @param bufferSizeChecker the buffer size checker function. null resets to the default behavior. 286 * @return {@code this} instance. 287 * @since 2.14.0 288 */ 289 public B setBufferSizeChecker(final IntUnaryOperator bufferSizeChecker) { 290 this.bufferSizeChecker = bufferSizeChecker != null ? bufferSizeChecker : defaultSizeChecker; 291 return asThis(); 292 } 293 294 /** 295 * Sets the buffer size for subclasses to initialize. 296 * <p> 297 * Subclasses may ignore this setting. 298 * </p> 299 * 300 * @param bufferSizeDefault the buffer size, null resets to the default. 301 * @return {@code this} instance. 302 */ 303 protected B setBufferSizeDefault(final int bufferSizeDefault) { 304 this.bufferSizeDefault = bufferSizeDefault; 305 return asThis(); 306 } 307 308 /** 309 * 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 310 * exceeded, this methods throws an {@link IllegalArgumentException}. 311 * 312 * @param bufferSizeMax maximum buffer size checked by the buffer size checker. 313 * @return {@code this} instance. 314 * @since 2.14.0 315 */ 316 public B setBufferSizeMax(final int bufferSizeMax) { 317 this.bufferSizeMax = bufferSizeMax > 0 ? bufferSizeMax : DEFAULT_MAX_VALUE; 318 return asThis(); 319 } 320 321 /** 322 * Sets the Charset. 323 * <p> 324 * Subclasses may ignore this setting. 325 * </p> 326 * 327 * @param charset the Charset, null resets to the default. 328 * @return {@code this} instance. 329 */ 330 public B setCharset(final Charset charset) { 331 this.charset = Charsets.toCharset(charset, charsetDefault); 332 return asThis(); 333 } 334 335 /** 336 * Sets the Charset. 337 * <p> 338 * Subclasses may ignore this setting. 339 * </p> 340 * 341 * @param charset the Charset name, null resets to the default. 342 * @return {@code this} instance. 343 */ 344 public B setCharset(final String charset) { 345 return setCharset(Charsets.toCharset(charset, charsetDefault)); 346 } 347 348 /** 349 * Sets the Charset default for subclasses to initialize. 350 * <p> 351 * Subclasses may ignore this setting. 352 * </p> 353 * 354 * @param defaultCharset the Charset name, null resets to the default. 355 * @return {@code this} instance. 356 */ 357 protected B setCharsetDefault(final Charset defaultCharset) { 358 this.charsetDefault = defaultCharset; 359 return asThis(); 360 } 361 362 /** 363 * Sets the OpenOption[]. 364 * <p> 365 * Normally used with InputStream, OutputStream, and Writer. 366 * </p> 367 * <p> 368 * Subclasses may ignore this setting. 369 * </p> 370 * 371 * @param openOptions the OpenOption[] name, null resets to the default. 372 * @return {@code this} instance. 373 * @since 2.13.0 374 * @see #setInputStream(InputStream) 375 * @see #setOutputStream(OutputStream) 376 * @see #setWriter(Writer) 377 */ 378 public B setOpenOptions(final OpenOption... openOptions) { 379 this.openOptions = openOptions != null ? openOptions : DEFAULT_OPEN_OPTIONS; 380 return asThis(); 381 } 382 383 private int throwIae(final int size, final int max) { 384 throw new IllegalArgumentException(String.format("Request %,d exceeds maximum %,d", size, max)); 385 } 386}