• 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/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