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 protected OpenOption[] getOpenOptions() { 158 return openOptions; 159 } 160 161 /** 162 * Gets an OutputStream from the origin with open options. 163 * 164 * @return An OutputStream 165 * @throws IOException if an I/O error occurs. 166 * @throws UnsupportedOperationException if the origin cannot be converted to an OutputStream. 167 * @throws IllegalStateException if the {@code origin} is {@code null}. 168 * @see AbstractOrigin#getOutputStream(OpenOption...) 169 * @since 2.13.0 170 */ 171 protected OutputStream getOutputStream() throws IOException { 172 return checkOrigin().getOutputStream(getOpenOptions()); 173 } 174 175 /** 176 * Gets a Path from the origin. 177 * 178 * @return A Path 179 * @throws UnsupportedOperationException if the origin cannot be converted to a Path. 180 * @throws IllegalStateException if the {@code origin} is {@code null}. 181 * @see AbstractOrigin#getPath() 182 * @since 2.13.0 183 */ 184 protected Path getPath() { 185 return checkOrigin().getPath(); 186 } 187 188 /** 189 * Gets an writer from the origin with open options. 190 * 191 * @return An writer. 192 * @throws IOException if an I/O error occurs. 193 * @throws UnsupportedOperationException if the origin cannot be converted to a Writer. 194 * @throws IllegalStateException if the {@code origin} is {@code null}. 195 * @see AbstractOrigin#getOutputStream(OpenOption...) 196 * @since 2.13.0 197 */ 198 protected Writer getWriter() throws IOException { 199 return checkOrigin().getWriter(getCharset(), getOpenOptions()); 200 } 201 202 /** 203 * Sets the buffer size. Invalid input (bufferSize <= 0) resets the value to its default. 204 * <p> 205 * Subclasses may ignore this setting. 206 * </p> 207 * 208 * @param bufferSize the buffer size. 209 * @return this. 210 */ 211 public B setBufferSize(final int bufferSize) { 212 this.bufferSize = checkBufferSize(bufferSize > 0 ? bufferSize : bufferSizeDefault); 213 return asThis(); 214 } 215 216 /** 217 * Sets the buffer size. 218 * <p> 219 * Subclasses may ignore this setting. 220 * </p> 221 * 222 * @param bufferSize the buffer size, null resets to the default. 223 * @return this. 224 */ 225 public B setBufferSize(final Integer bufferSize) { 226 setBufferSize(bufferSize != null ? bufferSize : bufferSizeDefault); 227 return asThis(); 228 } 229 230 /** 231 * Sets the buffer size checker function. Throws a {@link IllegalArgumentException} by default. 232 * 233 * @param bufferSizeChecker the buffer size checker function. null resets to the default behavior. 234 * @return this 235 * @since 2.14.0 236 */ 237 public B setBufferSizeChecker(final IntUnaryOperator bufferSizeChecker) { 238 this.bufferSizeChecker = bufferSizeChecker != null ? bufferSizeChecker : defaultSizeChecker; 239 return asThis(); 240 } 241 242 /** 243 * Sets the buffer size for subclasses to initialize. 244 * <p> 245 * Subclasses may ignore this setting. 246 * </p> 247 * 248 * @param bufferSizeDefault the buffer size, null resets to the default. 249 * @return this. 250 */ 251 protected B setBufferSizeDefault(final int bufferSizeDefault) { 252 this.bufferSizeDefault = bufferSizeDefault; 253 return asThis(); 254 } 255 256 /** 257 * 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 258 * exceeded, this methods throws an {@link IllegalArgumentException}. 259 * 260 * @param bufferSizeMax maximum buffer size checked by the buffer size checker. 261 * @return this. 262 * @since 2.14.0 263 */ 264 public B setBufferSizeMax(final int bufferSizeMax) { 265 this.bufferSizeMax = bufferSizeMax > 0 ? bufferSizeMax : DEFAULT_MAX_VALUE; 266 return asThis(); 267 } 268 269 /** 270 * Sets the Charset. 271 * <p> 272 * Subclasses may ignore this setting. 273 * </p> 274 * 275 * @param charset the Charset, null resets to the default. 276 * @return this. 277 */ 278 public B setCharset(final Charset charset) { 279 this.charset = Charsets.toCharset(charset, charsetDefault); 280 return asThis(); 281 } 282 283 /** 284 * Sets the Charset. 285 * <p> 286 * Subclasses may ignore this setting. 287 * </p> 288 * 289 * @param charset the Charset name, null resets to the default. 290 * @return this. 291 */ 292 public B setCharset(final String charset) { 293 return setCharset(Charsets.toCharset(charset, charsetDefault)); 294 } 295 296 /** 297 * Sets the Charset default for subclasses to initialize. 298 * <p> 299 * Subclasses may ignore this setting. 300 * </p> 301 * 302 * @param defaultCharset the Charset name, null resets to the default. 303 * @return this. 304 */ 305 protected B setCharsetDefault(final Charset defaultCharset) { 306 this.charsetDefault = defaultCharset; 307 return asThis(); 308 } 309 310 /** 311 * Sets the OpenOption[]. 312 * <p> 313 * Normally used with InputStream, OutputStream, and Writer. 314 * </p> 315 * <p> 316 * Subclasses may ignore this setting. 317 * </p> 318 * 319 * @param openOptions the OpenOption[] name, null resets to the default. 320 * @return this. 321 * @since 2.13.0 322 * @see #setInputStream(InputStream) 323 * @see #setOutputStream(OutputStream) 324 * @see #setWriter(Writer) 325 */ 326 public B setOpenOptions(final OpenOption... openOptions) { 327 this.openOptions = openOptions != null ? openOptions : DEFAULT_OPEN_OPTIONS; 328 return asThis(); 329 } 330 331 private int throwIae(final int size, final int max) { 332 throw new IllegalArgumentException(String.format("Request %,d exceeds maximum %,d", size, max)); 333 } 334}