View Javadoc

1   /*
2    * $Revision $
3    * ====================================================================
4    *
5    *  Licensed to the Apache Software Foundation (ASF) under one or more
6    *  contributor license agreements.  See the NOTICE file distributed with
7    *  this work for additional information regarding copyright ownership.
8    *  The ASF licenses this file to You under the Apache License, Version 2.0
9    *  (the "License"); you may not use this file except in compliance with
10   *  the License.  You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   *  Unless required by applicable law or agreed to in writing, software
15   *  distributed under the License is distributed on an "AS IS" BASIS,
16   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   *  See the License for the specific language governing permissions and
18   *  limitations 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  
28  package org.apache.http.conn;
29  
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.OutputStream;
33  import java.net.SocketException;
34  
35  import org.apache.http.annotation.NotThreadSafe;
36  
37  import org.apache.http.HttpEntity;
38  import org.apache.http.entity.HttpEntityWrapper;
39  import org.apache.http.util.EntityUtils;
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   * @since 4.0
48   */
49  @NotThreadSafe
50  public class BasicManagedEntity extends HttpEntityWrapper
51      implements ConnectionReleaseTrigger, EofSensorWatcher {
52  
53      /** The connection to release. */
54      protected ManagedClientConnection managedConn;
55  
56      /** Whether to keep the connection alive. */
57      protected final boolean attemptReuse;
58  
59      /**
60       * Creates a new managed entity that can release a connection.
61       *
62       * @param entity    the entity of which to wrap the content.
63       *                  Note that the argument entity can no longer be used
64       *                  afterwards, since the content will be taken by this
65       *                  managed entity.
66       * @param conn      the connection to release
67       * @param reuse     whether the connection should be re-used
68       */
69      public BasicManagedEntity(HttpEntity entity,
70                                ManagedClientConnection conn,
71                                boolean reuse) {
72          super(entity);
73  
74          if (conn == null)
75              throw new IllegalArgumentException
76                  ("Connection may not be null.");
77  
78          this.managedConn = conn;
79          this.attemptReuse = reuse;
80      }
81  
82      @Override
83      public boolean isRepeatable() {
84          return false;
85      }
86  
87      @Override
88      public InputStream getContent() throws IOException {
89          return new EofSensorInputStream(wrappedEntity.getContent(), this);
90      }
91  
92      private void ensureConsumed() throws IOException {
93          if (managedConn == null)
94              return;
95  
96          try {
97              if (attemptReuse) {
98                  // this will not trigger a callback from EofSensorInputStream
99                  EntityUtils.consume(wrappedEntity);
100                 managedConn.markReusable();
101             } else {
102                 managedConn.unmarkReusable();
103             }
104         } finally {
105             releaseManagedConnection();
106         }
107     }
108 
109     /**
110      * @deprecated (4.1) Use {@link EntityUtils#consume(HttpEntity)}
111      */
112     @Override
113     public void consumeContent() throws IOException {
114         ensureConsumed();
115     }
116 
117     @Override
118     public void writeTo(final OutputStream outstream) throws IOException {
119         super.writeTo(outstream);
120         ensureConsumed();
121     }
122 
123     public void releaseConnection() throws IOException {
124         ensureConsumed();
125     }
126 
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 
138     public boolean eofDetected(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 
156     public boolean streamClosed(InputStream wrapped) throws IOException {
157         try {
158             if (managedConn != null) {
159                 if (attemptReuse) {
160                     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 (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 
181     public boolean streamAbort(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      */
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 }