Home | History | Annotate | Download | only in routing
      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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    220     public final HttpHost getTargetHost() {
    221         return this.targetHost;
    222     }
    223 
    224 
    225     // non-JavaDoc, see interface RouteInfo
    226     public final InetAddress getLocalAddress() {
    227         return this.localAddress;
    228     }
    229 
    230 
    231     // non-JavaDoc, see interface RouteInfo
    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
    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
    267     public final HttpHost getProxyHost() {
    268         return (this.proxyChain == null) ? null : this.proxyChain[0];
    269     }
    270 
    271 
    272     // non-JavaDoc, see interface RouteInfo
    273     public final boolean isConnected() {
    274         return this.connected;
    275     }
    276 
    277 
    278     // non-JavaDoc, see interface RouteInfo
    279     public final TunnelType getTunnelType() {
    280         return this.tunnelled;
    281     }
    282 
    283 
    284     // non-JavaDoc, see interface RouteInfo
    285     public final boolean isTunnelled() {
    286         return (this.tunnelled == TunnelType.TUNNELLED);
    287     }
    288 
    289 
    290     // non-JavaDoc, see interface RouteInfo
    291     public final LayerType getLayerType() {
    292         return this.layered;
    293     }
    294 
    295 
    296     // non-JavaDoc, see interface RouteInfo
    297     public final boolean isLayered() {
    298         return (this.layered == LayerType.LAYERED);
    299     }
    300 
    301 
    302     // non-JavaDoc, see interface RouteInfo
    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      */
    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
    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
    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
    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
    439     public Object clone() throws CloneNotSupportedException {
    440         return super.clone();
    441     }
    442 
    443 
    444 } // class RouteTracker
    445