1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/BasicManagedEntity.java $
3 * $Revision $
4 * $Date: 2008-06-27 12:49:20 -0700 (Fri, 27 Jun 2008) $
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
31package org.apache.http.conn;
32
33import java.io.IOException;
34import java.io.InputStream;
35import java.io.OutputStream;
36
37import org.apache.http.HttpEntity;
38import org.apache.http.entity.HttpEntityWrapper;
39
40
41/**
42 * An entity that releases a {@link ManagedClientConnection connection}.
43 * A {@link ManagedClientConnection} will
44 * typically <i>not</i> return a managed entity, but you can replace
45 * the unmanaged entity in the response with a managed one.
46 *
47 * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
48 *
49 *
50 * <!-- empty lines to avoid svn diff problems -->
51 * @version $Revision: 672367 $
52 *
53 * @since 4.0
54 */
55public class BasicManagedEntity extends HttpEntityWrapper
56    implements ConnectionReleaseTrigger, EofSensorWatcher {
57
58    /** The connection to release. */
59    protected ManagedClientConnection managedConn;
60
61    /** Whether to keep the connection alive. */
62    protected final boolean attemptReuse;
63
64
65    /**
66     * Creates a new managed entity that can release a connection.
67     *
68     * @param entity    the entity of which to wrap the content.
69     *                  Note that the argument entity can no longer be used
70     *                  afterwards, since the content will be taken by this
71     *                  managed entity.
72     * @param conn      the connection to release
73     * @param reuse     whether the connection should be re-used
74     */
75    public BasicManagedEntity(HttpEntity entity,
76                              ManagedClientConnection conn,
77                              boolean reuse) {
78        super(entity);
79
80        if (conn == null)
81            throw new IllegalArgumentException
82                ("Connection may not be null.");
83
84        this.managedConn = conn;
85        this.attemptReuse = reuse;
86    }
87
88
89    // non-javadoc, see interface HttpEntity
90    @Override
91    public boolean isRepeatable() {
92        return false;
93    }
94
95
96    // non-javadoc, see interface HttpEntity
97    @Override
98    public InputStream getContent() throws IOException {
99
100        return new EofSensorInputStream(wrappedEntity.getContent(), this);
101    }
102
103
104    // non-javadoc, see interface HttpEntity
105    @Override
106    public void consumeContent() throws IOException {
107
108        if (managedConn == null)
109            return;
110
111        try {
112            if (attemptReuse) {
113                // this will not trigger a callback from EofSensorInputStream
114                wrappedEntity.consumeContent();
115                managedConn.markReusable();
116            }
117        } finally {
118            releaseManagedConnection();
119        }
120    }
121
122
123    // non-javadoc, see interface HttpEntity
124    @Override
125    public void writeTo(final OutputStream outstream) throws IOException {
126        super.writeTo(outstream);
127        consumeContent();
128    }
129
130
131    // non-javadoc, see interface ConnectionReleaseTrigger
132    public void releaseConnection()
133        throws IOException {
134
135        this.consumeContent();
136    }
137
138
139    // non-javadoc, see interface ConnectionReleaseTrigger
140    public void abortConnection()
141        throws IOException {
142
143        if (managedConn != null) {
144            try {
145                managedConn.abortConnection();
146            } finally {
147                managedConn = null;
148            }
149        }
150    }
151
152
153    // non-javadoc, see interface EofSensorWatcher
154    public boolean eofDetected(InputStream wrapped)
155        throws IOException {
156
157        try {
158            if (attemptReuse && (managedConn != null)) {
159                // there may be some cleanup required, such as
160                // reading trailers after the response body:
161                wrapped.close();
162                managedConn.markReusable();
163            }
164        } finally {
165            releaseManagedConnection();
166        }
167        return false;
168    }
169
170
171    // non-javadoc, see interface EofSensorWatcher
172    public boolean streamClosed(InputStream wrapped)
173        throws IOException {
174
175        try {
176            if (attemptReuse && (managedConn != null)) {
177                // this assumes that closing the stream will
178                // consume the remainder of the response body:
179                wrapped.close();
180                managedConn.markReusable();
181            }
182        } finally {
183            releaseManagedConnection();
184        }
185        return false;
186    }
187
188
189    // non-javadoc, see interface EofSensorWatcher
190    public boolean streamAbort(InputStream wrapped)
191        throws IOException {
192
193        if (managedConn != null) {
194            managedConn.abortConnection();
195        }
196        return false;
197    }
198
199
200    /**
201     * Releases the connection gracefully.
202     * The connection attribute will be nullified.
203     * Subsequent invocations are no-ops.
204     *
205     * @throws IOException      in case of an IO problem.
206     *         The connection attribute will be nullified anyway.
207     */
208    protected void releaseManagedConnection()
209        throws IOException {
210
211        if (managedConn != null) {
212            try {
213                managedConn.releaseConnection();
214            } finally {
215                managedConn = null;
216            }
217        }
218    }
219
220} // class BasicManagedEntity
221