UnsynchronizedFilterInputStream.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.input;

  18. import java.io.FilterInputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;

  21. import org.apache.commons.io.build.AbstractStreamBuilder;

  22. /**
  23.  * An unsynchronized version of {@link FilterInputStream}, not thread-safe.
  24.  * <p>
  25.  * Wraps an existing {@link InputStream} and performs some transformation on the input data while it is being read. Transformations can be anything from a
  26.  * simple byte-wise filtering input data to an on-the-fly compression or decompression of the underlying stream. Input streams that wrap another input stream
  27.  * and provide some additional functionality on top of it usually inherit from this class.
  28.  * </p>
  29.  * <p>
  30.  * To build an instance, use {@link Builder}.
  31.  * </p>
  32.  * <p>
  33.  * Provenance: Apache Harmony and modified.
  34.  * </p>
  35.  *
  36.  * @see Builder
  37.  * @see FilterInputStream
  38.  * @since 2.12.0
  39.  */
  40. //@NotThreadSafe
  41. public class UnsynchronizedFilterInputStream extends InputStream {

  42.     // @formatter:off
  43.     /**
  44.      * Builds a new {@link UnsynchronizedFilterInputStream}.
  45.      *
  46.      * <p>
  47.      * Using File IO:
  48.      * </p>
  49.      * <pre>{@code
  50.      * UnsynchronizedFilterInputStream s = UnsynchronizedFilterInputStream.builder()
  51.      *   .setFile(file)
  52.      *   .get();}
  53.      * </pre>
  54.      * <p>
  55.      * Using NIO Path:
  56.      * </p>
  57.      * <pre>{@code
  58.      * UnsynchronizedFilterInputStream s = UnsynchronizedFilterInputStream.builder()
  59.      *   .setPath(path)
  60.      *   .get();}
  61.      * </pre>
  62.      *
  63.      * @see #get()
  64.      */
  65.     // @formatter:on
  66.     public static class Builder extends AbstractStreamBuilder<UnsynchronizedFilterInputStream, Builder> {

  67.         /**
  68.          * Constructs a new builder of {@link UnsynchronizedFilterInputStream}.
  69.          */
  70.         public Builder() {
  71.             // empty
  72.         }

  73.         /**
  74.          * Builds a new {@link UnsynchronizedFilterInputStream}.
  75.          * <p>
  76.          * You must set an aspect that supports {@link #getInputStream()}, otherwise, this method throws an exception.
  77.          * </p>
  78.          * <p>
  79.          * This builder uses the following aspects:
  80.          * </p>
  81.          * <ul>
  82.          * <li>{@link #getInputStream()}</li>
  83.          * </ul>
  84.          *
  85.          * @return a new instance.
  86.          * @throws IllegalStateException         if the {@code origin} is {@code null}.
  87.          * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}.
  88.          * @throws IOException                   if an I/O error occurs converting to an {@link InputStream} using {@link #getInputStream()}.
  89.          * @see #getInputStream()
  90.          * @see #getUnchecked()
  91.          */
  92.         @Override
  93.         public UnsynchronizedFilterInputStream get() throws IOException {
  94.             return new UnsynchronizedFilterInputStream(getInputStream());
  95.         }

  96.     }

  97.     /**
  98.      * Constructs a new {@link Builder}.
  99.      *
  100.      * @return a new {@link Builder}.
  101.      */
  102.     public static Builder builder() {
  103.         return new Builder();
  104.     }

  105.     /**
  106.      * The source input stream that is filtered.
  107.      */
  108.     protected volatile InputStream inputStream;

  109.     /**
  110.      * Constructs a new {@code FilterInputStream} with the specified input stream as source.
  111.      *
  112.      * @param inputStream the non-null InputStream to filter reads on.
  113.      */
  114.     UnsynchronizedFilterInputStream(final InputStream inputStream) {
  115.         this.inputStream = inputStream;
  116.     }

  117.     /**
  118.      * Returns the number of bytes that are available before this stream will block.
  119.      *
  120.      * @return the number of bytes available before blocking.
  121.      * @throws IOException if an error occurs in this stream.
  122.      */
  123.     @Override
  124.     public int available() throws IOException {
  125.         return inputStream.available();
  126.     }

  127.     /**
  128.      * Closes this stream. This implementation closes the filtered stream.
  129.      *
  130.      * @throws IOException if an error occurs while closing this stream.
  131.      */
  132.     @Override
  133.     public void close() throws IOException {
  134.         inputStream.close();
  135.     }

  136.     /**
  137.      * Sets a mark position in this stream. The parameter {@code readLimit} indicates how many bytes can be read before the mark is invalidated. Sending
  138.      * {@code reset()} will reposition this stream back to the marked position, provided that {@code readLimit} has not been surpassed.
  139.      * <p>
  140.      * This implementation sets a mark in the filtered stream.
  141.      *
  142.      * @param readLimit the number of bytes that can be read from this stream before the mark is invalidated.
  143.      * @see #markSupported()
  144.      * @see #reset()
  145.      */
  146.     @SuppressWarnings("sync-override") // by design.
  147.     @Override
  148.     public void mark(final int readLimit) {
  149.         inputStream.mark(readLimit);
  150.     }

  151.     /**
  152.      * Indicates whether this stream supports {@code mark()} and {@code reset()}. This implementation returns whether or not the filtered stream supports
  153.      * marking.
  154.      *
  155.      * @return {@code true} if {@code mark()} and {@code reset()} are supported, {@code false} otherwise.
  156.      * @see #mark(int)
  157.      * @see #reset()
  158.      * @see #skip(long)
  159.      */
  160.     @Override
  161.     public boolean markSupported() {
  162.         return inputStream.markSupported();
  163.     }

  164.     /**
  165.      * Reads a single byte from the filtered stream and returns it as an integer in the range from 0 to 255. Returns -1 if the end of this stream has been
  166.      * reached.
  167.      *
  168.      * @return the byte read or -1 if the end of the filtered stream has been reached.
  169.      * @throws IOException if the stream is closed or another IOException occurs.
  170.      */
  171.     @Override
  172.     public int read() throws IOException {
  173.         return inputStream.read();
  174.     }

  175.     /**
  176.      * Reads bytes from this stream and stores them in the byte array {@code buffer}. Returns the number of bytes actually read or -1 if no bytes were read and
  177.      * the end of this stream was encountered. This implementation reads bytes from the filtered stream.
  178.      *
  179.      * @param buffer the byte array in which to store the read bytes.
  180.      * @return the number of bytes actually read or -1 if the end of the filtered stream has been reached while reading.
  181.      * @throws IOException if this stream is closed or another IOException occurs.
  182.      */
  183.     @Override
  184.     public int read(final byte[] buffer) throws IOException {
  185.         return read(buffer, 0, buffer.length);
  186.     }

  187.     /**
  188.      * Reads at most {@code count} bytes from this stream and stores them in the byte array {@code buffer} starting at {@code offset}. Returns the number of
  189.      * bytes actually read or -1 if no bytes have been read and the end of this stream has been reached. This implementation reads bytes from the filtered
  190.      * stream.
  191.      *
  192.      * @param buffer the byte array in which to store the bytes read.
  193.      * @param offset the initial position in {@code buffer} to store the bytes read from this stream.
  194.      * @param count  the maximum number of bytes to store in {@code buffer}.
  195.      * @return the number of bytes actually read or -1 if the end of the filtered stream has been reached while reading.
  196.      * @throws IOException if this stream is closed or another I/O error occurs.
  197.      */
  198.     @Override
  199.     public int read(final byte[] buffer, final int offset, final int count) throws IOException {
  200.         return inputStream.read(buffer, offset, count);
  201.     }

  202.     /**
  203.      * Resets this stream to the last marked location. This implementation resets the target stream.
  204.      *
  205.      * @throws IOException if this stream is already closed, no mark has been set or the mark is no longer valid because more than {@code readLimit} bytes have
  206.      *                     been read since setting the mark.
  207.      * @see #mark(int)
  208.      * @see #markSupported()
  209.      */
  210.     @SuppressWarnings("sync-override") // by design.
  211.     @Override
  212.     public void reset() throws IOException {
  213.         inputStream.reset();
  214.     }

  215.     /**
  216.      * Skips {@code count} number of bytes in this stream. Subsequent {@code read()}'s will not return these bytes unless {@code reset()} is used. This
  217.      * implementation skips {@code count} number of bytes in the filtered stream.
  218.      *
  219.      * @param count the number of bytes to skip.
  220.      * @return the number of bytes actually skipped.
  221.      * @throws IOException if this stream is closed or another IOException occurs.
  222.      * @see #mark(int)
  223.      * @see #reset()
  224.      */
  225.     @Override
  226.     public long skip(final long count) throws IOException {
  227.         return inputStream.skip(count);
  228.     }
  229. }