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