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.IOException; 021import java.io.InputStream; 022import java.io.OutputStream; 023import java.io.Reader; 024import java.io.Writer; 025import java.nio.charset.Charset; 026import java.nio.file.OpenOption; 027import java.nio.file.Path; 028import java.util.function.IntUnaryOperator; 029 030import org.apache.commons.io.Charsets; 031import org.apache.commons.io.IOUtils; 032import org.apache.commons.io.file.PathUtils; 033 034/** 035 * Abstracts building a typed instance of {@code T}. 036 * 037 * @param <T> the type of instances to build. 038 * @param <B> the type of builder subclass. 039 * @since 2.12.0 040 */ 041public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T, B>> extends AbstractOriginSupplier<T, B> { 042 043 private static final int DEFAULT_MAX_VALUE = Integer.MAX_VALUE; 044 045 private static final OpenOption[] DEFAULT_OPEN_OPTIONS = PathUtils.EMPTY_OPEN_OPTION_ARRAY; 046 047 /** 048 * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 049 */ 050 private int bufferSize = IOUtils.DEFAULT_BUFFER_SIZE; 051 052 /** 053 * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 054 */ 055 private int bufferSizeDefault = IOUtils.DEFAULT_BUFFER_SIZE; 056 057 /** 058 * The maximum buffer size. 059 */ 060 private int bufferSizeMax = DEFAULT_MAX_VALUE; 061 062 /** 063 * The Charset, defaults to {@link Charset#defaultCharset()}. 064 */ 065 private Charset charset = Charset.defaultCharset(); 066 067 /** 068 * The Charset, defaults to {@link Charset#defaultCharset()}. 069 */ 070 private Charset charsetDefault = Charset.defaultCharset(); 071 072 private OpenOption[] openOptions = DEFAULT_OPEN_OPTIONS; 073 074 /** 075 * The default checking behavior for a buffer size request. Throws a {@link IllegalArgumentException} by default. 076 */ 077 private final IntUnaryOperator defaultSizeChecker = size -> size > bufferSizeMax ? throwIae(size, bufferSizeMax) : size; 078 079 /** 080 * The checking behavior for a buffer size request. 081 */ 082 private IntUnaryOperator bufferSizeChecker = defaultSizeChecker; 083 084 /** 085 * Applies the buffer size request. 086 * 087 * @param size the size request. 088 * @return the size to use, usually the input, or can throw an unchecked exception, like {@link IllegalArgumentException}. 089 */ 090 private int checkBufferSize(final int size) { 091 return bufferSizeChecker.applyAsInt(size); 092 } 093 094 /** 095 * Gets the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 096 * 097 * @return the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}). 098 */ 099 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 {@code this} instance. 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 {@code this} instance. 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 {@code this} instance. 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 {@code this} instance. 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 {@code this} instance. 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 {@code this} instance. 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 {@code this} instance. 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 {@code this} instance. 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 {@code this} instance. 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}