1 /* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/HttpRoute.java $ 3 * $Revision: 653041 $ 4 * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 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 * The route for a request. 40 * Instances of this class are unmodifiable and therefore suitable 41 * for use as lookup keys. 42 * 43 * @author <a href="mailto:rolandw at apache.org">Roland Weber</a> 44 * 45 * 46 * <!-- empty lines to avoid svn diff problems --> 47 * @version $Revision: 653041 $ 48 * 49 * @since 4.0 50 * 51 * @deprecated Please use {@link java.net.URL#openConnection} instead. 52 * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> 53 * for further details. 54 */ 55 @Deprecated 56 public final class HttpRoute implements RouteInfo, Cloneable { 57 58 /** The target host to connect to. */ 59 private final HttpHost targetHost; 60 61 /** 62 * The local address to connect from. 63 * <code>null</code> indicates that the default should be used. 64 */ 65 private final InetAddress localAddress; 66 67 /** The proxy servers, if any. */ 68 private final HttpHost[] proxyChain; 69 70 /** Whether the the route is tunnelled through the proxy. */ 71 private final TunnelType tunnelled; 72 73 /** Whether the route is layered. */ 74 private final LayerType layered; 75 76 /** Whether the route is (supposed to be) secure. */ 77 private final boolean secure; 78 79 80 /** 81 * Internal, fully-specified constructor. 82 * This constructor does <i>not</i> clone the proxy chain array, 83 * nor test it for <code>null</code> elements. This conversion and 84 * check is the responsibility of the public constructors. 85 * The order of arguments here is different from the similar public 86 * constructor, as required by Java. 87 * 88 * @param local the local address to route from, or 89 * <code>null</code> for the default 90 * @param target the host to which to route 91 * @param proxies the proxy chain to use, or 92 * <code>null</code> for a direct route 93 * @param secure <code>true</code> if the route is (to be) secure, 94 * <code>false</code> otherwise 95 * @param tunnelled the tunnel type of this route, or 96 * <code>null</code> for PLAIN 97 * @param layered the layering type of this route, or 98 * <code>null</code> for PLAIN 99 */ 100 private HttpRoute(InetAddress local, 101 HttpHost target, HttpHost[] proxies, 102 boolean secure, 103 TunnelType tunnelled, LayerType layered) { 104 if (target == null) { 105 throw new IllegalArgumentException 106 ("Target host may not be null."); 107 } 108 if ((tunnelled == TunnelType.TUNNELLED) && (proxies == null)) { 109 throw new IllegalArgumentException 110 ("Proxy required if tunnelled."); 111 } 112 113 // tunnelled is already checked above, that is in line with the default 114 if (tunnelled == null) 115 tunnelled = TunnelType.PLAIN; 116 if (layered == null) 117 layered = LayerType.PLAIN; 118 119 this.targetHost = target; 120 this.localAddress = local; 121 this.proxyChain = proxies; 122 this.secure = secure; 123 this.tunnelled = tunnelled; 124 this.layered = layered; 125 } 126 127 128 /** 129 * Creates a new route with all attributes specified explicitly. 130 * 131 * @param target the host to which to route 132 * @param local the local address to route from, or 133 * <code>null</code> for the default 134 * @param proxies the proxy chain to use, or 135 * <code>null</code> for a direct route 136 * @param secure <code>true</code> if the route is (to be) secure, 137 * <code>false</code> otherwise 138 * @param tunnelled the tunnel type of this route 139 * @param layered the layering type of this route 140 */ 141 public HttpRoute(HttpHost target, InetAddress local, HttpHost[] proxies, 142 boolean secure, TunnelType tunnelled, LayerType layered) { 143 this(local, target, toChain(proxies), secure, tunnelled, layered); 144 } 145 146 147 /** 148 * Creates a new route with at most one proxy. 149 * 150 * @param target the host to which to route 151 * @param local the local address to route from, or 152 * <code>null</code> for the default 153 * @param proxy the proxy to use, or 154 * <code>null</code> for a direct route 155 * @param secure <code>true</code> if the route is (to be) secure, 156 * <code>false</code> otherwise 157 * @param tunnelled <code>true</code> if the route is (to be) tunnelled 158 * via the proxy, 159 * <code>false</code> otherwise 160 * @param layered <code>true</code> if the route includes a 161 * layered protocol, 162 * <code>false</code> otherwise 163 */ 164 public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy, 165 boolean secure, TunnelType tunnelled, LayerType layered) { 166 this(local, target, toChain(proxy), secure, tunnelled, layered); 167 } 168 169 170 /** 171 * Creates a new direct route. 172 * That is a route without a proxy. 173 * 174 * @param target the host to which to route 175 * @param local the local address to route from, or 176 * <code>null</code> for the default 177 * @param secure <code>true</code> if the route is (to be) secure, 178 * <code>false</code> otherwise 179 */ 180 public HttpRoute(HttpHost target, InetAddress local, boolean secure) { 181 this(local, target, null, secure, TunnelType.PLAIN, LayerType.PLAIN); 182 } 183 184 185 /** 186 * Creates a new direct insecure route. 187 * 188 * @param target the host to which to route 189 */ 190 public HttpRoute(HttpHost target) { 191 this(null, target, null, false, TunnelType.PLAIN, LayerType.PLAIN); 192 } 193 194 195 /** 196 * Creates a new route through a proxy. 197 * When using this constructor, the <code>proxy</code> MUST be given. 198 * For convenience, it is assumed that a secure connection will be 199 * layered over a tunnel through the proxy. 200 * 201 * @param target the host to which to route 202 * @param local the local address to route from, or 203 * <code>null</code> for the default 204 * @param proxy the proxy to use 205 * @param secure <code>true</code> if the route is (to be) secure, 206 * <code>false</code> otherwise 207 */ 208 public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy, 209 boolean secure) { 210 this(local, target, toChain(proxy), secure, 211 secure ? TunnelType.TUNNELLED : TunnelType.PLAIN, 212 secure ? LayerType.LAYERED : LayerType.PLAIN); 213 if (proxy == null) { 214 throw new IllegalArgumentException 215 ("Proxy host may not be null."); 216 } 217 } 218 219 220 /** 221 * Helper to convert a proxy to a proxy chain. 222 * 223 * @param proxy the only proxy in the chain, or <code>null</code> 224 * 225 * @return a proxy chain array, or <code>null</code> 226 */ 227 private static HttpHost[] toChain(HttpHost proxy) { 228 if (proxy == null) 229 return null; 230 231 return new HttpHost[]{ proxy }; 232 } 233 234 235 /** 236 * Helper to duplicate and check a proxy chain. 237 * An empty proxy chain is converted to <code>null</code>. 238 * 239 * @param proxies the proxy chain to duplicate, or <code>null</code> 240 * 241 * @return a new proxy chain array, or <code>null</code> 242 */ 243 private static HttpHost[] toChain(HttpHost[] proxies) { 244 if ((proxies == null) || (proxies.length < 1)) 245 return null; 246 247 for (HttpHost proxy : proxies) { 248 if (proxy == null) 249 throw new IllegalArgumentException 250 ("Proxy chain may not contain null elements."); 251 } 252 253 // copy the proxy chain, the traditional way 254 HttpHost[] result = new HttpHost[proxies.length]; 255 System.arraycopy(proxies, 0, result, 0, proxies.length); 256 257 return result; 258 } 259 260 261 262 // non-JavaDoc, see interface RouteInfo 263 public final HttpHost getTargetHost() { 264 return this.targetHost; 265 } 266 267 268 // non-JavaDoc, see interface RouteInfo 269 public final InetAddress getLocalAddress() { 270 return this.localAddress; 271 } 272 273 274 // non-JavaDoc, see interface RouteInfo 275 public final int getHopCount() { 276 return (proxyChain == null) ? 1 : (proxyChain.length+1); 277 } 278 279 280 // non-JavaDoc, see interface RouteInfo 281 public final HttpHost getHopTarget(int hop) { 282 if (hop < 0) 283 throw new IllegalArgumentException 284 ("Hop index must not be negative: " + hop); 285 final int hopcount = getHopCount(); 286 if (hop >= hopcount) 287 throw new IllegalArgumentException 288 ("Hop index " + hop + 289 " exceeds route length " + hopcount); 290 291 HttpHost result = null; 292 if (hop < hopcount-1) 293 result = this.proxyChain[hop]; 294 else 295 result = this.targetHost; 296 297 return result; 298 } 299 300 301 // non-JavaDoc, see interface RouteInfo 302 public final HttpHost getProxyHost() { 303 return (this.proxyChain == null) ? null : this.proxyChain[0]; 304 } 305 306 307 // non-JavaDoc, see interface RouteInfo 308 public final TunnelType getTunnelType() { 309 return this.tunnelled; 310 } 311 312 313 // non-JavaDoc, see interface RouteInfo 314 public final boolean isTunnelled() { 315 return (this.tunnelled == TunnelType.TUNNELLED); 316 } 317 318 319 // non-JavaDoc, see interface RouteInfo 320 public final LayerType getLayerType() { 321 return this.layered; 322 } 323 324 325 // non-JavaDoc, see interface RouteInfo 326 public final boolean isLayered() { 327 return (this.layered == LayerType.LAYERED); 328 } 329 330 331 // non-JavaDoc, see interface RouteInfo 332 public final boolean isSecure() { 333 return this.secure; 334 } 335 336 337 /** 338 * Compares this route to another. 339 * 340 * @param o the object to compare with 341 * 342 * @return <code>true</code> if the argument is the same route, 343 * <code>false</code> 344 */ 345 @Override 346 public final boolean equals(Object o) { 347 if (o == this) 348 return true; 349 if (!(o instanceof HttpRoute)) 350 return false; 351 352 HttpRoute that = (HttpRoute) o; 353 boolean equal = this.targetHost.equals(that.targetHost); 354 equal &= 355 ( this.localAddress == that.localAddress) || 356 ((this.localAddress != null) && 357 this.localAddress.equals(that.localAddress)); 358 equal &= 359 ( this.proxyChain == that.proxyChain) || 360 ((this.proxyChain != null) && 361 (that.proxyChain != null) && 362 (this.proxyChain.length == that.proxyChain.length)); 363 // comparison of actual proxies follows below 364 equal &= 365 (this.secure == that.secure) && 366 (this.tunnelled == that.tunnelled) && 367 (this.layered == that.layered); 368 369 // chain length has been compared above, now check the proxies 370 if (equal && (this.proxyChain != null)) { 371 for (int i=0; equal && (i<this.proxyChain.length); i++) 372 equal = this.proxyChain[i].equals(that.proxyChain[i]); 373 } 374 375 return equal; 376 } 377 378 379 /** 380 * Generates a hash code for this route. 381 * 382 * @return the hash code 383 */ 384 @Override 385 public final int hashCode() { 386 387 int hc = this.targetHost.hashCode(); 388 389 if (this.localAddress != null) 390 hc ^= localAddress.hashCode(); 391 if (this.proxyChain != null) { 392 hc ^= proxyChain.length; 393 for (HttpHost aProxyChain : proxyChain) hc ^= aProxyChain.hashCode(); 394 } 395 396 if (this.secure) 397 hc ^= 0x11111111; 398 399 hc ^= this.tunnelled.hashCode(); 400 hc ^= this.layered.hashCode(); 401 402 return hc; 403 } 404 405 406 /** 407 * Obtains a description of this route. 408 * 409 * @return a human-readable representation of this route 410 */ 411 @Override 412 public final String toString() { 413 StringBuilder cab = new StringBuilder(50 + getHopCount()*30); 414 415 cab.append("HttpRoute["); 416 if (this.localAddress != null) { 417 cab.append(this.localAddress); 418 cab.append("->"); 419 } 420 cab.append('{'); 421 if (this.tunnelled == TunnelType.TUNNELLED) 422 cab.append('t'); 423 if (this.layered == LayerType.LAYERED) 424 cab.append('l'); 425 if (this.secure) 426 cab.append('s'); 427 cab.append("}->"); 428 if (this.proxyChain != null) { 429 for (HttpHost aProxyChain : this.proxyChain) { 430 cab.append(aProxyChain); 431 cab.append("->"); 432 } 433 } 434 cab.append(this.targetHost); 435 cab.append(']'); 436 437 return cab.toString(); 438 } 439 440 441 // default implementation of clone() is sufficient 442 @Override 443 public Object clone() throws CloneNotSupportedException { 444 return super.clone(); 445 } 446 447 448 } // class HttpRoute 449