AutoCloseInputStream.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 static org.apache.commons.io.IOUtils.EOF;

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

  21. /**
  22.  * Proxy stream that closes and discards the underlying stream as soon as the end of input has been reached or when the stream is explicitly closed. Not even a
  23.  * reference to the underlying stream is kept after it has been closed, so any allocated in-memory buffers can be freed even if the client application still
  24.  * keeps a reference to the proxy stream.
  25.  * <p>
  26.  * This class is typically used to release any resources related to an open stream as soon as possible even if the client application (by not explicitly closing
  27.  * the stream when no longer needed) or the underlying stream (by not releasing resources once the last byte has been read) do not do that.
  28.  * </p>
  29.  * <p>
  30.  * To build an instance, use {@link Builder}.
  31.  * </p>
  32.  *
  33.  * @since 1.4
  34.  * @see Builder
  35.  */
  36. public class AutoCloseInputStream extends ProxyInputStream {

  37.     // @formatter:off
  38.     /**
  39.      * Builds a new {@link AutoCloseInputStream} instance.
  40.      *
  41.      * <p>
  42.      * For example:
  43.      * </p>
  44.      * <pre>{@code
  45.      * AutoCloseInputStream s = AutoCloseInputStream.builder()
  46.      *   .setPath(path)
  47.      *   .get();}
  48.      * </pre>
  49.      * <pre>{@code
  50.      * AutoCloseInputStream s = AutoCloseInputStream.builder()
  51.      *   .setInputStream(inputStream)
  52.      *   .get();}
  53.      * </pre>
  54.      *
  55.      * @see #get()
  56.      * @since 2.13.0
  57.      */
  58.     // @formatter:on
  59.     public static class Builder extends AbstractBuilder<AutoCloseInputStream, Builder> {

  60.         /**
  61.          * Constructs a new builder of {@link AutoCloseInputStream}.
  62.          */
  63.         public Builder() {
  64.             // empty
  65.         }

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

  89.     }

  90.     /**
  91.      * Constructs a new {@link Builder}.
  92.      *
  93.      * @return a new {@link Builder}.
  94.      * @since 2.12.0
  95.      */
  96.     public static Builder builder() {
  97.         return new Builder();
  98.     }

  99.     private AutoCloseInputStream(final Builder builder) throws IOException {
  100.         super(builder);
  101.     }

  102.     /**
  103.      * Constructs an automatically closing proxy for the given input stream.
  104.      *
  105.      * @param in underlying input stream
  106.      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}
  107.      */
  108.     @SuppressWarnings("resource") // ClosedInputStream.nonNull() doesn't allocate
  109.     @Deprecated
  110.     public AutoCloseInputStream(final InputStream in) {
  111.         super(ClosedInputStream.ifNull(in));
  112.     }

  113.     /**
  114.      * Automatically closes the stream if the end of stream was reached.
  115.      *
  116.      * @param n number of bytes read, or -1 if no more bytes are available
  117.      * @throws IOException if the stream could not be closed
  118.      * @since 2.0
  119.      */
  120.     @Override
  121.     protected void afterRead(final int n) throws IOException {
  122.         if (n == EOF) {
  123.             close();
  124.         }
  125.         super.afterRead(n);
  126.     }

  127.     /**
  128.      * Closes the underlying input stream and replaces the reference to it with a {@link ClosedInputStream} instance.
  129.      * <p>
  130.      * This method is automatically called by the read methods when the end of input has been reached.
  131.      * </p>
  132.      * <p>
  133.      * Note that it is safe to call this method any number of times. The original underlying input stream is closed and discarded only once when this method is
  134.      * first called.
  135.      * </p>
  136.      *
  137.      * @throws IOException if the underlying input stream cannot be closed
  138.      */
  139.     @Override
  140.     public void close() throws IOException {
  141.         super.close();
  142.         in = ClosedInputStream.INSTANCE;
  143.     }

  144.     /**
  145.      * Ensures that the stream is closed before it gets garbage-collected. As mentioned in {@link #close()}, this is a no-op if the stream has already been
  146.      * closed.
  147.      *
  148.      * @throws Throwable if an error occurs
  149.      */
  150.     @Override
  151.     protected void finalize() throws Throwable {
  152.         close();
  153.         super.finalize();
  154.     }

  155. }