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/AbstractPoolEntry.java $
      3  * $Revision: 658775 $
      4  * $Date: 2008-05-21 10:30:45 -0700 (Wed, 21 May 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 
     36 import org.apache.http.HttpHost;
     37 import org.apache.http.params.HttpParams;
     38 import org.apache.http.protocol.HttpContext;
     39 import org.apache.http.conn.routing.HttpRoute;
     40 import org.apache.http.conn.routing.RouteTracker;
     41 import org.apache.http.conn.ClientConnectionOperator;
     42 import org.apache.http.conn.OperatedClientConnection;
     43 
     44 
     45 
     46 /**
     47  * A pool entry for use by connection manager implementations.
     48  * Pool entries work in conjunction with an
     49  * {@link AbstractClientConnAdapter adapter}.
     50  * The adapter is handed out to applications that obtain a connection.
     51  * The pool entry stores the underlying connection and tracks the
     52  * {@link HttpRoute route} established.
     53  * The adapter delegates methods for establishing the route to
     54  * it's pool entry.
     55  * <br/>
     56  * If the managed connections is released or revoked, the adapter
     57  * gets disconnected, but the pool entry still contains the
     58  * underlying connection and the established route.
     59  *
     60  * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
     61  * @author <a href="mailto:becke (at) u.washington.edu">Michael Becke</a>
     62  *
     63  *
     64  * <!-- empty lines to avoid svn diff problems -->
     65  * @version   $Revision: 658775 $
     66  *
     67  * @since 4.0
     68  */
     69 public abstract class AbstractPoolEntry {
     70 
     71     /** The connection operator. */
     72     protected final ClientConnectionOperator connOperator;
     73 
     74     /** The underlying connection being pooled or used. */
     75     protected final OperatedClientConnection connection;
     76 
     77     /** The route for which this entry gets allocated. */
     78     //@@@ currently accessed from connection manager(s) as attribute
     79     //@@@ avoid that, derived classes should decide whether update is allowed
     80     //@@@ SCCM: yes, TSCCM: no
     81     protected volatile HttpRoute route;
     82 
     83     /** Connection state object */
     84     protected volatile Object state;
     85 
     86     /** The tracked route, or <code>null</code> before tracking starts. */
     87     protected volatile RouteTracker tracker;
     88 
     89 
     90     /**
     91      * Creates a new pool entry.
     92      *
     93      * @param connOperator     the Connection Operator for this entry
     94      * @param route   the planned route for the connection,
     95      *                or <code>null</code>
     96      */
     97     protected AbstractPoolEntry(ClientConnectionOperator connOperator,
     98                                 HttpRoute route) {
     99         super();
    100         if (connOperator == null) {
    101             throw new IllegalArgumentException("Connection operator may not be null");
    102         }
    103         this.connOperator = connOperator;
    104         this.connection = connOperator.createConnection();
    105         this.route = route;
    106         this.tracker = null;
    107     }
    108 
    109     /**
    110      * Returns the state object associated with this pool entry.
    111      *
    112      * @return The state object
    113      */
    114     public Object getState() {
    115         return state;
    116     }
    117 
    118     /**
    119      * Assigns a state object to this pool entry.
    120      *
    121      * @param state The state object
    122      */
    123     public void setState(final Object state) {
    124         this.state = state;
    125     }
    126 
    127     /**
    128      * Opens the underlying connection.
    129      *
    130      * @param route         the route along which to open the connection
    131      * @param context       the context for opening the connection
    132      * @param params        the parameters for opening the connection
    133      *
    134      * @throws IOException  in case of a problem
    135      */
    136     public void open(HttpRoute route,
    137                      HttpContext context, HttpParams params)
    138         throws IOException {
    139 
    140         if (route == null) {
    141             throw new IllegalArgumentException
    142                 ("Route must not be null.");
    143         }
    144         //@@@ is context allowed to be null? depends on operator?
    145         if (params == null) {
    146             throw new IllegalArgumentException
    147                 ("Parameters must not be null.");
    148         }
    149         if ((this.tracker != null) && this.tracker.isConnected()) {
    150             throw new IllegalStateException("Connection already open.");
    151         }
    152 
    153         // - collect the arguments
    154         // - call the operator
    155         // - update the tracking data
    156         // In this order, we can be sure that only a successful
    157         // opening of the connection will be tracked.
    158 
    159         //@@@ verify route against planned route?
    160 
    161         this.tracker = new RouteTracker(route);
    162         final HttpHost proxy  = route.getProxyHost();
    163 
    164         connOperator.openConnection
    165             (this.connection,
    166              (proxy != null) ? proxy : route.getTargetHost(),
    167              route.getLocalAddress(),
    168              context, params);
    169 
    170         RouteTracker localTracker = tracker; // capture volatile
    171 
    172         // If this tracker was reset while connecting,
    173         // fail early.
    174         if (localTracker == null) {
    175             throw new IOException("Request aborted");
    176         }
    177 
    178         if (proxy == null) {
    179             localTracker.connectTarget(this.connection.isSecure());
    180         } else {
    181             localTracker.connectProxy(proxy, this.connection.isSecure());
    182         }
    183 
    184     } // open
    185 
    186 
    187     /**
    188      * Tracks tunnelling of the connection to the target.
    189      * The tunnel has to be established outside by sending a CONNECT
    190      * request to the (last) proxy.
    191      *
    192      * @param secure    <code>true</code> if the tunnel should be
    193      *                  considered secure, <code>false</code> otherwise
    194      * @param params    the parameters for tunnelling the connection
    195      *
    196      * @throws IOException  in case of a problem
    197      */
    198     public void tunnelTarget(boolean secure, HttpParams params)
    199         throws IOException {
    200 
    201         if (params == null) {
    202             throw new IllegalArgumentException
    203                 ("Parameters must not be null.");
    204         }
    205 
    206         //@@@ check for proxy in planned route?
    207         if ((this.tracker == null) || !this.tracker.isConnected()) {
    208             throw new IllegalStateException("Connection not open.");
    209         }
    210         if (this.tracker.isTunnelled()) {
    211             throw new IllegalStateException
    212                 ("Connection is already tunnelled.");
    213         }
    214 
    215         // LOG.debug?
    216 
    217         this.connection.update(null, tracker.getTargetHost(),
    218                                secure, params);
    219         this.tracker.tunnelTarget(secure);
    220 
    221     } // tunnelTarget
    222 
    223 
    224     /**
    225      * Tracks tunnelling of the connection to a chained proxy.
    226      * The tunnel has to be established outside by sending a CONNECT
    227      * request to the previous proxy.
    228      *
    229      * @param next      the proxy to which the tunnel was established.
    230      *  See {@link org.apache.http.conn.ManagedClientConnection#tunnelProxy
    231      *                                  ManagedClientConnection.tunnelProxy}
    232      *                  for details.
    233      * @param secure    <code>true</code> if the tunnel should be
    234      *                  considered secure, <code>false</code> otherwise
    235      * @param params    the parameters for tunnelling the connection
    236      *
    237      * @throws IOException  in case of a problem
    238      */
    239     public void tunnelProxy(HttpHost next, boolean secure, HttpParams params)
    240         throws IOException {
    241 
    242         if (next == null) {
    243             throw new IllegalArgumentException
    244                 ("Next proxy must not be null.");
    245         }
    246         if (params == null) {
    247             throw new IllegalArgumentException
    248                 ("Parameters must not be null.");
    249         }
    250 
    251         //@@@ check for proxy in planned route?
    252         if ((this.tracker == null) || !this.tracker.isConnected()) {
    253             throw new IllegalStateException("Connection not open.");
    254         }
    255 
    256         // LOG.debug?
    257 
    258         this.connection.update(null, next, secure, params);
    259         this.tracker.tunnelProxy(next, secure);
    260 
    261     } // tunnelProxy
    262 
    263 
    264     /**
    265      * Layers a protocol on top of an established tunnel.
    266      *
    267      * @param context   the context for layering
    268      * @param params    the parameters for layering
    269      *
    270      * @throws IOException  in case of a problem
    271      */
    272     public void layerProtocol(HttpContext context, HttpParams params)
    273         throws IOException {
    274 
    275         //@@@ is context allowed to be null? depends on operator?
    276         if (params == null) {
    277             throw new IllegalArgumentException
    278                 ("Parameters must not be null.");
    279         }
    280 
    281         if ((this.tracker == null) || !this.tracker.isConnected()) {
    282             throw new IllegalStateException("Connection not open.");
    283         }
    284         if (!this.tracker.isTunnelled()) {
    285             //@@@ allow this?
    286             throw new IllegalStateException
    287                 ("Protocol layering without a tunnel not supported.");
    288         }
    289         if (this.tracker.isLayered()) {
    290             throw new IllegalStateException
    291                 ("Multiple protocol layering not supported.");
    292         }
    293 
    294         // - collect the arguments
    295         // - call the operator
    296         // - update the tracking data
    297         // In this order, we can be sure that only a successful
    298         // layering on top of the connection will be tracked.
    299 
    300         final HttpHost target = tracker.getTargetHost();
    301 
    302         connOperator.updateSecureConnection(this.connection, target,
    303                                              context, params);
    304 
    305         this.tracker.layerProtocol(this.connection.isSecure());
    306 
    307     } // layerProtocol
    308 
    309 
    310     /**
    311      * Shuts down the entry.
    312      *
    313      * If {@link #open(HttpRoute, HttpContext, HttpParams)} is in progress,
    314      * this will cause that open to possibly throw an {@link IOException}.
    315      */
    316     protected void shutdownEntry() {
    317         tracker = null;
    318     }
    319 
    320 
    321 } // class AbstractPoolEntry
    322 
    323