/sdks/httpcomponents-client-4.1.2-src/httpcomponents-client-4.1.2/httpclient/src/main/java/org/apache/http/conn/routing/RouteTracker.java

https://github.com/steveclark7/Test1 · Java · 376 lines · 204 code · 46 blank · 126 comment · 45 complexity · 321b60fc357c627dcd33aba87d7f758e MD5 · raw file

  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. * ====================================================================
  20. *
  21. * This software consists of voluntary contributions made by many
  22. * individuals on behalf of the Apache Software Foundation. For more
  23. * information on the Apache Software Foundation, please see
  24. * <http://www.apache.org/>.
  25. *
  26. */
  27. package org.apache.http.conn.routing;
  28. import java.net.InetAddress;
  29. import org.apache.http.annotation.NotThreadSafe;
  30. import org.apache.http.util.LangUtils;
  31. import org.apache.http.HttpHost;
  32. /**
  33. * Helps tracking the steps in establishing a route.
  34. *
  35. * @since 4.0
  36. */
  37. @NotThreadSafe
  38. public final class RouteTracker implements RouteInfo, Cloneable {
  39. /** The target host to connect to. */
  40. private final HttpHost targetHost;
  41. /**
  42. * The local address to connect from.
  43. * <code>null</code> indicates that the default should be used.
  44. */
  45. private final InetAddress localAddress;
  46. // the attributes above are fixed at construction time
  47. // now follow attributes that indicate the established route
  48. /** Whether the first hop of the route is established. */
  49. private boolean connected;
  50. /** The proxy chain, if any. */
  51. private HttpHost[] proxyChain;
  52. /** Whether the the route is tunnelled end-to-end through proxies. */
  53. private TunnelType tunnelled;
  54. /** Whether the route is layered over a tunnel. */
  55. private LayerType layered;
  56. /** Whether the route is secure. */
  57. private boolean secure;
  58. /**
  59. * Creates a new route tracker.
  60. * The target and origin need to be specified at creation time.
  61. *
  62. * @param target the host to which to route
  63. * @param local the local address to route from, or
  64. * <code>null</code> for the default
  65. */
  66. public RouteTracker(HttpHost target, InetAddress local) {
  67. if (target == null) {
  68. throw new IllegalArgumentException("Target host may not be null.");
  69. }
  70. this.targetHost = target;
  71. this.localAddress = local;
  72. this.tunnelled = TunnelType.PLAIN;
  73. this.layered = LayerType.PLAIN;
  74. }
  75. /**
  76. * Creates a new tracker for the given route.
  77. * Only target and origin are taken from the route,
  78. * everything else remains to be tracked.
  79. *
  80. * @param route the route to track
  81. */
  82. public RouteTracker(HttpRoute route) {
  83. this(route.getTargetHost(), route.getLocalAddress());
  84. }
  85. /**
  86. * Tracks connecting to the target.
  87. *
  88. * @param secure <code>true</code> if the route is secure,
  89. * <code>false</code> otherwise
  90. */
  91. public final void connectTarget(boolean secure) {
  92. if (this.connected) {
  93. throw new IllegalStateException("Already connected.");
  94. }
  95. this.connected = true;
  96. this.secure = secure;
  97. }
  98. /**
  99. * Tracks connecting to the first proxy.
  100. *
  101. * @param proxy the proxy connected to
  102. * @param secure <code>true</code> if the route is secure,
  103. * <code>false</code> otherwise
  104. */
  105. public final void connectProxy(HttpHost proxy, boolean secure) {
  106. if (proxy == null) {
  107. throw new IllegalArgumentException("Proxy host may not be null.");
  108. }
  109. if (this.connected) {
  110. throw new IllegalStateException("Already connected.");
  111. }
  112. this.connected = true;
  113. this.proxyChain = new HttpHost[]{ proxy };
  114. this.secure = secure;
  115. }
  116. /**
  117. * Tracks tunnelling 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 tunnelTarget(boolean secure) {
  123. if (!this.connected) {
  124. throw new IllegalStateException("No tunnel unless connected.");
  125. }
  126. if (this.proxyChain == null) {
  127. throw new IllegalStateException("No tunnel without proxy.");
  128. }
  129. this.tunnelled = TunnelType.TUNNELLED;
  130. this.secure = secure;
  131. }
  132. /**
  133. * Tracks tunnelling to a proxy in a proxy chain.
  134. * This will extend the tracked proxy chain, but it does not mark
  135. * the route as tunnelled. Only end-to-end tunnels are considered there.
  136. *
  137. * @param proxy the proxy tunnelled to
  138. * @param secure <code>true</code> if the route is secure,
  139. * <code>false</code> otherwise
  140. */
  141. public final void tunnelProxy(HttpHost proxy, boolean secure) {
  142. if (proxy == null) {
  143. throw new IllegalArgumentException("Proxy host may not be null.");
  144. }
  145. if (!this.connected) {
  146. throw new IllegalStateException("No tunnel unless connected.");
  147. }
  148. if (this.proxyChain == null) {
  149. throw new IllegalStateException("No proxy tunnel without proxy.");
  150. }
  151. // prepare an extended proxy chain
  152. HttpHost[] proxies = new HttpHost[this.proxyChain.length+1];
  153. System.arraycopy(this.proxyChain, 0,
  154. proxies, 0, this.proxyChain.length);
  155. proxies[proxies.length-1] = proxy;
  156. this.proxyChain = proxies;
  157. this.secure = secure;
  158. }
  159. /**
  160. * Tracks layering a protocol.
  161. *
  162. * @param secure <code>true</code> if the route is secure,
  163. * <code>false</code> otherwise
  164. */
  165. public final void layerProtocol(boolean secure) {
  166. // it is possible to layer a protocol over a direct connection,
  167. // although this case is probably not considered elsewhere
  168. if (!this.connected) {
  169. throw new IllegalStateException
  170. ("No layered protocol unless connected.");
  171. }
  172. this.layered = LayerType.LAYERED;
  173. this.secure = secure;
  174. }
  175. public final HttpHost getTargetHost() {
  176. return this.targetHost;
  177. }
  178. public final InetAddress getLocalAddress() {
  179. return this.localAddress;
  180. }
  181. public final int getHopCount() {
  182. int hops = 0;
  183. if (this.connected) {
  184. if (proxyChain == null)
  185. hops = 1;
  186. else
  187. hops = proxyChain.length + 1;
  188. }
  189. return hops;
  190. }
  191. public final HttpHost getHopTarget(int hop) {
  192. if (hop < 0)
  193. throw new IllegalArgumentException
  194. ("Hop index must not be negative: " + hop);
  195. final int hopcount = getHopCount();
  196. if (hop >= hopcount) {
  197. throw new IllegalArgumentException
  198. ("Hop index " + hop +
  199. " exceeds tracked route length " + hopcount +".");
  200. }
  201. HttpHost result = null;
  202. if (hop < hopcount-1)
  203. result = this.proxyChain[hop];
  204. else
  205. result = this.targetHost;
  206. return result;
  207. }
  208. public final HttpHost getProxyHost() {
  209. return (this.proxyChain == null) ? null : this.proxyChain[0];
  210. }
  211. public final boolean isConnected() {
  212. return this.connected;
  213. }
  214. public final TunnelType getTunnelType() {
  215. return this.tunnelled;
  216. }
  217. public final boolean isTunnelled() {
  218. return (this.tunnelled == TunnelType.TUNNELLED);
  219. }
  220. public final LayerType getLayerType() {
  221. return this.layered;
  222. }
  223. public final boolean isLayered() {
  224. return (this.layered == LayerType.LAYERED);
  225. }
  226. public final boolean isSecure() {
  227. return this.secure;
  228. }
  229. /**
  230. * Obtains the tracked route.
  231. * If a route has been tracked, it is {@link #isConnected connected}.
  232. * If not connected, nothing has been tracked so far.
  233. *
  234. * @return the tracked route, or
  235. * <code>null</code> if nothing has been tracked so far
  236. */
  237. public final HttpRoute toRoute() {
  238. return !this.connected ?
  239. null : new HttpRoute(this.targetHost, this.localAddress,
  240. this.proxyChain, this.secure,
  241. this.tunnelled, this.layered);
  242. }
  243. /**
  244. * Compares this tracked route to another.
  245. *
  246. * @param o the object to compare with
  247. *
  248. * @return <code>true</code> if the argument is the same tracked route,
  249. * <code>false</code>
  250. */
  251. @Override
  252. public final boolean equals(Object o) {
  253. if (o == this)
  254. return true;
  255. if (!(o instanceof RouteTracker))
  256. return false;
  257. RouteTracker that = (RouteTracker) o;
  258. return
  259. // Do the cheapest checks first
  260. (this.connected == that.connected) &&
  261. (this.secure == that.secure) &&
  262. (this.tunnelled == that.tunnelled) &&
  263. (this.layered == that.layered) &&
  264. LangUtils.equals(this.targetHost, that.targetHost) &&
  265. LangUtils.equals(this.localAddress, that.localAddress) &&
  266. LangUtils.equals(this.proxyChain, that.proxyChain);
  267. }
  268. /**
  269. * Generates a hash code for this tracked route.
  270. * Route trackers are modifiable and should therefore not be used
  271. * as lookup keys. Use {@link #toRoute toRoute} to obtain an
  272. * unmodifiable representation of the tracked route.
  273. *
  274. * @return the hash code
  275. */
  276. @Override
  277. public final int hashCode() {
  278. int hash = LangUtils.HASH_SEED;
  279. hash = LangUtils.hashCode(hash, this.targetHost);
  280. hash = LangUtils.hashCode(hash, this.localAddress);
  281. if (this.proxyChain != null) {
  282. for (int i = 0; i < this.proxyChain.length; i++) {
  283. hash = LangUtils.hashCode(hash, this.proxyChain[i]);
  284. }
  285. }
  286. hash = LangUtils.hashCode(hash, this.connected);
  287. hash = LangUtils.hashCode(hash, this.secure);
  288. hash = LangUtils.hashCode(hash, this.tunnelled);
  289. hash = LangUtils.hashCode(hash, this.layered);
  290. return hash;
  291. }
  292. /**
  293. * Obtains a description of the tracked route.
  294. *
  295. * @return a human-readable representation of the tracked route
  296. */
  297. @Override
  298. public final String toString() {
  299. StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
  300. cab.append("RouteTracker[");
  301. if (this.localAddress != null) {
  302. cab.append(this.localAddress);
  303. cab.append("->");
  304. }
  305. cab.append('{');
  306. if (this.connected)
  307. cab.append('c');
  308. if (this.tunnelled == TunnelType.TUNNELLED)
  309. cab.append('t');
  310. if (this.layered == LayerType.LAYERED)
  311. cab.append('l');
  312. if (this.secure)
  313. cab.append('s');
  314. cab.append("}->");
  315. if (this.proxyChain != null) {
  316. for (int i=0; i<this.proxyChain.length; i++) {
  317. cab.append(this.proxyChain[i]);
  318. cab.append("->");
  319. }
  320. }
  321. cab.append(this.targetHost);
  322. cab.append(']');
  323. return cab.toString();
  324. }
  325. // default implementation of clone() is sufficient
  326. @Override
  327. public Object clone() throws CloneNotSupportedException {
  328. return super.clone();
  329. }
  330. }