View Javadoc
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  
19  import static org.apache.commons.io.IOUtils.EOF;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  
24  import org.apache.commons.io.build.AbstractStreamBuilder;
25  
26  /**
27   * 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
28   * 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
29   * keeps a reference to the proxy stream.
30   * <p>
31   * 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
32   * 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.
33   * </p>
34   * <p>
35   * To build an instance, use {@link Builder}.
36   * </p>
37   *
38   * @since 1.4
39   * @see Builder
40   */
41  public class AutoCloseInputStream extends ProxyInputStream {
42  
43      // @formatter:off
44      /**
45       * Builds a new {@link AutoCloseInputStream} instance.
46       *
47       * <p>
48       * For example:
49       * </p>
50       * <pre>{@code
51       * AutoCloseInputStream s = AutoCloseInputStream.builder()
52       *   .setPath(path)
53       *   .get();}
54       * </pre>
55       * <pre>{@code
56       * AutoCloseInputStream s = AutoCloseInputStream.builder()
57       *   .setInputStream(inputStream)
58       *   .get();}
59       * </pre>
60       *
61       * @see #get()
62       * @since 2.13.0
63       */
64      // @formatter:on
65      public static class Builder extends AbstractStreamBuilder<AutoCloseInputStream, Builder> {
66  
67          /**
68           * Builds a new {@link AutoCloseInputStream}.
69           * <p>
70           * You must set input that supports {@link #getInputStream()}, otherwise, this method throws an exception.
71           * </p>
72           * <p>
73           * This builder use the following aspects:
74           * </p>
75           * <ul>
76           * <li>{@link #getInputStream()}</li>
77           * </ul>
78           *
79           * @return a new instance.
80           * @throws IllegalStateException         if the {@code origin} is {@code null}.
81           * @throws UnsupportedOperationException if the origin cannot be converted to an {@link InputStream}.
82           * @throws IOException                   if an I/O error occurs.
83           * @see #getInputStream()
84           */
85          @SuppressWarnings("resource") // Caller closes
86          @Override
87          public AutoCloseInputStream get() throws IOException {
88              return new AutoCloseInputStream(getInputStream());
89          }
90  
91      }
92  
93      /**
94       * Constructs a new {@link Builder}.
95       *
96       * @return a new {@link Builder}.
97       * @since 2.12.0
98       */
99      public static Builder builder() {
100         return new Builder();
101     }
102 
103     /**
104      * Constructs an automatically closing proxy for the given input stream.
105      *
106      * @param in underlying input stream
107      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}
108      */
109     @Deprecated
110     public AutoCloseInputStream(final InputStream in) {
111         super(in);
112     }
113 
114     /**
115      * Automatically closes the stream if the end of stream was reached.
116      *
117      * @param n number of bytes read, or -1 if no more bytes are available
118      * @throws IOException if the stream could not be closed
119      * @since 2.0
120      */
121     @Override
122     protected void afterRead(final int n) throws IOException {
123         if (n == EOF) {
124             close();
125         }
126     }
127 
128     /**
129      * Closes the underlying input stream and replaces the reference to it with a {@link ClosedInputStream} instance.
130      * <p>
131      * This method is automatically called by the read methods when the end of input has been reached.
132      * </p>
133      * <p>
134      * 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
135      * first called.
136      * </p>
137      *
138      * @throws IOException if the underlying input stream can not be closed
139      */
140     @Override
141     public void close() throws IOException {
142         in.close();
143         in = ClosedInputStream.INSTANCE;
144     }
145 
146     /**
147      * 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
148      * closed.
149      *
150      * @throws Throwable if an error occurs
151      */
152     @Override
153     protected void finalize() throws Throwable {
154         close();
155         super.finalize();
156     }
157 
158 }