From 64dac236b7d012798f3367202ea7b267da27d9e4 Mon Sep 17 00:00:00 2001 From: Roland Weber Date: Thu, 8 Feb 2007 20:15:48 +0000 Subject: [PATCH] unmodifiable route representation, excluding conn auth state git-svn-id: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpclient/trunk@505024 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/http/conn/HttpRoute.java | 321 ++++++++++++++++++ .../org/apache/http/conn/RouteTracker.java | 103 +++++- 2 files changed, 418 insertions(+), 6 deletions(-) create mode 100644 src/java/org/apache/http/conn/HttpRoute.java diff --git a/src/java/org/apache/http/conn/HttpRoute.java b/src/java/org/apache/http/conn/HttpRoute.java new file mode 100644 index 000000000..0eb6d352f --- /dev/null +++ b/src/java/org/apache/http/conn/HttpRoute.java @@ -0,0 +1,321 @@ +/* + * $HeadURL$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.conn; + +import java.net.InetAddress; + +import org.apache.http.HttpHost; +import org.apache.http.util.CharArrayBuffer; + + +/** + * The route for a request. + * Instances of this class are unmodifiable and therefore suitable + * for use as lookup keys. + * + * @author Roland Weber + * + * + * + * @version $Revision$ + * + * @since 4.0 + */ +public final class HttpRoute implements Cloneable { + + /** The target host to connect to. */ + private final HttpHost targetHost; + + /** + * The local address to connect from. + * null indicates that the default should be used. + */ + private final InetAddress localAddress; + + /** The proxy server, if any. */ + private final HttpHost proxyHost; + + /** Whether the the route is tunnelled through the proxy. */ + private final boolean tunnelled; + + /** Whether the route is layered. */ + private final boolean layered; + + /** Whether the route is (supposed to be) secure. */ + private final boolean secure; + + + /** + * Creates a new route with all attributes specified explicitly. + * + * @param target the host to which to route + * @param local the local address to route from, or + * null for the default + * @param proxy the proxy to use, or + * null for a direct route + * @param secure true if the route is (to be) secure, + * false otherwise + * @param tunnelled true if the route is (to be) tunnelled + * via the proxy, + * false otherwise + * @param layered true if the route includes a + * layered protocol, + * false otherwise + */ + public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy, + boolean secure, boolean tunnelled, boolean layered) { + if (target == null) { + throw new IllegalArgumentException + ("Target host may not be null."); + } + if (tunnelled && (proxy == null)) { + throw new IllegalArgumentException + ("Proxy host may not be null if tunnelled."); + } + + this.targetHost = target; + this.localAddress = local; + this.proxyHost = proxy; + this.secure = secure; + this.tunnelled = tunnelled; + this.layered = layered; + } + + + /** + * Creates a new direct route. + * That is a route without a proxy. + * + * @param target the host to which to route + * @param local the local address to route from, or + * null for the default + * @param secure true if the route is (to be) secure, + * false otherwise + */ + public HttpRoute(HttpHost target, InetAddress local, boolean secure) { + this(target, local, null, secure, false, false); + } + + + /** + * Creates a new route through a proxy. + * When using this constructor, the proxy MUST be given. + * For convenience, it is assumed that a secure connection will be + * layered over a tunnel through the proxy. + * + * @param target the host to which to route + * @param local the local address to route from, or + * null for the default + * @param proxy the proxy to use + * @param secure true if the route is (to be) secure, + * false otherwise + */ + public HttpRoute(HttpHost target, InetAddress local, HttpHost proxy, + boolean secure) { + this(target, local, proxy, secure, secure, secure); + if (proxy == null) { + throw new IllegalArgumentException + ("Proxy host may not be null."); + } + } + + + /** + * Obtains the target host. + * + * @return the target host + */ + public final HttpHost getTargetHost() { + return this.targetHost; + } + + + /** + * Obtains the local address to connect from. + * + * @return the local address, + * or null + */ + public final InetAddress getLocalAddress() { + return this.localAddress; + } + + + /** + * Obtains the proxy host. + * + * @return the proxy host, or + * null if this route is direct + */ + public final HttpHost getProxyHost() { + return this.proxyHost; + } + + + /** + * Checks whether this route is tunnelled through a proxy. + * + * @return true if tunnelled, + * false otherwise + */ + public final boolean isTunnelled() { + return this.tunnelled; + } + + + /** + * Checks whether this route includes a layered protocol. + * + * @return true if layered, + * false otherwise + */ + public final boolean isLayered() { + return this.layered; + } + + + /** + * Checks whether this route is secure. + * + * @return true if secure, + * false otherwise + */ + public final boolean isSecure() { + return this.secure; + } + + + /** + * Converts to the {@link HostConfiguration traditional} interface. + * + * @return a host configuration matching this route as good as possible + * + * @deprecated No replacement. + * This class will replace {@link HostConfiguration} + * where routes need to be represented. No conversion necessary. + */ + public final HostConfiguration toHostConfig() { + return new HostConfiguration + (this.targetHost, this.proxyHost, this.localAddress); + } + + + /** + * Compares this route to another. + * + * @param o the object to compare with + * + * @return true if the argument is the same route, + * false + */ + public final boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof HttpRoute)) + return false; + + HttpRoute that = (HttpRoute) o; + boolean equal = this.targetHost.equals(that.targetHost); + equal &= + ( this.localAddress == that.localAddress) | + ((this.localAddress != null) && + this.localAddress.equals(that.localAddress)); + equal &= + ( this.proxyHost == that.proxyHost) | + ((this.proxyHost != null) && + this.proxyHost.equals(that.proxyHost)); + equal &= + (this.secure == that.secure) && + (this.tunnelled == that.tunnelled) && + (this.layered == that.layered); + + return equal; + } + + + /** + * Generates a hash code for this route. + * + * @return the hash code + */ + public final int hashCode() { + + int hc = this.targetHost.hashCode(); + + if (this.localAddress != null) + hc ^= localAddress.hashCode(); + if (this.proxyHost != null) + hc ^= proxyHost.hashCode(); + + if (this.secure) + hc ^= 0x11111111; + if (this.tunnelled) + hc ^= 0x22222222; + if (this.layered) + hc ^= 0x44444444; + + return hc; + } + + + /** + * Obtains a description of this route. + * + * @return a human-readable representation of this route + */ + public final String toString() { + CharArrayBuffer cab = new CharArrayBuffer(80); + + cab.append("HttpRoute["); + if (this.localAddress != null) { + cab.append(this.localAddress); + cab.append("->"); + } + cab.append('{'); + if (this.tunnelled) + cab.append('t'); + if (this.layered) + cab.append('l'); + if (this.secure) + cab.append('s'); + cab.append("}->"); + if (this.proxyHost != null) { + cab.append(this.proxyHost); + cab.append("->"); + } + cab.append(this.targetHost); + cab.append(']'); + + return cab.toString(); + } + +} // class HttpRoute diff --git a/src/java/org/apache/http/conn/RouteTracker.java b/src/java/org/apache/http/conn/RouteTracker.java index 649d2c3f0..2c9ae8f09 100644 --- a/src/java/org/apache/http/conn/RouteTracker.java +++ b/src/java/org/apache/http/conn/RouteTracker.java @@ -34,7 +34,6 @@ package org.apache.http.conn; import java.net.InetAddress; import org.apache.http.HttpHost; -//import org.apache.http.util.LangUtils; import org.apache.http.util.CharArrayBuffer; @@ -45,7 +44,7 @@ import org.apache.http.util.CharArrayBuffer; * * * - * @version $Revision$ $Date$ + * @version $Revision$ * * @since 4.0 */ @@ -96,6 +95,18 @@ public final class RouteTracker implements Cloneable { } + /** + * Creates a new tracker for the given route. + * Only target and origin are taken from the route, + * everything else remains to be tracked. + * + * @param route the route to track + */ + public RouteTracker(HttpRoute route) { + this(route.getTargetHost(), route.getLocalAddress()); + } + + /** * Tracks connecting to the target. * @@ -229,6 +240,22 @@ public final class RouteTracker implements Cloneable { } + /** + * Obtains the tracked route. + * If a route has been tracked, it is {@link #isConnected connected}. + * If not connected, nothing has been tracked so far. + * + * @return the tracked route, or + * null if nothing has been tracked so far + */ + public final HttpRoute toRoute() { + return !this.connected ? + null : new HttpRoute(this.targetHost, this.localAddress, + this.proxyHost, this.secure, + this.tunnelled, this.layered); + } + + /** * Obtains the tracked route. *
Note: @@ -237,21 +264,85 @@ public final class RouteTracker implements Cloneable { * In particular, it can not represent intermediate steps in establishing * a route. * + * @deprecated use {@link #toRoute toRoute} instead. Kept temporarily + * until {@link HttpRoute} takes over from {@link HostConfiguration}. + * * @return a representation of the route tracked so far */ - public final HostConfiguration toRoute() { + public final HostConfiguration toHostConfig() { return new HostConfiguration (this.targetHost, this.proxyHost, this.localAddress); } - //@@@ ? equals + hashCode + /** + * Compares this tracked route to another. + * + * @param o the object to compare with + * + * @return true if the argument is the same tracked route, + * false + */ + public final boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof RouteTracker)) + return false; + + RouteTracker that = (RouteTracker) o; + boolean equal = this.targetHost.equals(that.targetHost); + equal &= + ( this.localAddress == that.localAddress) | + ((this.localAddress != null) && + this.localAddress.equals(that.localAddress)); + equal &= + ( this.proxyHost == that.proxyHost) | + ((this.proxyHost != null) && + this.proxyHost.equals(that.proxyHost)); + equal &= + (this.connected == that.connected) && + (this.secure == that.secure) && + (this.tunnelled == that.tunnelled) && + (this.layered == that.layered); + + return equal; + } /** - * Obtains a description of this route. + * Generates a hash code for this tracked route. + * Route trackers are modifiable and should therefore not be used + * as lookup keys. Use {@link #toRoute toRoute} to obtain an + * unmodifiable representation of the tracked route. * - * @return a human-readable representation of this route + * @return the hash code + */ + public final int hashCode() { + + int hc = this.targetHost.hashCode(); + + if (this.localAddress != null) + hc ^= localAddress.hashCode(); + if (this.proxyHost != null) + hc ^= proxyHost.hashCode(); + + if (this.connected) + hc ^= 0x11111111; + if (this.secure) + hc ^= 0x22222222; + if (this.tunnelled) + hc ^= 0x44444444; + if (this.layered) + hc ^= 0x88888888; + + return hc; + } + + + /** + * Obtains a description of the tracked route. + * + * @return a human-readable representation of the tracked route */ public final String toString() { CharArrayBuffer cab = new CharArrayBuffer(80);