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 }