Home | History | Annotate | Download | only in conn
      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      */
    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      */
    129     protected void detach() {
    130         wrappedConnection = null;
    131         connManager = null; // base class attribute
    132         duration = Long.MAX_VALUE;
    133     }
    134 
    135     protected OperatedClientConnection getWrappedConnection() {
    136         return wrappedConnection;
    137     }
    138 
    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      */
    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      */
    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
    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
    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
    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
    198     public int getSocketTimeout() {
    199         OperatedClientConnection conn = getWrappedConnection();
    200         assertValid(conn);
    201         return conn.getSocketTimeout();
    202     }
    203 
    204 
    205     // non-javadoc, see interface HttpConnection
    206     public HttpConnectionMetrics getMetrics() {
    207         OperatedClientConnection conn = getWrappedConnection();
    208         assertValid(conn);
    209         return conn.getMetrics();
    210     }
    211 
    212 
    213     // non-javadoc, see interface HttpClientConnection
    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
    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
    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
    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
    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
    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
    290     public InetAddress getLocalAddress() {
    291         OperatedClientConnection conn = getWrappedConnection();
    292         assertValid(conn);
    293         return conn.getLocalAddress();
    294     }
    295 
    296     // non-javadoc, see interface HttpInetConnection
    297     public int getLocalPort() {
    298         OperatedClientConnection conn = getWrappedConnection();
    299         assertValid(conn);
    300         return conn.getLocalPort();
    301     }
    302 
    303 
    304     // non-javadoc, see interface HttpInetConnection
    305     public InetAddress getRemoteAddress() {
    306         OperatedClientConnection conn = getWrappedConnection();
    307         assertValid(conn);
    308         return conn.getRemoteAddress();
    309     }
    310 
    311     // non-javadoc, see interface HttpInetConnection
    312     public int getRemotePort() {
    313         OperatedClientConnection conn = getWrappedConnection();
    314         assertValid(conn);
    315         return conn.getRemotePort();
    316     }
    317 
    318     // non-javadoc, see interface ManagedClientConnection
    319     public boolean isSecure() {
    320         OperatedClientConnection conn = getWrappedConnection();
    321         assertValid(conn);
    322         return conn.isSecure();
    323     }
    324 
    325     // non-javadoc, see interface ManagedClientConnection
    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
    341     public void markReusable() {
    342         markedReusable = true;
    343     }
    344 
    345     // non-javadoc, see interface ManagedClientConnection
    346     public void unmarkReusable() {
    347         markedReusable = false;
    348     }
    349 
    350     // non-javadoc, see interface ManagedClientConnection
    351     public boolean isMarkedReusable() {
    352         return markedReusable;
    353     }
    354 
    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
    364     public void releaseConnection() {
    365         if (connManager != null) {
    366             connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS);
    367         }
    368     }
    369 
    370     // non-javadoc, see interface ConnectionReleaseTrigger
    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