• 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/conn/routing/RouteTracker.java $
3  * $Revision: 620254 $
4  * $Date: 2008-02-10 02:18:48 -0800 (Sun, 10 Feb 2008) $
5  *
6  * ====================================================================
7  * Licensed to the Apache Software Foundation (ASF) under one
8  * or more contributor license agreements.  See the NOTICE file
9  * distributed with this work for additional information
10  * regarding copyright ownership.  The ASF licenses this file
11  * to you under the Apache License, Version 2.0 (the
12  * "License"); you may not use this file except in compliance
13  * with 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,
18  * software distributed under the License is distributed on an
19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20  * KIND, either express or implied.  See the License for the
21  * specific language governing permissions and limitations
22  * under the License.
23  * ====================================================================
24  *
25  * This software consists of voluntary contributions made by many
26  * individuals on behalf of the Apache Software Foundation.  For more
27  * information on the Apache Software Foundation, please see
28  * <http://www.apache.org/>.
29  *
30  */
31 
32 package org.apache.http.conn.routing;
33 
34 import java.net.InetAddress;
35 
36 import org.apache.http.HttpHost;
37 
38 
39 /**
40  * Helps tracking the steps in establishing a route.
41  *
42  * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
43  *
44  *
45  * <!-- empty lines to avoid svn diff problems -->
46  * @version $Revision: 620254 $
47  *
48  * @since 4.0
49  *
50  * @deprecated Please use {@link java.net.URL#openConnection} instead.
51  *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
52  *     for further details.
53  */
54 @Deprecated
55 public final class RouteTracker implements RouteInfo, Cloneable {
56 
57     /** The target host to connect to. */
58     private final HttpHost targetHost;
59 
60     /**
61      * The local address to connect from.
62      * <code>null</code> indicates that the default should be used.
63      */
64     private final InetAddress localAddress;
65 
66     // the attributes above are fixed at construction time
67     // now follow attributes that indicate the established route
68 
69     /** Whether the first hop of the route is established. */
70     private boolean connected;
71 
72     /** The proxy chain, if any. */
73     private HttpHost[] proxyChain;
74 
75     /** Whether the the route is tunnelled end-to-end through proxies. */
76     private TunnelType tunnelled;
77 
78     /** Whether the route is layered over a tunnel. */
79     private LayerType layered;
80 
81     /** Whether the route is secure. */
82     private boolean secure;
83 
84 
85     /**
86      * Creates a new route tracker.
87      * The target and origin need to be specified at creation time.
88      *
89      * @param target    the host to which to route
90      * @param local     the local address to route from, or
91      *                  <code>null</code> for the default
92      */
RouteTracker(HttpHost target, InetAddress local)93     public RouteTracker(HttpHost target, InetAddress local) {
94         if (target == null) {
95             throw new IllegalArgumentException("Target host may not be null.");
96         }
97         this.targetHost   = target;
98         this.localAddress = local;
99         this.tunnelled    = TunnelType.PLAIN;
100         this.layered      = LayerType.PLAIN;
101     }
102 
103 
104     /**
105      * Creates a new tracker for the given route.
106      * Only target and origin are taken from the route,
107      * everything else remains to be tracked.
108      *
109      * @param route     the route to track
110      */
RouteTracker(HttpRoute route)111     public RouteTracker(HttpRoute route) {
112         this(route.getTargetHost(), route.getLocalAddress());
113     }
114 
115 
116     /**
117      * Tracks connecting to the target.
118      *
119      * @param secure    <code>true</code> if the route is secure,
120      *                  <code>false</code> otherwise
121      */
connectTarget(boolean secure)122     public final void connectTarget(boolean secure) {
123         if (this.connected) {
124             throw new IllegalStateException("Already connected.");
125         }
126         this.connected = true;
127         this.secure = secure;
128     }
129 
130 
131     /**
132      * Tracks connecting to the first proxy.
133      *
134      * @param proxy     the proxy connected to
135      * @param secure    <code>true</code> if the route is secure,
136      *                  <code>false</code> otherwise
137      */
connectProxy(HttpHost proxy, boolean secure)138     public final void connectProxy(HttpHost proxy, boolean secure) {
139         if (proxy == null) {
140             throw new IllegalArgumentException("Proxy host may not be null.");
141         }
142         if (this.connected) {
143             throw new IllegalStateException("Already connected.");
144         }
145         this.connected  = true;
146         this.proxyChain = new HttpHost[]{ proxy };
147         this.secure     = secure;
148     }
149 
150 
151     /**
152      * Tracks tunnelling to the target.
153      *
154      * @param secure    <code>true</code> if the route is secure,
155      *                  <code>false</code> otherwise
156      */
tunnelTarget(boolean secure)157     public final void tunnelTarget(boolean secure) {
158         if (!this.connected) {
159             throw new IllegalStateException("No tunnel unless connected.");
160         }
161         if (this.proxyChain == null) {
162             throw new IllegalStateException("No tunnel without proxy.");
163         }
164         this.tunnelled = TunnelType.TUNNELLED;
165         this.secure    = secure;
166     }
167 
168 
169     /**
170      * Tracks tunnelling to a proxy in a proxy chain.
171      * This will extend the tracked proxy chain, but it does not mark
172      * the route as tunnelled. Only end-to-end tunnels are considered there.
173      *
174      * @param proxy     the proxy tunnelled to
175      * @param secure    <code>true</code> if the route is secure,
176      *                  <code>false</code> otherwise
177      */
tunnelProxy(HttpHost proxy, boolean secure)178     public final void tunnelProxy(HttpHost proxy, boolean secure) {
179         if (proxy == null) {
180             throw new IllegalArgumentException("Proxy host may not be null.");
181         }
182         if (!this.connected) {
183             throw new IllegalStateException("No tunnel unless connected.");
184         }
185         if (this.proxyChain == null) {
186             throw new IllegalStateException("No proxy tunnel without proxy.");
187         }
188 
189         // prepare an extended proxy chain
190         HttpHost[] proxies = new HttpHost[this.proxyChain.length+1];
191         System.arraycopy(this.proxyChain, 0,
192                          proxies, 0, this.proxyChain.length);
193         proxies[proxies.length-1] = proxy;
194 
195         this.proxyChain = proxies;
196         this.secure     = secure;
197     }
198 
199 
200     /**
201      * Tracks layering a protocol.
202      *
203      * @param secure    <code>true</code> if the route is secure,
204      *                  <code>false</code> otherwise
205      */
layerProtocol(boolean secure)206     public final void layerProtocol(boolean secure) {
207         // it is possible to layer a protocol over a direct connection,
208         // although this case is probably not considered elsewhere
209         if (!this.connected) {
210             throw new IllegalStateException
211                 ("No layered protocol unless connected.");
212         }
213         this.layered = LayerType.LAYERED;
214         this.secure  = secure;
215     }
216 
217 
218 
219     // non-JavaDoc, see interface RouteInfo
getTargetHost()220     public final HttpHost getTargetHost() {
221         return this.targetHost;
222     }
223 
224 
225     // non-JavaDoc, see interface RouteInfo
getLocalAddress()226     public final InetAddress getLocalAddress() {
227         return this.localAddress;
228     }
229 
230 
231     // non-JavaDoc, see interface RouteInfo
getHopCount()232     public final int getHopCount() {
233         int hops = 0;
234         if (this.connected) {
235             if (proxyChain == null)
236                 hops = 1;
237             else
238                 hops = proxyChain.length + 1;
239         }
240         return hops;
241     }
242 
243 
244     // non-JavaDoc, see interface RouteInfo
getHopTarget(int hop)245     public final HttpHost getHopTarget(int hop) {
246         if (hop < 0)
247             throw new IllegalArgumentException
248                 ("Hop index must not be negative: " + hop);
249         final int hopcount = getHopCount();
250         if (hop >= hopcount) {
251             throw new IllegalArgumentException
252                 ("Hop index " + hop +
253                  " exceeds tracked route length " + hopcount +".");
254         }
255 
256         HttpHost result = null;
257         if (hop < hopcount-1)
258             result = this.proxyChain[hop];
259         else
260             result = this.targetHost;
261 
262         return result;
263     }
264 
265 
266     // non-JavaDoc, see interface RouteInfo
getProxyHost()267     public final HttpHost getProxyHost() {
268         return (this.proxyChain == null) ? null : this.proxyChain[0];
269     }
270 
271 
272     // non-JavaDoc, see interface RouteInfo
isConnected()273     public final boolean isConnected() {
274         return this.connected;
275     }
276 
277 
278     // non-JavaDoc, see interface RouteInfo
getTunnelType()279     public final TunnelType getTunnelType() {
280         return this.tunnelled;
281     }
282 
283 
284     // non-JavaDoc, see interface RouteInfo
isTunnelled()285     public final boolean isTunnelled() {
286         return (this.tunnelled == TunnelType.TUNNELLED);
287     }
288 
289 
290     // non-JavaDoc, see interface RouteInfo
getLayerType()291     public final LayerType getLayerType() {
292         return this.layered;
293     }
294 
295 
296     // non-JavaDoc, see interface RouteInfo
isLayered()297     public final boolean isLayered() {
298         return (this.layered == LayerType.LAYERED);
299     }
300 
301 
302     // non-JavaDoc, see interface RouteInfo
isSecure()303     public final boolean isSecure() {
304         return this.secure;
305     }
306 
307 
308     /**
309      * Obtains the tracked route.
310      * If a route has been tracked, it is {@link #isConnected connected}.
311      * If not connected, nothing has been tracked so far.
312      *
313      * @return  the tracked route, or
314      *          <code>null</code> if nothing has been tracked so far
315      */
toRoute()316     public final HttpRoute toRoute() {
317         return !this.connected ?
318             null : new HttpRoute(this.targetHost, this.localAddress,
319                                  this.proxyChain, this.secure,
320                                  this.tunnelled, this.layered);
321     }
322 
323 
324     /**
325      * Compares this tracked route to another.
326      *
327      * @param o         the object to compare with
328      *
329      * @return  <code>true</code> if the argument is the same tracked route,
330      *          <code>false</code>
331      */
332     @Override
equals(Object o)333     public final boolean equals(Object o) {
334         if (o == this)
335             return true;
336         if (!(o instanceof RouteTracker))
337             return false;
338 
339         RouteTracker that = (RouteTracker) o;
340         boolean equal = this.targetHost.equals(that.targetHost);
341         equal &=
342             ( this.localAddress == that.localAddress) ||
343             ((this.localAddress != null) &&
344               this.localAddress.equals(that.localAddress));
345         equal &=
346             ( this.proxyChain        == that.proxyChain) ||
347             ((this.proxyChain        != null) &&
348              (that.proxyChain        != null) &&
349              (this.proxyChain.length == that.proxyChain.length));
350         // comparison of actual proxies follows below
351         equal &=
352             (this.connected == that.connected) &&
353             (this.secure    == that.secure) &&
354             (this.tunnelled == that.tunnelled) &&
355             (this.layered   == that.layered);
356 
357         // chain length has been compared above, now check the proxies
358         if (equal && (this.proxyChain != null)) {
359             for (int i=0; equal && (i<this.proxyChain.length); i++)
360                 equal = this.proxyChain[i].equals(that.proxyChain[i]);
361         }
362 
363         return equal;
364     }
365 
366 
367     /**
368      * Generates a hash code for this tracked route.
369      * Route trackers are modifiable and should therefore not be used
370      * as lookup keys. Use {@link #toRoute toRoute} to obtain an
371      * unmodifiable representation of the tracked route.
372      *
373      * @return  the hash code
374      */
375     @Override
hashCode()376     public final int hashCode() {
377 
378         int hc = this.targetHost.hashCode();
379 
380         if (this.localAddress != null)
381             hc ^= localAddress.hashCode();
382         if (this.proxyChain != null) {
383             hc ^= proxyChain.length;
384             for (int i=0; i<proxyChain.length; i++)
385                 hc ^= proxyChain[i].hashCode();
386         }
387 
388         if (this.connected)
389             hc ^= 0x11111111;
390         if (this.secure)
391             hc ^= 0x22222222;
392 
393         hc ^= this.tunnelled.hashCode();
394         hc ^= this.layered.hashCode();
395 
396         return hc;
397     }
398 
399 
400     /**
401      * Obtains a description of the tracked route.
402      *
403      * @return  a human-readable representation of the tracked route
404      */
405     @Override
toString()406     public final String toString() {
407         StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
408 
409         cab.append("RouteTracker[");
410         if (this.localAddress != null) {
411             cab.append(this.localAddress);
412             cab.append("->");
413         }
414         cab.append('{');
415         if (this.connected)
416             cab.append('c');
417         if (this.tunnelled == TunnelType.TUNNELLED)
418             cab.append('t');
419         if (this.layered == LayerType.LAYERED)
420             cab.append('l');
421         if (this.secure)
422             cab.append('s');
423         cab.append("}->");
424         if (this.proxyChain != null) {
425             for (int i=0; i<this.proxyChain.length; i++) {
426                 cab.append(this.proxyChain[i]);
427                 cab.append("->");
428             }
429         }
430         cab.append(this.targetHost);
431         cab.append(']');
432 
433         return cab.toString();
434     }
435 
436 
437     // default implementation of clone() is sufficient
438     @Override
clone()439     public Object clone() throws CloneNotSupportedException {
440         return super.clone();
441     }
442 
443 
444 } // class RouteTracker
445