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 */
17package org.apache.commons.io.input;
18
19import java.io.IOException;
20import java.io.InputStream;
21
22/**
23 * Proxy stream that closes and discards the underlying stream as soon as the
24 * end of input has been reached or when the stream is explicitly closed.
25 * Not even a reference to the underlying stream is kept after it has been
26 * closed, so any allocated in-memory buffers can be freed even if the
27 * client application still keeps a reference to the proxy stream.
28 * <p>
29 * This class is typically used to release any resources related to an open
30 * stream as soon as possible even if the client application (by not explicitly
31 * closing the stream when no longer needed) or the underlying stream (by not
32 * releasing resources once the last byte has been read) do not do that.
33 *
34 * @version $Id: AutoCloseInputStream.java 610010 2008-01-08 14:50:59Z niallp $
35 * @since Commons IO 1.4
36 */
37public class AutoCloseInputStream extends ProxyInputStream {
38
39    /**
40     * Creates an automatically closing proxy for the given input stream.
41     *
42     * @param in underlying input stream
43     */
44    public AutoCloseInputStream(InputStream in) {
45        super(in);
46    }
47
48    /**
49     * Closes the underlying input stream and replaces the reference to it
50     * with a {@link ClosedInputStream} instance.
51     * <p>
52     * This method is automatically called by the read methods when the end
53     * of input has been reached.
54     * <p>
55     * Note that it is safe to call this method any number of times. The original
56     * underlying input stream is closed and discarded only once when this
57     * method is first called.
58     *
59     * @throws IOException if the underlying input stream can not be closed
60     */
61    public void close() throws IOException {
62        in.close();
63        in = new ClosedInputStream();
64    }
65
66    /**
67     * Reads and returns a single byte from the underlying input stream.
68     * If the underlying stream returns -1, the {@link #close()} method is
69     * called to automatically close and discard the stream.
70     *
71     * @return next byte in the stream, or -1 if no more bytes are available
72     * @throws IOException if the stream could not be read or closed
73     */
74    public int read() throws IOException {
75        int n = in.read();
76        if (n == -1) {
77            close();
78        }
79        return n;
80    }
81
82    /**
83     * Reads and returns bytes from the underlying input stream to the given
84     * buffer. If the underlying stream returns -1, the {@link #close()} method
85     * i called to automatically close and discard the stream.
86     *
87     * @param b buffer to which bytes from the stream are written
88     * @return number of bytes read, or -1 if no more bytes are available
89     * @throws IOException if the stream could not be read or closed
90     */
91    public int read(byte[] b) throws IOException {
92        int n = in.read(b);
93        if (n == -1) {
94            close();
95        }
96        return n;
97    }
98
99    /**
100     * Reads and returns bytes from the underlying input stream to the given
101     * buffer. If the underlying stream returns -1, the {@link #close()} method
102     * i called to automatically close and discard the stream.
103     *
104     * @param b buffer to which bytes from the stream are written
105     * @param off start offset within the buffer
106     * @param len maximum number of bytes to read
107     * @return number of bytes read, or -1 if no more bytes are available
108     * @throws IOException if the stream could not be read or closed
109     */
110    public int read(byte[] b, int off, int len) throws IOException {
111        int n = in.read(b, off, len);
112        if (n == -1) {
113            close();
114        }
115        return n;
116    }
117
118    /**
119     * Ensures that the stream is closed before it gets garbage-collected.
120     * As mentioned in {@link #close()}, this is a no-op if the stream has
121     * already been closed.
122     * @throws Throwable if an error occurs
123     */
124    protected void finalize() throws Throwable {
125        close();
126        super.finalize();
127    }
128
129}
130