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