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@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 */ AbstractPoolEntry(ClientConnectionOperator connOperator, HttpRoute route)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 */ getState()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 */ setState(final Object state)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 */ open(HttpRoute route, HttpContext context, HttpParams params)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 */ tunnelTarget(boolean secure, HttpParams params)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 */ tunnelProxy(HttpHost next, boolean secure, HttpParams params)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 */ layerProtocol(HttpContext context, HttpParams params)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 */ shutdownEntry()316 protected void shutdownEntry() { 317 tracker = null; 318 } 319 320 321 } // class AbstractPoolEntry 322 323