1 /*
2  * ====================================================================
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with 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,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  * ====================================================================
20  *
21  * This software consists of voluntary contributions made by many
22  * individuals on behalf of the Apache Software Foundation.  For more
23  * information on the Apache Software Foundation, please see
24  * <http://www.apache.org/>.
25  *
26  */
27 package ch.boye.httpclientandroidlib.conn;
28 
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32 import java.net.SocketException;
33 
34 import ch.boye.httpclientandroidlib.HttpEntity;
35 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
36 import ch.boye.httpclientandroidlib.entity.HttpEntityWrapper;
37 import ch.boye.httpclientandroidlib.util.Args;
38 import ch.boye.httpclientandroidlib.util.EntityUtils;
39 
40 /**
41  * An entity that releases a {@link ManagedClientConnection connection}.
42  * A {@link ManagedClientConnection} will
43  * typically <i>not</i> return a managed entity, but you can replace
44  * the unmanaged entity in the response with a managed one.
45  *
46  * @since 4.0
47  *
48  * @deprecated (4.3) do not use.
49  */
50 @Deprecated
51 @NotThreadSafe
52 public class BasicManagedEntity extends HttpEntityWrapper
53     implements ConnectionReleaseTrigger, EofSensorWatcher {
54 
55     /** The connection to release. */
56     protected ManagedClientConnection managedConn;
57 
58     /** Whether to keep the connection alive. */
59     protected final boolean attemptReuse;
60 
61     /**
62      * Creates a new managed entity that can release a connection.
63      *
64      * @param entity    the entity of which to wrap the content.
65      *                  Note that the argument entity can no longer be used
66      *                  afterwards, since the content will be taken by this
67      *                  managed entity.
68      * @param conn      the connection to release
69      * @param reuse     whether the connection should be re-used
70      */
BasicManagedEntity(final HttpEntity entity, final ManagedClientConnection conn, final boolean reuse)71     public BasicManagedEntity(final HttpEntity entity,
72                               final ManagedClientConnection conn,
73                               final boolean reuse) {
74         super(entity);
75         Args.notNull(conn, "Connection");
76         this.managedConn = conn;
77         this.attemptReuse = reuse;
78     }
79 
80     @Override
isRepeatable()81     public boolean isRepeatable() {
82         return false;
83     }
84 
85     @Override
getContent()86     public InputStream getContent() throws IOException {
87         return new EofSensorInputStream(wrappedEntity.getContent(), this);
88     }
89 
ensureConsumed()90     private void ensureConsumed() throws IOException {
91         if (managedConn == null) {
92             return;
93         }
94 
95         try {
96             if (attemptReuse) {
97                 // this will not trigger a callback from EofSensorInputStream
98                 EntityUtils.consume(wrappedEntity);
99                 managedConn.markReusable();
100             } else {
101                 managedConn.unmarkReusable();
102             }
103         } finally {
104             releaseManagedConnection();
105         }
106     }
107 
108     /**
109      * @deprecated (4.1) Use {@link EntityUtils#consume(HttpEntity)}
110      */
111     @Deprecated
112     @Override
consumeContent()113     public void consumeContent() throws IOException {
114         ensureConsumed();
115     }
116 
117     @Override
writeTo(final OutputStream outstream)118     public void writeTo(final OutputStream outstream) throws IOException {
119         super.writeTo(outstream);
120         ensureConsumed();
121     }
122 
releaseConnection()123     public void releaseConnection() throws IOException {
124         ensureConsumed();
125     }
126 
abortConnection()127     public void abortConnection() throws IOException {
128 
129         if (managedConn != null) {
130             try {
131                 managedConn.abortConnection();
132             } finally {
133                 managedConn = null;
134             }
135         }
136     }
137 
eofDetected(final InputStream wrapped)138     public boolean eofDetected(final InputStream wrapped) throws IOException {
139         try {
140             if (managedConn != null) {
141                 if (attemptReuse) {
142                     // there may be some cleanup required, such as
143                     // reading trailers after the response body:
144                     wrapped.close();
145                     managedConn.markReusable();
146                 } else {
147                     managedConn.unmarkReusable();
148                 }
149             }
150         } finally {
151             releaseManagedConnection();
152         }
153         return false;
154     }
155 
streamClosed(final InputStream wrapped)156     public boolean streamClosed(final InputStream wrapped) throws IOException {
157         try {
158             if (managedConn != null) {
159                 if (attemptReuse) {
160                     final boolean valid = managedConn.isOpen();
161                     // this assumes that closing the stream will
162                     // consume the remainder of the response body:
163                     try {
164                         wrapped.close();
165                         managedConn.markReusable();
166                     } catch (final SocketException ex) {
167                         if (valid) {
168                             throw ex;
169                         }
170                     }
171                 } else {
172                     managedConn.unmarkReusable();
173                 }
174             }
175         } finally {
176             releaseManagedConnection();
177         }
178         return false;
179     }
180 
streamAbort(final InputStream wrapped)181     public boolean streamAbort(final InputStream wrapped) throws IOException {
182         if (managedConn != null) {
183             managedConn.abortConnection();
184         }
185         return false;
186     }
187 
188     /**
189      * Releases the connection gracefully.
190      * The connection attribute will be nullified.
191      * Subsequent invocations are no-ops.
192      *
193      * @throws IOException      in case of an IO problem.
194      *         The connection attribute will be nullified anyway.
195      */
releaseManagedConnection()196     protected void releaseManagedConnection()
197         throws IOException {
198 
199         if (managedConn != null) {
200             try {
201                 managedConn.releaseConnection();
202             } finally {
203                 managedConn = null;
204             }
205         }
206     }
207 
208 }
209