AbstractStreamBuilder.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.io.build;

  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.OutputStream;
  22. import java.io.RandomAccessFile;
  23. import java.io.Reader;
  24. import java.io.Writer;
  25. import java.nio.charset.Charset;
  26. import java.nio.file.OpenOption;
  27. import java.nio.file.Path;
  28. import java.util.function.IntUnaryOperator;

  29. import org.apache.commons.io.Charsets;
  30. import org.apache.commons.io.IOUtils;
  31. import org.apache.commons.io.file.PathUtils;

  32. /**
  33.  * Abstracts building a typed instance of {@code T}.
  34.  *
  35.  * @param <T> the type of instances to build.
  36.  * @param <B> the type of builder subclass.
  37.  * @since 2.12.0
  38.  */
  39. public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T, B>> extends AbstractOriginSupplier<T, B> {

  40.     private static final int DEFAULT_MAX_VALUE = Integer.MAX_VALUE;

  41.     private static final OpenOption[] DEFAULT_OPEN_OPTIONS = PathUtils.EMPTY_OPEN_OPTION_ARRAY;

  42.     /**
  43.      * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
  44.      */
  45.     private int bufferSize = IOUtils.DEFAULT_BUFFER_SIZE;

  46.     /**
  47.      * The buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
  48.      */
  49.     private int bufferSizeDefault = IOUtils.DEFAULT_BUFFER_SIZE;

  50.     /**
  51.      * The maximum buffer size.
  52.      */
  53.     private int bufferSizeMax = DEFAULT_MAX_VALUE;

  54.     /**
  55.      * The Charset, defaults to {@link Charset#defaultCharset()}.
  56.      */
  57.     private Charset charset = Charset.defaultCharset();

  58.     /**
  59.      * The Charset, defaults to {@link Charset#defaultCharset()}.
  60.      */
  61.     private Charset charsetDefault = Charset.defaultCharset();

  62.     private OpenOption[] openOptions = DEFAULT_OPEN_OPTIONS;

  63.     /**
  64.      * The default checking behavior for a buffer size request. Throws a {@link IllegalArgumentException} by default.
  65.      */
  66.     private final IntUnaryOperator defaultSizeChecker = size -> size > bufferSizeMax ? throwIae(size, bufferSizeMax) : size;

  67.     /**
  68.      * The checking behavior for a buffer size request.
  69.      */
  70.     private IntUnaryOperator bufferSizeChecker = defaultSizeChecker;

  71.     /**
  72.      * Constructs a new instance for subclasses.
  73.      */
  74.     public AbstractStreamBuilder() {
  75.         // empty
  76.     }

  77.     /**
  78.      * Applies the buffer size request.
  79.      *
  80.      * @param size the size request.
  81.      * @return the size to use, usually the input, or can throw an unchecked exception, like {@link IllegalArgumentException}.
  82.      */
  83.     private int checkBufferSize(final int size) {
  84.         return bufferSizeChecker.applyAsInt(size);
  85.     }

  86.     /**
  87.      * Gets the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
  88.      *
  89.      * @return the buffer size, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
  90.      */
  91.     public int getBufferSize() {
  92.         return bufferSize;
  93.     }

  94.     /**
  95.      * Gets the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
  96.      *
  97.      * @return the buffer size default, defaults to {@link IOUtils#DEFAULT_BUFFER_SIZE} ({@value IOUtils#DEFAULT_BUFFER_SIZE}).
  98.      */
  99.     public int getBufferSizeDefault() {
  100.         return bufferSizeDefault;
  101.     }

  102.     /**
  103.      * Gets a CharSequence from the origin with a Charset.
  104.      *
  105.      * @return An input stream
  106.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  107.      * @throws UnsupportedOperationException if the origin cannot be converted to a CharSequence.
  108.      * @throws IOException                   if an I/O error occurs.
  109.      * @see AbstractOrigin#getCharSequence(Charset)
  110.      * @since 2.13.0
  111.      */
  112.     public CharSequence getCharSequence() throws IOException {
  113.         return checkOrigin().getCharSequence(getCharset());
  114.     }

  115.     /**
  116.      * Gets the Charset, defaults to {@link Charset#defaultCharset()}.
  117.      *
  118.      * @return the Charset, defaults to {@link Charset#defaultCharset()}.
  119.      */
  120.     public Charset getCharset() {
  121.         return charset;
  122.     }

  123.     /**
  124.      * Gets the Charset default, defaults to {@link Charset#defaultCharset()}.
  125.      *
  126.      * @return the Charset default, defaults to {@link Charset#defaultCharset()}.
  127.      */
  128.     public Charset getCharsetDefault() {
  129.         return charsetDefault;
  130.     }

  131.     /**
  132.      * Gets a File from the origin.
  133.      *
  134.      * @return A File
  135.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  136.      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link File}.
  137.      * @see AbstractOrigin#getPath()
  138.      * @since 2.18.0
  139.      */
  140.     public File getFile() {
  141.         return checkOrigin().getFile();
  142.     }

  143.     /**
  144.      * Gets an InputStream from the origin with OpenOption[].
  145.      *
  146.      * @return An input stream
  147.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  148.      * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}.
  149.      * @throws IOException                   if an I/O error occurs.
  150.      * @see AbstractOrigin#getInputStream(OpenOption...)
  151.      * @see #getOpenOptions()
  152.      * @since 2.13.0
  153.      */
  154.     public InputStream getInputStream() throws IOException {
  155.         return checkOrigin().getInputStream(getOpenOptions());
  156.     }

  157.     /**
  158.      * Gets the OpenOption array.
  159.      *
  160.      * @return the OpenOption array.
  161.      */
  162.     public OpenOption[] getOpenOptions() {
  163.         return openOptions;
  164.     }

  165.     /**
  166.      * Gets an OutputStream from the origin with OpenOption[].
  167.      *
  168.      * @return An OutputStream
  169.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  170.      * @throws UnsupportedOperationException if the origin cannot be converted to an {@link OutputStream}.
  171.      * @throws IOException                   if an I/O error occurs.
  172.      * @see AbstractOrigin#getOutputStream(OpenOption...)
  173.      * @see #getOpenOptions()
  174.      * @since 2.13.0
  175.      */
  176.     public OutputStream getOutputStream() throws IOException {
  177.         return checkOrigin().getOutputStream(getOpenOptions());
  178.     }

  179.     /**
  180.      * Gets a Path from the origin.
  181.      *
  182.      * @return A Path
  183.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  184.      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Path}.
  185.      * @see AbstractOrigin#getPath()
  186.      * @since 2.13.0
  187.      */
  188.     public Path getPath() {
  189.         return checkOrigin().getPath();
  190.     }

  191.     /**
  192.      * Gets a RandomAccessFile from the origin.
  193.      *
  194.      * @return A RandomAccessFile
  195.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  196.      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link RandomAccessFile}.
  197.      * @throws IOException                   if an I/O error occurs.
  198.      * @since 2.18.0
  199.      */
  200.     public RandomAccessFile getRandomAccessFile() throws IOException {
  201.         return checkOrigin().getRandomAccessFile(getOpenOptions());
  202.     }

  203.     /**
  204.      * Gets a Reader from the origin with a Charset.
  205.      *
  206.      * @return A Reader
  207.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  208.      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Reader}.
  209.      * @throws IOException                   if an I/O error occurs.
  210.      * @see AbstractOrigin#getReader(Charset)
  211.      * @see #getCharset()
  212.      * @since 2.16.0
  213.      */
  214.     public Reader getReader() throws IOException {
  215.         return checkOrigin().getReader(getCharset());
  216.     }

  217.     /**
  218.      * Gets a Writer from the origin with an OpenOption[].
  219.      *
  220.      * @return An writer.
  221.      * @throws IllegalStateException         if the {@code origin} is {@code null}.
  222.      * @throws UnsupportedOperationException if the origin cannot be converted to a {@link Writer}.
  223.      * @throws IOException                   if an I/O error occurs.
  224.      * @see AbstractOrigin#getOutputStream(OpenOption...)
  225.      * @see #getOpenOptions()
  226.      * @since 2.13.0
  227.      */
  228.     public Writer getWriter() throws IOException {
  229.         return checkOrigin().getWriter(getCharset(), getOpenOptions());
  230.     }

  231.     /**
  232.      * Sets the buffer size. Invalid input (bufferSize &lt;= 0) resets the value to its default.
  233.      * <p>
  234.      * Subclasses may ignore this setting.
  235.      * </p>
  236.      *
  237.      * @param bufferSize the buffer size.
  238.      * @return {@code this} instance.
  239.      */
  240.     public B setBufferSize(final int bufferSize) {
  241.         this.bufferSize = checkBufferSize(bufferSize > 0 ? bufferSize : bufferSizeDefault);
  242.         return asThis();
  243.     }

  244.     /**
  245.      * Sets the buffer size.
  246.      * <p>
  247.      * Subclasses may ignore this setting.
  248.      * </p>
  249.      *
  250.      * @param bufferSize the buffer size, null resets to the default.
  251.      * @return {@code this} instance.
  252.      */
  253.     public B setBufferSize(final Integer bufferSize) {
  254.         setBufferSize(bufferSize != null ? bufferSize : bufferSizeDefault);
  255.         return asThis();
  256.     }

  257.     /**
  258.      * Sets the buffer size checker function. Throws a {@link IllegalArgumentException} by default.
  259.      *
  260.      * @param bufferSizeChecker the buffer size checker function. null resets to the default behavior.
  261.      * @return {@code this} instance.
  262.      * @since 2.14.0
  263.      */
  264.     public B setBufferSizeChecker(final IntUnaryOperator bufferSizeChecker) {
  265.         this.bufferSizeChecker = bufferSizeChecker != null ? bufferSizeChecker : defaultSizeChecker;
  266.         return asThis();
  267.     }

  268.     /**
  269.      * Sets the buffer size for subclasses to initialize.
  270.      * <p>
  271.      * Subclasses may ignore this setting.
  272.      * </p>
  273.      *
  274.      * @param bufferSizeDefault the buffer size, null resets to the default.
  275.      * @return {@code this} instance.
  276.      */
  277.     protected B setBufferSizeDefault(final int bufferSizeDefault) {
  278.         this.bufferSizeDefault = bufferSizeDefault;
  279.         return asThis();
  280.     }

  281.     /**
  282.      * 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
  283.      * exceeded, this methods throws an {@link IllegalArgumentException}.
  284.      *
  285.      * @param bufferSizeMax maximum buffer size checked by the buffer size checker.
  286.      * @return {@code this} instance.
  287.      * @since 2.14.0
  288.      */
  289.     public B setBufferSizeMax(final int bufferSizeMax) {
  290.         this.bufferSizeMax = bufferSizeMax > 0 ? bufferSizeMax : DEFAULT_MAX_VALUE;
  291.         return asThis();
  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.      * Sets the Charset.
  308.      * <p>
  309.      * Subclasses may ignore this setting.
  310.      * </p>
  311.      *
  312.      * @param charset the Charset name, null resets to the default.
  313.      * @return {@code this} instance.
  314.      */
  315.     public B setCharset(final String charset) {
  316.         return setCharset(Charsets.toCharset(charset, charsetDefault));
  317.     }

  318.     /**
  319.      * Sets the Charset default for subclasses to initialize.
  320.      * <p>
  321.      * Subclasses may ignore this setting.
  322.      * </p>
  323.      *
  324.      * @param defaultCharset the Charset name, null resets to the default.
  325.      * @return {@code this} instance.
  326.      */
  327.     protected B setCharsetDefault(final Charset defaultCharset) {
  328.         this.charsetDefault = defaultCharset;
  329.         return asThis();
  330.     }

  331.     /**
  332.      * Sets the OpenOption[].
  333.      * <p>
  334.      * Normally used with InputStream, OutputStream, and Writer.
  335.      * </p>
  336.      * <p>
  337.      * Subclasses may ignore this setting.
  338.      * </p>
  339.      *
  340.      * @param openOptions the OpenOption[] name, null resets to the default.
  341.      * @return {@code this} instance.
  342.      * @since 2.13.0
  343.      * @see #setInputStream(InputStream)
  344.      * @see #setOutputStream(OutputStream)
  345.      * @see #setWriter(Writer)
  346.      */
  347.     public B setOpenOptions(final OpenOption... openOptions) {
  348.         this.openOptions = openOptions != null ? openOptions : DEFAULT_OPEN_OPTIONS;
  349.         return asThis();
  350.     }

  351.     private int throwIae(final int size, final int max) {
  352.         throw new IllegalArgumentException(String.format("Request %,d exceeds maximum %,d", size, max));
  353.     }
  354. }