All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.http.conn.EofSensorInputStream Maven / Gradle / Ivy

There is a newer version: 4.5.14
Show newest version
/*
 * ====================================================================
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * .
 *
 */

package org.apache.http.conn;

import java.io.InputStream;
import java.io.IOException;

import org.apache.http.annotation.NotThreadSafe;

/**
 * A stream wrapper that triggers actions on {@link #close close()} and EOF.
 * Primarily used to auto-release an underlying
 * {@link ManagedClientConnection connection}
 * when the response body is consumed or no longer needed.
 * 

* This class is based on AutoCloseInputStream in HttpClient 3.1, * but has notable differences. It does not allow mark/reset, distinguishes * different kinds of event, and does not always close the underlying stream * on EOF. That decision is left to the {@link EofSensorWatcher watcher}. * * @see EofSensorWatcher * * @since 4.0 */ // don't use FilterInputStream as the base class, we'd have to // override markSupported(), mark(), and reset() to disable them @NotThreadSafe public class EofSensorInputStream extends InputStream implements ConnectionReleaseTrigger { /** * The wrapped input stream, while accessible. * The value changes to null when the wrapped stream * becomes inaccessible. */ protected InputStream wrappedStream; /** * Indicates whether this stream itself is closed. * If it isn't, but {@link #wrappedStream wrappedStream} * is null, we're running in EOF mode. * All read operations will indicate EOF without accessing * the underlying stream. After closing this stream, read * operations will trigger an {@link IOException IOException}. * * @see #isReadAllowed isReadAllowed */ private boolean selfClosed; /** The watcher to be notified, if any. */ private final EofSensorWatcher eofWatcher; /** * Creates a new EOF sensor. * If no watcher is passed, the underlying stream will simply be * closed when EOF is detected or {@link #close close} is called. * Otherwise, the watcher decides whether the underlying stream * should be closed before detaching from it. * * @param in the wrapped stream * @param watcher the watcher for events, or null for * auto-close behavior without notification */ public EofSensorInputStream(final InputStream in, final EofSensorWatcher watcher) { if (in == null) { throw new IllegalArgumentException ("Wrapped stream may not be null."); } wrappedStream = in; selfClosed = false; eofWatcher = watcher; } /** * Checks whether the underlying stream can be read from. * * @return true if the underlying stream is accessible, * false if this stream is in EOF mode and * detached from the underlying stream * * @throws IOException if this stream is already closed */ protected boolean isReadAllowed() throws IOException { if (selfClosed) { throw new IOException("Attempted read on closed stream."); } return (wrappedStream != null); } @Override public int read() throws IOException { int l = -1; if (isReadAllowed()) { try { l = wrappedStream.read(); checkEOF(l); } catch (IOException ex) { checkAbort(); throw ex; } } return l; } @Override public int read(byte[] b, int off, int len) throws IOException { int l = -1; if (isReadAllowed()) { try { l = wrappedStream.read(b, off, len); checkEOF(l); } catch (IOException ex) { checkAbort(); throw ex; } } return l; } @Override public int read(byte[] b) throws IOException { int l = -1; if (isReadAllowed()) { try { l = wrappedStream.read(b); checkEOF(l); } catch (IOException ex) { checkAbort(); throw ex; } } return l; } @Override public int available() throws IOException { int a = 0; // not -1 if (isReadAllowed()) { try { a = wrappedStream.available(); // no checkEOF() here, available() can't trigger EOF } catch (IOException ex) { checkAbort(); throw ex; } } return a; } @Override public void close() throws IOException { // tolerate multiple calls to close() selfClosed = true; checkClose(); } /** * Detects EOF and notifies the watcher. * This method should only be called while the underlying stream is * still accessible. Use {@link #isReadAllowed isReadAllowed} to * check that condition. *
* If EOF is detected, the watcher will be notified and this stream * is detached from the underlying stream. This prevents multiple * notifications from this stream. * * @param eof the result of the calling read operation. * A negative value indicates that EOF is reached. * * @throws IOException * in case of an IO problem on closing the underlying stream */ protected void checkEOF(int eof) throws IOException { if ((wrappedStream != null) && (eof < 0)) { try { boolean scws = true; // should close wrapped stream? if (eofWatcher != null) scws = eofWatcher.eofDetected(wrappedStream); if (scws) wrappedStream.close(); } finally { wrappedStream = null; } } } /** * Detects stream close and notifies the watcher. * There's not much to detect since this is called by {@link #close close}. * The watcher will only be notified if this stream is closed * for the first time and before EOF has been detected. * This stream will be detached from the underlying stream to prevent * multiple notifications to the watcher. * * @throws IOException * in case of an IO problem on closing the underlying stream */ protected void checkClose() throws IOException { if (wrappedStream != null) { try { boolean scws = true; // should close wrapped stream? if (eofWatcher != null) scws = eofWatcher.streamClosed(wrappedStream); if (scws) wrappedStream.close(); } finally { wrappedStream = null; } } } /** * Detects stream abort and notifies the watcher. * There's not much to detect since this is called by * {@link #abortConnection abortConnection}. * The watcher will only be notified if this stream is aborted * for the first time and before EOF has been detected or the * stream has been {@link #close closed} gracefully. * This stream will be detached from the underlying stream to prevent * multiple notifications to the watcher. * * @throws IOException * in case of an IO problem on closing the underlying stream */ protected void checkAbort() throws IOException { if (wrappedStream != null) { try { boolean scws = true; // should close wrapped stream? if (eofWatcher != null) scws = eofWatcher.streamAbort(wrappedStream); if (scws) wrappedStream.close(); } finally { wrappedStream = null; } } } /** * Same as {@link #close close()}. */ public void releaseConnection() throws IOException { close(); } /** * Aborts this stream. * This is a special version of {@link #close close()} which prevents * re-use of the underlying connection, if any. Calling this method * indicates that there should be no attempt to read until the end of * the stream. */ public void abortConnection() throws IOException { // tolerate multiple calls selfClosed = true; checkAbort(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy