mobile/android/thirdparty/ch/boye/httpclientandroidlib/conn/EofSensorInputStream.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2  * ====================================================================
     3  *
     4  *  Licensed to the Apache Software Foundation (ASF) under one or more
     5  *  contributor license agreements.  See the NOTICE file distributed with
     6  *  this work for additional information regarding copyright ownership.
     7  *  The ASF licenses this file to You under the Apache License, Version 2.0
     8  *  (the "License"); you may not use this file except in compliance with
     9  *  the License.  You may obtain a copy of the License at
    10  *
    11  *      http://www.apache.org/licenses/LICENSE-2.0
    12  *
    13  *  Unless required by applicable law or agreed to in writing, software
    14  *  distributed under the License is distributed on an "AS IS" BASIS,
    15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  *  See the License for the specific language governing permissions and
    17  *  limitations under the License.
    18  * ====================================================================
    19  *
    20  * This software consists of voluntary contributions made by many
    21  * individuals on behalf of the Apache Software Foundation.  For more
    22  * information on the Apache Software Foundation, please see
    23  * <http://www.apache.org/>.
    24  *
    25  */
    27 package ch.boye.httpclientandroidlib.conn;
    29 import java.io.InputStream;
    30 import java.io.IOException;
    32 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
    34 /**
    35  * A stream wrapper that triggers actions on {@link #close close()} and EOF.
    36  * Primarily used to auto-release an underlying
    37  * {@link ManagedClientConnection connection}
    38  * when the response body is consumed or no longer needed.
    39  * <p>
    40  * This class is based on <code>AutoCloseInputStream</code> in HttpClient 3.1,
    41  * but has notable differences. It does not allow mark/reset, distinguishes
    42  * different kinds of event, and does not always close the underlying stream
    43  * on EOF. That decision is left to the {@link EofSensorWatcher watcher}.
    44  *
    45  * @see EofSensorWatcher
    46  *
    47  * @since 4.0
    48  */
    49 // don't use FilterInputStream as the base class, we'd have to
    50 // override markSupported(), mark(), and reset() to disable them
    51 @NotThreadSafe
    52 public class EofSensorInputStream extends InputStream implements ConnectionReleaseTrigger {
    54     /**
    55      * The wrapped input stream, while accessible.
    56      * The value changes to <code>null</code> when the wrapped stream
    57      * becomes inaccessible.
    58      */
    59     protected InputStream wrappedStream;
    61     /**
    62      * Indicates whether this stream itself is closed.
    63      * If it isn't, but {@link #wrappedStream wrappedStream}
    64      * is <code>null</code>, we're running in EOF mode.
    65      * All read operations will indicate EOF without accessing
    66      * the underlying stream. After closing this stream, read
    67      * operations will trigger an {@link IOException IOException}.
    68      *
    69      * @see #isReadAllowed isReadAllowed
    70      */
    71     private boolean selfClosed;
    73     /** The watcher to be notified, if any. */
    74     private final EofSensorWatcher eofWatcher;
    76     /**
    77      * Creates a new EOF sensor.
    78      * If no watcher is passed, the underlying stream will simply be
    79      * closed when EOF is detected or {@link #close close} is called.
    80      * Otherwise, the watcher decides whether the underlying stream
    81      * should be closed before detaching from it.
    82      *
    83      * @param in        the wrapped stream
    84      * @param watcher   the watcher for events, or <code>null</code> for
    85      *                  auto-close behavior without notification
    86      */
    87     public EofSensorInputStream(final InputStream in,
    88                                 final EofSensorWatcher watcher) {
    89         if (in == null) {
    90             throw new IllegalArgumentException
    91                 ("Wrapped stream may not be null.");
    92         }
    94         wrappedStream = in;
    95         selfClosed = false;
    96         eofWatcher = watcher;
    97     }
    99     /**
   100      * Checks whether the underlying stream can be read from.
   101      *
   102      * @return  <code>true</code> if the underlying stream is accessible,
   103      *          <code>false</code> if this stream is in EOF mode and
   104      *          detached from the underlying stream
   105      *
   106      * @throws IOException      if this stream is already closed
   107      */
   108     protected boolean isReadAllowed() throws IOException {
   109         if (selfClosed) {
   110             throw new IOException("Attempted read on closed stream.");
   111         }
   112         return (wrappedStream != null);
   113     }
   115     @Override
   116     public int read() throws IOException {
   117         int l = -1;
   119         if (isReadAllowed()) {
   120             try {
   121                 l = wrappedStream.read();
   122                 checkEOF(l);
   123             } catch (IOException ex) {
   124                 checkAbort();
   125                 throw ex;
   126             }
   127         }
   129         return l;
   130     }
   132     @Override
   133     public int read(byte[] b, int off, int len) throws IOException {
   134         int l = -1;
   136         if (isReadAllowed()) {
   137             try {
   138                 l = wrappedStream.read(b,  off,  len);
   139                 checkEOF(l);
   140             } catch (IOException ex) {
   141                 checkAbort();
   142                 throw ex;
   143             }
   144         }
   146         return l;
   147     }
   149     @Override
   150     public int read(byte[] b) throws IOException {
   151         int l = -1;
   153         if (isReadAllowed()) {
   154             try {
   155                 l = wrappedStream.read(b);
   156                 checkEOF(l);
   157             } catch (IOException ex) {
   158                 checkAbort();
   159                 throw ex;
   160             }
   161         }
   162         return l;
   163     }
   165     @Override
   166     public int available() throws IOException {
   167         int a = 0; // not -1
   169         if (isReadAllowed()) {
   170             try {
   171                 a = wrappedStream.available();
   172                 // no checkEOF() here, available() can't trigger EOF
   173             } catch (IOException ex) {
   174                 checkAbort();
   175                 throw ex;
   176             }
   177         }
   179         return a;
   180     }
   182     @Override
   183     public void close() throws IOException {
   184         // tolerate multiple calls to close()
   185         selfClosed = true;
   186         checkClose();
   187     }
   189     /**
   190      * Detects EOF and notifies the watcher.
   191      * This method should only be called while the underlying stream is
   192      * still accessible. Use {@link #isReadAllowed isReadAllowed} to
   193      * check that condition.
   194      * <br/>
   195      * If EOF is detected, the watcher will be notified and this stream
   196      * is detached from the underlying stream. This prevents multiple
   197      * notifications from this stream.
   198      *
   199      * @param eof       the result of the calling read operation.
   200      *                  A negative value indicates that EOF is reached.
   201      *
   202      * @throws IOException
   203      *          in case of an IO problem on closing the underlying stream
   204      */
   205     protected void checkEOF(int eof) throws IOException {
   207         if ((wrappedStream != null) && (eof < 0)) {
   208             try {
   209                 boolean scws = true; // should close wrapped stream?
   210                 if (eofWatcher != null)
   211                     scws = eofWatcher.eofDetected(wrappedStream);
   212                 if (scws)
   213                     wrappedStream.close();
   214             } finally {
   215                 wrappedStream = null;
   216             }
   217         }
   218     }
   220     /**
   221      * Detects stream close and notifies the watcher.
   222      * There's not much to detect since this is called by {@link #close close}.
   223      * The watcher will only be notified if this stream is closed
   224      * for the first time and before EOF has been detected.
   225      * This stream will be detached from the underlying stream to prevent
   226      * multiple notifications to the watcher.
   227      *
   228      * @throws IOException
   229      *          in case of an IO problem on closing the underlying stream
   230      */
   231     protected void checkClose() throws IOException {
   233         if (wrappedStream != null) {
   234             try {
   235                 boolean scws = true; // should close wrapped stream?
   236                 if (eofWatcher != null)
   237                     scws = eofWatcher.streamClosed(wrappedStream);
   238                 if (scws)
   239                     wrappedStream.close();
   240             } finally {
   241                 wrappedStream = null;
   242             }
   243         }
   244     }
   246     /**
   247      * Detects stream abort and notifies the watcher.
   248      * There's not much to detect since this is called by
   249      * {@link #abortConnection abortConnection}.
   250      * The watcher will only be notified if this stream is aborted
   251      * for the first time and before EOF has been detected or the
   252      * stream has been {@link #close closed} gracefully.
   253      * This stream will be detached from the underlying stream to prevent
   254      * multiple notifications to the watcher.
   255      *
   256      * @throws IOException
   257      *          in case of an IO problem on closing the underlying stream
   258      */
   259     protected void checkAbort() throws IOException {
   261         if (wrappedStream != null) {
   262             try {
   263                 boolean scws = true; // should close wrapped stream?
   264                 if (eofWatcher != null)
   265                     scws = eofWatcher.streamAbort(wrappedStream);
   266                 if (scws)
   267                     wrappedStream.close();
   268             } finally {
   269                 wrappedStream = null;
   270             }
   271         }
   272     }
   274     /**
   275      * Same as {@link #close close()}.
   276      */
   277     public void releaseConnection() throws IOException {
   278         close();
   279     }
   281     /**
   282      * Aborts this stream.
   283      * This is a special version of {@link #close close()} which prevents
   284      * re-use of the underlying connection, if any. Calling this method
   285      * indicates that there should be no attempt to read until the end of
   286      * the stream.
   287      */
   288     public void abortConnection() throws IOException {
   289         // tolerate multiple calls
   290         selfClosed = true;
   291         checkAbort();
   292     }
   294 }

mercurial