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
28 * end of input has been reached or when the stream is explicitly closed.
29 * Not even a reference to the underlying stream is kept after it has been
30 * closed, so any allocated in-memory buffers can be freed even if the
31 * client application still keeps a reference to the proxy stream.
32 * <p>
33 * This class is typically used to release any resources related to an open
34 * stream as soon as possible even if the client application (by not explicitly
35 * closing the stream when no longer needed) or the underlying stream (by not
36 * releasing resources once the last byte has been read) do not do that.
37 * </p>
38 *
39 * @since 1.4
40 */
41 public class AutoCloseInputStream extends ProxyInputStream {
42
43 /**
44 * Builds a new {@link AutoCloseInputStream} instance.
45 * <p>
46 * For example:
47 * </p>
48 *
49 * <pre>{@code
50 * AutoCloseInputStream s = AutoCloseInputStream.builder()
51 * .setPath(path)
52 * .get();}
53 * </pre>
54 *
55 * <pre>{@code
56 * AutoCloseInputStream s = AutoCloseInputStream.builder()
57 * .setInputStream(inputStream)
58 * .get();}
59 * </pre>
60 *
61 * @since 2.13.0
62 */
63 public static class Builder extends AbstractStreamBuilder<AutoCloseInputStream, Builder> {
64
65 /**
66 * Constructs a new instance.
67 * <p>
68 * This builder use the aspect InputStream.
69 * </p>
70 *
71 * @return a new instance.
72 * @throws IOException if an I/O error occurs.
73 * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character.
74 */
75 @SuppressWarnings("resource") // Caller closes
76 @Override
77 public AutoCloseInputStream get() throws IOException {
78 return new AutoCloseInputStream(getInputStream());
79 }
80
81 }
82
83 /**
84 * Constructs a new {@link Builder}.
85 *
86 * @return a new {@link Builder}.
87 * @since 2.12.0
88 */
89 public static Builder builder() {
90 return new Builder();
91 }
92
93 /**
94 * Constructs an automatically closing proxy for the given input stream.
95 *
96 * @param in underlying input stream
97 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}
98 */
99 @Deprecated
100 public AutoCloseInputStream(final InputStream in) {
101 super(in);
102 }
103
104 /**
105 * Automatically closes the stream if the end of stream was reached.
106 *
107 * @param n number of bytes read, or -1 if no more bytes are available
108 * @throws IOException if the stream could not be closed
109 * @since 2.0
110 */
111 @Override
112 protected void afterRead(final int n) throws IOException {
113 if (n == EOF) {
114 close();
115 }
116 }
117
118 /**
119 * Closes the underlying input stream and replaces the reference to it
120 * with a {@link ClosedInputStream} instance.
121 * <p>
122 * This method is automatically called by the read methods when the end
123 * of input has been reached.
124 * <p>
125 * Note that it is safe to call this method any number of times. The original
126 * underlying input stream is closed and discarded only once when this
127 * method is first called.
128 *
129 * @throws IOException if the underlying input stream can not be closed
130 */
131 @Override
132 public void close() throws IOException {
133 in.close();
134 in = ClosedInputStream.INSTANCE;
135 }
136
137 /**
138 * Ensures that the stream is closed before it gets garbage-collected.
139 * As mentioned in {@link #close()}, this is a no-op if the stream has
140 * already been closed.
141 * @throws Throwable if an error occurs
142 */
143 @Override
144 protected void finalize() throws Throwable {
145 close();
146 super.finalize();
147 }
148
149 }