View Javadoc

1   /*
2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/AutoCloseInputStream.java,v 1.9 2004/04/18 23:51:34 jsdever Exp $
3    * $Revision: 291181 $
4    * $Date: 2005-09-23 14:13:25 -0400 (Fri, 23 Sep 2005) $
5    *
6    * ====================================================================
7    *
8    *  Copyright 2002-2004 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   */
29  
30  package org.apache.commons.httpclient;
31  
32  import java.io.FilterInputStream;
33  import java.io.IOException;
34  import java.io.InputStream;
35  
36  /***
37   * Closes an underlying stream as soon as the end of the stream is reached, and
38   * notifies a client when it has done so.
39   *
40   * @author Ortwin Glueck
41   * @author Eric Johnson
42   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
43   *
44   * @since 2.0
45   */
46  class AutoCloseInputStream extends FilterInputStream {
47  
48      /*** 
49       * True if this stream is open.  Assume that the underlying stream 
50       * is open until we get an EOF indication.
51       */
52      private boolean streamOpen = true;
53  
54      /*** True if the stream closed itself. */
55      private boolean selfClosed = false;
56  
57      /*** 
58       * The watcher is notified when the contents of the stream have
59       * been  exhausted
60       */ 
61      private ResponseConsumedWatcher watcher = null;
62  
63      /***
64       * Create a new auto closing stream for the provided connection
65       *
66       * @param in the input stream to read from
67       * @param watcher   To be notified when the contents of the stream have been
68       *  consumed.
69       */
70      public AutoCloseInputStream(
71              final InputStream in, final ResponseConsumedWatcher watcher) {
72          super(in);
73          this.watcher = watcher;
74      }
75  
76      /***
77       * Reads the next byte of data from the input stream.
78       *
79       * @throws IOException when there is an error reading
80       * @return the character read, or -1 for EOF
81       */
82      public int read() throws IOException {
83          int l = -1;
84  
85          if (isReadAllowed()) {
86              // underlying stream not closed, go ahead and read.
87              l = super.read();
88              checkClose(l);
89          }
90  
91          return l;
92      }
93  
94      /***
95       * Reads up to <code>len</code> bytes of data from the stream.
96       *
97       * @param b a <code>byte</code> array to read data into
98       * @param off an offset within the array to store data
99       * @param len the maximum number of bytes to read
100      * @return the number of bytes read or -1 for EOF
101      * @throws IOException if there are errors reading
102      */
103     public int read(byte[] b, int off, int len) throws IOException {
104         int l = -1;
105 
106         if (isReadAllowed()) {
107             l = super.read(b,  off,  len);
108             checkClose(l);
109         }
110 
111         return l;
112     }
113 
114     /***
115      * Reads some number of bytes from the input stream and stores them into the
116      * buffer array b.
117      *
118      * @param b a <code>byte</code> array to read data into
119      * @return the number of bytes read or -1 for EOF
120      * @throws IOException if there are errors reading
121      */
122     public int read(byte[] b) throws IOException {
123         int l = -1;
124 
125         if (isReadAllowed()) {
126             l = super.read(b);
127             checkClose(l);
128         }
129         return l;
130     }
131 
132     /***
133      * Close the stream, and also close the underlying stream if it is not
134      * already closed.
135      * @throws IOException If an IO problem occurs.
136      */
137     public void close() throws IOException {
138         if (!selfClosed) {
139             selfClosed = true;
140             notifyWatcher();
141         }
142     }
143 
144     /***
145      * Close the underlying stream should the end of the stream arrive.
146      *
147      * @param readResult    The result of the read operation to check.
148      * @throws IOException If an IO problem occurs.
149      */
150     private void checkClose(int readResult) throws IOException {
151         if (readResult == -1) {
152             notifyWatcher();
153         }
154     }
155 
156     /***
157      * See whether a read of the underlying stream should be allowed, and if
158      * not, check to see whether our stream has already been closed!
159      *
160      * @return <code>true</code> if it is still OK to read from the stream.
161      * @throws IOException If an IO problem occurs.
162      */
163     private boolean isReadAllowed() throws IOException {
164         if (!streamOpen && selfClosed) {
165             throw new IOException("Attempted read on closed stream.");
166         }
167         return streamOpen;
168     }
169 
170     /***
171      * Notify the watcher that the contents have been consumed.
172      * @throws IOException If an IO problem occurs.
173      */
174     private void notifyWatcher() throws IOException {
175         if (streamOpen) {
176             super.close();
177             streamOpen = false;
178 
179             if (watcher != null) {
180                 watcher.responseConsumed();
181             }
182         }
183     }
184 }
185