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