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