1069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/*
2069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/routing/RouteTracker.java $
3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Revision: 620254 $
4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Date: 2008-02-10 02:18:48 -0800 (Sun, 10 Feb 2008) $
5069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
6069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
7069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one
8069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * or more contributor license agreements.  See the NOTICE file
9069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * distributed with this work for additional information
10069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * regarding copyright ownership.  The ASF licenses this file
11069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * to you under the Apache License, Version 2.0 (the
12069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "License"); you may not use this file except in compliance
13069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * with the License.  You may obtain a copy of the License at
14069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
15069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *   http://www.apache.org/licenses/LICENSE-2.0
16069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
17069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Unless required by applicable law or agreed to in writing,
18069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * software distributed under the License is distributed on an
19069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * KIND, either express or implied.  See the License for the
21069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * specific language governing permissions and limitations
22069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * under the License.
23069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
24069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
25069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This software consists of voluntary contributions made by many
26069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * individuals on behalf of the Apache Software Foundation.  For more
27069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * information on the Apache Software Foundation, please see
28069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <http://www.apache.org/>.
29069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
30069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
31069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
32069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpackage org.apache.http.conn.routing;
33069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
34069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.net.InetAddress;
35069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
36069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.HttpHost;
37069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
38069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/**
40069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Helps tracking the steps in establishing a route.
41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <!-- empty lines to avoid svn diff problems -->
46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @version $Revision: 620254 $
47069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
48069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @since 4.0
49069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
50069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic final class RouteTracker implements RouteInfo, Cloneable {
51069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
52069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The target host to connect to. */
53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private final HttpHost targetHost;
54069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The local address to connect from.
57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * <code>null</code> indicates that the default should be used.
58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private final InetAddress localAddress;
60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // the attributes above are fixed at construction time
62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // now follow attributes that indicate the established route
63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** Whether the first hop of the route is established. */
65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private boolean connected;
66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The proxy chain, if any. */
68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private HttpHost[] proxyChain;
69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** Whether the the route is tunnelled end-to-end through proxies. */
71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private TunnelType tunnelled;
72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** Whether the route is layered over a tunnel. */
74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private LayerType layered;
75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** Whether the route is secure. */
77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private boolean secure;
78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Creates a new route tracker.
82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The target and origin need to be specified at creation time.
83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param target    the host to which to route
85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param local     the local address to route from, or
86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  <code>null</code> for the default
87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public RouteTracker(HttpHost target, InetAddress local) {
89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (target == null) {
90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException("Target host may not be null.");
91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.targetHost   = target;
93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.localAddress = local;
94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.tunnelled    = TunnelType.PLAIN;
95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.layered      = LayerType.PLAIN;
96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Creates a new tracker for the given route.
101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Only target and origin are taken from the route,
102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * everything else remains to be tracked.
103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param route     the route to track
105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public RouteTracker(HttpRoute route) {
107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this(route.getTargetHost(), route.getLocalAddress());
108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Tracks connecting to the target.
113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param secure    <code>true</code> if the route is secure,
115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  <code>false</code> otherwise
116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final void connectTarget(boolean secure) {
118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.connected) {
119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException("Already connected.");
120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.connected = true;
122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.secure = secure;
123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Tracks connecting to the first proxy.
128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param proxy     the proxy connected to
130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param secure    <code>true</code> if the route is secure,
131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  <code>false</code> otherwise
132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final void connectProxy(HttpHost proxy, boolean secure) {
134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (proxy == null) {
135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException("Proxy host may not be null.");
136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.connected) {
138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException("Already connected.");
139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.connected  = true;
141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.proxyChain = new HttpHost[]{ proxy };
142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.secure     = secure;
143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Tracks tunnelling to the target.
148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param secure    <code>true</code> if the route is secure,
150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  <code>false</code> otherwise
151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final void tunnelTarget(boolean secure) {
153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (!this.connected) {
154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException("No tunnel unless connected.");
155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.proxyChain == null) {
157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException("No tunnel without proxy.");
158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.tunnelled = TunnelType.TUNNELLED;
160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.secure    = secure;
161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Tracks tunnelling to a proxy in a proxy chain.
166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * This will extend the tracked proxy chain, but it does not mark
167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * the route as tunnelled. Only end-to-end tunnels are considered there.
168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param proxy     the proxy tunnelled to
170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param secure    <code>true</code> if the route is secure,
171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  <code>false</code> otherwise
172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final void tunnelProxy(HttpHost proxy, boolean secure) {
174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (proxy == null) {
175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException("Proxy host may not be null.");
176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (!this.connected) {
178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException("No tunnel unless connected.");
179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.proxyChain == null) {
181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException("No proxy tunnel without proxy.");
182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // prepare an extended proxy chain
185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        HttpHost[] proxies = new HttpHost[this.proxyChain.length+1];
186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        System.arraycopy(this.proxyChain, 0,
187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                         proxies, 0, this.proxyChain.length);
188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        proxies[proxies.length-1] = proxy;
189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.proxyChain = proxies;
191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.secure     = secure;
192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Tracks layering a protocol.
197069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
198069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param secure    <code>true</code> if the route is secure,
199069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  <code>false</code> otherwise
200069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
201069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final void layerProtocol(boolean secure) {
202069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // it is possible to layer a protocol over a direct connection,
203069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // although this case is probably not considered elsewhere
204069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (!this.connected) {
205069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException
206069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("No layered protocol unless connected.");
207069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
208069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.layered = LayerType.LAYERED;
209069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.secure  = secure;
210069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
211069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
212069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
213069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
214069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
215069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final HttpHost getTargetHost() {
216069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return this.targetHost;
217069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
218069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
219069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
220069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
221069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final InetAddress getLocalAddress() {
222069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return this.localAddress;
223069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
224069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
225069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
226069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
227069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final int getHopCount() {
228069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        int hops = 0;
229069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.connected) {
230069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (proxyChain == null)
231069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                hops = 1;
232069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            else
233069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                hops = proxyChain.length + 1;
234069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
235069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return hops;
236069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
237069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
238069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
239069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
240069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final HttpHost getHopTarget(int hop) {
241069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (hop < 0)
242069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
243069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Hop index must not be negative: " + hop);
244069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        final int hopcount = getHopCount();
245069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (hop >= hopcount) {
246069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
247069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Hop index " + hop +
248069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                 " exceeds tracked route length " + hopcount +".");
249069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
250069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
251069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        HttpHost result = null;
252069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (hop < hopcount-1)
253069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            result = this.proxyChain[hop];
254069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        else
255069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            result = this.targetHost;
256069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
257069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return result;
258069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
259069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
260069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
261069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
262069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final HttpHost getProxyHost() {
263069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return (this.proxyChain == null) ? null : this.proxyChain[0];
264069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
265069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
266069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
267069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
268069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final boolean isConnected() {
269069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return this.connected;
270069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
271069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
272069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
273069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
274069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final TunnelType getTunnelType() {
275069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return this.tunnelled;
276069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
277069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
278069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
279069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
280069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final boolean isTunnelled() {
281069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return (this.tunnelled == TunnelType.TUNNELLED);
282069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
283069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
284069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
285069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
286069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final LayerType getLayerType() {
287069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return this.layered;
288069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
289069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
290069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
291069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
292069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final boolean isLayered() {
293069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return (this.layered == LayerType.LAYERED);
294069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
295069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
296069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
297069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-JavaDoc, see interface RouteInfo
298069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final boolean isSecure() {
299069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return this.secure;
300069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
301069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
302069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
303069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
304069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Obtains the tracked route.
305069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * If a route has been tracked, it is {@link #isConnected connected}.
306069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * If not connected, nothing has been tracked so far.
307069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
308069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the tracked route, or
309069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          <code>null</code> if nothing has been tracked so far
310069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
311069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final HttpRoute toRoute() {
312069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return !this.connected ?
313069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            null : new HttpRoute(this.targetHost, this.localAddress,
314069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                                 this.proxyChain, this.secure,
315069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                                 this.tunnelled, this.layered);
316069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
317069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
318069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
319069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
320069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Compares this tracked route to another.
321069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
322069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param o         the object to compare with
323069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
324069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  <code>true</code> if the argument is the same tracked route,
325069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          <code>false</code>
326069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
327069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    @Override
328069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final boolean equals(Object o) {
329069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (o == this)
330069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return true;
331069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (!(o instanceof RouteTracker))
332069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return false;
333069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
334069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        RouteTracker that = (RouteTracker) o;
335069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean equal = this.targetHost.equals(that.targetHost);
336069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        equal &=
337069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            ( this.localAddress == that.localAddress) ||
338069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            ((this.localAddress != null) &&
339069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project              this.localAddress.equals(that.localAddress));
340069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        equal &=
341069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            ( this.proxyChain        == that.proxyChain) ||
342069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            ((this.proxyChain        != null) &&
343069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project             (that.proxyChain        != null) &&
344069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project             (this.proxyChain.length == that.proxyChain.length));
345069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // comparison of actual proxies follows below
346069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        equal &=
347069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            (this.connected == that.connected) &&
348069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            (this.secure    == that.secure) &&
349069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            (this.tunnelled == that.tunnelled) &&
350069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            (this.layered   == that.layered);
351069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
352069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // chain length has been compared above, now check the proxies
353069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (equal && (this.proxyChain != null)) {
354069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            for (int i=0; equal && (i<this.proxyChain.length); i++)
355069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                equal = this.proxyChain[i].equals(that.proxyChain[i]);
356069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
357069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
358069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return equal;
359069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
360069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
361069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
362069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
363069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Generates a hash code for this tracked route.
364069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Route trackers are modifiable and should therefore not be used
365069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * as lookup keys. Use {@link #toRoute toRoute} to obtain an
366069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * unmodifiable representation of the tracked route.
367069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
368069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the hash code
369069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
370069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    @Override
371069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final int hashCode() {
372069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
373069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        int hc = this.targetHost.hashCode();
374069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
375069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.localAddress != null)
376069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            hc ^= localAddress.hashCode();
377069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.proxyChain != null) {
378069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            hc ^= proxyChain.length;
379069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            for (int i=0; i<proxyChain.length; i++)
380069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                hc ^= proxyChain[i].hashCode();
381069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
382069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
383069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.connected)
384069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            hc ^= 0x11111111;
385069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.secure)
386069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            hc ^= 0x22222222;
387069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
388069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        hc ^= this.tunnelled.hashCode();
389069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        hc ^= this.layered.hashCode();
390069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
391069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return hc;
392069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
393069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
394069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
395069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
396069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Obtains a description of the tracked route.
397069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
398069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  a human-readable representation of the tracked route
399069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
400069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    @Override
401069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final String toString() {
402069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
403069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
404069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        cab.append("RouteTracker[");
405069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.localAddress != null) {
406069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            cab.append(this.localAddress);
407069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            cab.append("->");
408069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
409069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        cab.append('{');
410069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.connected)
411069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            cab.append('c');
412069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.tunnelled == TunnelType.TUNNELLED)
413069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            cab.append('t');
414069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.layered == LayerType.LAYERED)
415069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            cab.append('l');
416069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.secure)
417069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            cab.append('s');
418069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        cab.append("}->");
419069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.proxyChain != null) {
420069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            for (int i=0; i<this.proxyChain.length; i++) {
421069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                cab.append(this.proxyChain[i]);
422069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                cab.append("->");
423069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
424069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
425069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        cab.append(this.targetHost);
426069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        cab.append(']');
427069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
428069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return cab.toString();
429069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
430069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
431069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
432069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // default implementation of clone() is sufficient
433069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    @Override
434069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public Object clone() throws CloneNotSupportedException {
435069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return super.clone();
436069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
437069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
438069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
439069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project} // class RouteTracker
440