• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractClientConnAdapter.java $
3  * $Revision: 672969 $
4  * $Date: 2008-06-30 18:09:50 -0700 (Mon, 30 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 
31 package org.apache.http.impl.conn;
32 
33 
34 import java.io.IOException;
35 import java.io.InterruptedIOException;
36 import java.net.InetAddress;
37 import java.net.Socket;
38 import java.util.concurrent.TimeUnit;
39 
40 import javax.net.ssl.SSLSocket;
41 import javax.net.ssl.SSLSession;
42 
43 import org.apache.http.HttpException;
44 import org.apache.http.HttpRequest;
45 import org.apache.http.HttpEntityEnclosingRequest;
46 import org.apache.http.HttpResponse;
47 import org.apache.http.HttpConnectionMetrics;
48 import org.apache.http.conn.OperatedClientConnection;
49 import org.apache.http.conn.ManagedClientConnection;
50 import org.apache.http.conn.ClientConnectionManager;
51 
52 
53 /**
54  * Abstract adapter from {@link OperatedClientConnection operated} to
55  * {@link ManagedClientConnection managed} client connections.
56  * Read and write methods are delegated to the wrapped connection.
57  * Operations affecting the connection state have to be implemented
58  * by derived classes. Operations for querying the connection state
59  * are delegated to the wrapped connection if there is one, or
60  * return a default value if there is none.
61  * <br/>
62  * This adapter tracks the checkpoints for reusable communication states,
63  * as indicated by {@link #markReusable markReusable} and queried by
64  * {@link #isMarkedReusable isMarkedReusable}.
65  * All send and receive operations will automatically clear the mark.
66  * <br/>
67  * Connection release calls are delegated to the connection manager,
68  * if there is one. {@link #abortConnection abortConnection} will
69  * clear the reusability mark first. The connection manager is
70  * expected to tolerate multiple calls to the release method.
71  *
72  * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
73  *
74  *
75  * <!-- empty lines to avoid svn diff problems -->
76  * @version   $Revision: 672969 $ $Date: 2008-06-30 18:09:50 -0700 (Mon, 30 Jun 2008) $
77  *
78  * @since 4.0
79  */
80 public abstract class AbstractClientConnAdapter
81     implements ManagedClientConnection {
82 
83     /** Thread that requested this connection. */
84     private final Thread executionThread;
85 
86     /**
87      * The connection manager, if any.
88      * This attribute MUST NOT be final, so the adapter can be detached
89      * from the connection manager without keeping a hard reference there.
90      */
91     private volatile ClientConnectionManager connManager;
92 
93     /** The wrapped connection. */
94     private volatile OperatedClientConnection wrappedConnection;
95 
96     /** The reusability marker. */
97     private volatile boolean markedReusable;
98 
99     /** True if the connection has been aborted. */
100     private volatile boolean aborted;
101 
102     /** The duration this is valid for while idle (in ms). */
103     private volatile long duration;
104 
105     /**
106      * Creates a new connection adapter.
107      * The adapter is initially <i>not</i>
108      * {@link #isMarkedReusable marked} as reusable.
109      *
110      * @param mgr       the connection manager, or <code>null</code>
111      * @param conn      the connection to wrap, or <code>null</code>
112      */
AbstractClientConnAdapter(ClientConnectionManager mgr, OperatedClientConnection conn)113     protected AbstractClientConnAdapter(ClientConnectionManager mgr,
114                                         OperatedClientConnection conn) {
115         super();
116         executionThread = Thread.currentThread();
117         connManager = mgr;
118         wrappedConnection = conn;
119         markedReusable = false;
120         aborted = false;
121         duration = Long.MAX_VALUE;
122     } // <constructor>
123 
124 
125     /**
126      * Detaches this adapter from the wrapped connection.
127      * This adapter becomes useless.
128      */
detach()129     protected void detach() {
130         wrappedConnection = null;
131         connManager = null; // base class attribute
132         duration = Long.MAX_VALUE;
133     }
134 
getWrappedConnection()135     protected OperatedClientConnection getWrappedConnection() {
136         return wrappedConnection;
137     }
138 
getManager()139     protected ClientConnectionManager getManager() {
140         return connManager;
141     }
142 
143     /**
144      * Asserts that the connection has not been aborted.
145      *
146      * @throws InterruptedIOException   if the connection has been aborted
147      */
assertNotAborted()148     protected final void assertNotAborted() throws InterruptedIOException {
149         if (aborted) {
150             throw new InterruptedIOException("Connection has been shut down.");
151         }
152     }
153 
154     /**
155      * Asserts that there is a wrapped connection to delegate to.
156      *
157      * @throws IllegalStateException    if there is no wrapped connection
158      *                                  or connection has been aborted
159      */
assertValid( final OperatedClientConnection wrappedConn)160     protected final void assertValid(
161             final OperatedClientConnection wrappedConn) {
162         if (wrappedConn == null) {
163             throw new IllegalStateException("No wrapped connection.");
164         }
165     }
166 
167     // non-javadoc, see interface HttpConnection
isOpen()168     public boolean isOpen() {
169         OperatedClientConnection conn = getWrappedConnection();
170         if (conn == null)
171             return false;
172 
173         return conn.isOpen();
174     }
175 
176 
177     // non-javadoc, see interface HttpConnection
isStale()178     public boolean isStale() {
179         if (aborted)
180             return true;
181         OperatedClientConnection conn = getWrappedConnection();
182         if (conn == null)
183             return true;
184 
185         return conn.isStale();
186     }
187 
188 
189     // non-javadoc, see interface HttpConnection
setSocketTimeout(int timeout)190     public void setSocketTimeout(int timeout) {
191         OperatedClientConnection conn = getWrappedConnection();
192         assertValid(conn);
193         conn.setSocketTimeout(timeout);
194     }
195 
196 
197     // non-javadoc, see interface HttpConnection
getSocketTimeout()198     public int getSocketTimeout() {
199         OperatedClientConnection conn = getWrappedConnection();
200         assertValid(conn);
201         return conn.getSocketTimeout();
202     }
203 
204 
205     // non-javadoc, see interface HttpConnection
getMetrics()206     public HttpConnectionMetrics getMetrics() {
207         OperatedClientConnection conn = getWrappedConnection();
208         assertValid(conn);
209         return conn.getMetrics();
210     }
211 
212 
213     // non-javadoc, see interface HttpClientConnection
flush()214     public void flush()
215         throws IOException {
216 
217         assertNotAborted();
218         OperatedClientConnection conn = getWrappedConnection();
219         assertValid(conn);
220 
221         conn.flush();
222     }
223 
224 
225     // non-javadoc, see interface HttpClientConnection
isResponseAvailable(int timeout)226     public boolean isResponseAvailable(int timeout)
227         throws IOException {
228 
229         assertNotAborted();
230         OperatedClientConnection conn = getWrappedConnection();
231         assertValid(conn);
232 
233         return conn.isResponseAvailable(timeout);
234     }
235 
236 
237     // non-javadoc, see interface HttpClientConnection
receiveResponseEntity(HttpResponse response)238     public void receiveResponseEntity(HttpResponse response)
239         throws HttpException, IOException {
240 
241         assertNotAborted();
242         OperatedClientConnection conn = getWrappedConnection();
243         assertValid(conn);
244 
245         unmarkReusable();
246         conn.receiveResponseEntity(response);
247     }
248 
249 
250     // non-javadoc, see interface HttpClientConnection
receiveResponseHeader()251     public HttpResponse receiveResponseHeader()
252         throws HttpException, IOException {
253 
254         assertNotAborted();
255         OperatedClientConnection conn = getWrappedConnection();
256         assertValid(conn);
257 
258         unmarkReusable();
259         return conn.receiveResponseHeader();
260     }
261 
262 
263     // non-javadoc, see interface HttpClientConnection
sendRequestEntity(HttpEntityEnclosingRequest request)264     public void sendRequestEntity(HttpEntityEnclosingRequest request)
265         throws HttpException, IOException {
266 
267         assertNotAborted();
268         OperatedClientConnection conn = getWrappedConnection();
269         assertValid(conn);
270 
271         unmarkReusable();
272         conn.sendRequestEntity(request);
273     }
274 
275 
276     // non-javadoc, see interface HttpClientConnection
sendRequestHeader(HttpRequest request)277     public void sendRequestHeader(HttpRequest request)
278         throws HttpException, IOException {
279 
280         assertNotAborted();
281         OperatedClientConnection conn = getWrappedConnection();
282         assertValid(conn);
283 
284         unmarkReusable();
285         conn.sendRequestHeader(request);
286     }
287 
288 
289     // non-javadoc, see interface HttpInetConnection
getLocalAddress()290     public InetAddress getLocalAddress() {
291         OperatedClientConnection conn = getWrappedConnection();
292         assertValid(conn);
293         return conn.getLocalAddress();
294     }
295 
296     // non-javadoc, see interface HttpInetConnection
getLocalPort()297     public int getLocalPort() {
298         OperatedClientConnection conn = getWrappedConnection();
299         assertValid(conn);
300         return conn.getLocalPort();
301     }
302 
303 
304     // non-javadoc, see interface HttpInetConnection
getRemoteAddress()305     public InetAddress getRemoteAddress() {
306         OperatedClientConnection conn = getWrappedConnection();
307         assertValid(conn);
308         return conn.getRemoteAddress();
309     }
310 
311     // non-javadoc, see interface HttpInetConnection
getRemotePort()312     public int getRemotePort() {
313         OperatedClientConnection conn = getWrappedConnection();
314         assertValid(conn);
315         return conn.getRemotePort();
316     }
317 
318     // non-javadoc, see interface ManagedClientConnection
isSecure()319     public boolean isSecure() {
320         OperatedClientConnection conn = getWrappedConnection();
321         assertValid(conn);
322         return conn.isSecure();
323     }
324 
325     // non-javadoc, see interface ManagedClientConnection
getSSLSession()326     public SSLSession getSSLSession() {
327         OperatedClientConnection conn = getWrappedConnection();
328         assertValid(conn);
329         if (!isOpen())
330             return null;
331 
332         SSLSession result = null;
333         Socket    sock    = conn.getSocket();
334         if (sock instanceof SSLSocket) {
335             result = ((SSLSocket)sock).getSession();
336         }
337         return result;
338     }
339 
340     // non-javadoc, see interface ManagedClientConnection
markReusable()341     public void markReusable() {
342         markedReusable = true;
343     }
344 
345     // non-javadoc, see interface ManagedClientConnection
unmarkReusable()346     public void unmarkReusable() {
347         markedReusable = false;
348     }
349 
350     // non-javadoc, see interface ManagedClientConnection
isMarkedReusable()351     public boolean isMarkedReusable() {
352         return markedReusable;
353     }
354 
setIdleDuration(long duration, TimeUnit unit)355     public void setIdleDuration(long duration, TimeUnit unit) {
356         if(duration > 0) {
357             this.duration = unit.toMillis(duration);
358         } else {
359             this.duration = -1;
360         }
361     }
362 
363     // non-javadoc, see interface ConnectionReleaseTrigger
releaseConnection()364     public void releaseConnection() {
365         if (connManager != null) {
366             connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS);
367         }
368     }
369 
370     // non-javadoc, see interface ConnectionReleaseTrigger
abortConnection()371     public void abortConnection() {
372         if (aborted) {
373             return;
374         }
375         aborted = true;
376         unmarkReusable();
377         try {
378             shutdown();
379         } catch (IOException ignore) {
380         }
381         // Usually #abortConnection() is expected to be called from
382         // a helper thread in order to unblock the main execution thread
383         // blocked in an I/O operation. It may be unsafe to call
384         // #releaseConnection() from the helper thread, so we have to rely
385         // on an IOException thrown by the closed socket on the main thread
386         // to trigger the release of the connection back to the
387         // connection manager.
388         //
389         // However, if this method is called from the main execution thread
390         // it should be safe to release the connection immediately. Besides,
391         // this also helps ensure the connection gets released back to the
392         // manager if #abortConnection() is called from the main execution
393         // thread while there is no blocking I/O operation.
394         if (executionThread.equals(Thread.currentThread())) {
395             releaseConnection();
396         }
397     }
398 
399 } // class AbstractClientConnAdapter
400