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: 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