1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.conn.routing;
29
30 import java.net.InetAddress;
31
32 import org.apache.http.HttpHost;
33 import org.apache.http.annotation.NotThreadSafe;
34 import org.apache.http.util.Args;
35 import org.apache.http.util.Asserts;
36 import org.apache.http.util.LangUtils;
37
38
39
40
41
42
43 @NotThreadSafe
44 public final class RouteTracker implements RouteInfo, Cloneable {
45
46
47 private final HttpHost targetHost;
48
49
50
51
52
53 private final InetAddress localAddress;
54
55
56
57
58
59 private boolean connected;
60
61
62 private HttpHost[] proxyChain;
63
64
65 private TunnelType tunnelled;
66
67
68 private LayerType layered;
69
70
71 private boolean secure;
72
73
74
75
76
77
78
79
80
81 public RouteTracker(final HttpHost target, final InetAddress local) {
82 Args.notNull(target, "Target host");
83 this.targetHost = target;
84 this.localAddress = local;
85 this.tunnelled = TunnelType.PLAIN;
86 this.layered = LayerType.PLAIN;
87 }
88
89
90
91
92 public void reset() {
93 this.connected = false;
94 this.proxyChain = null;
95 this.tunnelled = TunnelType.PLAIN;
96 this.layered = LayerType.PLAIN;
97 this.secure = false;
98 }
99
100
101
102
103
104
105
106
107 public RouteTracker(final HttpRoute route) {
108 this(route.getTargetHost(), route.getLocalAddress());
109 }
110
111
112
113
114
115
116
117 public final void connectTarget(final boolean secure) {
118 Asserts.check(!this.connected, "Already connected");
119 this.connected = true;
120 this.secure = secure;
121 }
122
123
124
125
126
127
128
129
130 public final void connectProxy(final HttpHost proxy, final boolean secure) {
131 Args.notNull(proxy, "Proxy host");
132 Asserts.check(!this.connected, "Already connected");
133 this.connected = true;
134 this.proxyChain = new HttpHost[]{ proxy };
135 this.secure = secure;
136 }
137
138
139
140
141
142
143
144 public final void tunnelTarget(final boolean secure) {
145 Asserts.check(this.connected, "No tunnel unless connected");
146 Asserts.notNull(this.proxyChain, "No tunnel without proxy");
147 this.tunnelled = TunnelType.TUNNELLED;
148 this.secure = secure;
149 }
150
151
152
153
154
155
156
157
158
159
160 public final void tunnelProxy(final HttpHost proxy, final boolean secure) {
161 Args.notNull(proxy, "Proxy host");
162 Asserts.check(this.connected, "No tunnel unless connected");
163 Asserts.notNull(this.proxyChain, "No tunnel without proxy");
164
165 final HttpHost[] proxies = new HttpHost[this.proxyChain.length+1];
166 System.arraycopy(this.proxyChain, 0,
167 proxies, 0, this.proxyChain.length);
168 proxies[proxies.length-1] = proxy;
169
170 this.proxyChain = proxies;
171 this.secure = secure;
172 }
173
174
175
176
177
178
179
180 public final void layerProtocol(final boolean secure) {
181
182
183 Asserts.check(this.connected, "No layered protocol unless connected");
184 this.layered = LayerType.LAYERED;
185 this.secure = secure;
186 }
187
188 public final HttpHost getTargetHost() {
189 return this.targetHost;
190 }
191
192 public final InetAddress getLocalAddress() {
193 return this.localAddress;
194 }
195
196 public final int getHopCount() {
197 int hops = 0;
198 if (this.connected) {
199 if (proxyChain == null) {
200 hops = 1;
201 } else {
202 hops = proxyChain.length + 1;
203 }
204 }
205 return hops;
206 }
207
208 public final HttpHost getHopTarget(final int hop) {
209 Args.notNegative(hop, "Hop index");
210 final int hopcount = getHopCount();
211 Args.check(hop < hopcount, "Hop index exceeds tracked route length");
212 HttpHost result = null;
213 if (hop < hopcount-1) {
214 result = this.proxyChain[hop];
215 } else {
216 result = this.targetHost;
217 }
218
219 return result;
220 }
221
222 public final HttpHost getProxyHost() {
223 return (this.proxyChain == null) ? null : this.proxyChain[0];
224 }
225
226 public final boolean isConnected() {
227 return this.connected;
228 }
229
230 public final TunnelType getTunnelType() {
231 return this.tunnelled;
232 }
233
234 public final boolean isTunnelled() {
235 return (this.tunnelled == TunnelType.TUNNELLED);
236 }
237
238 public final LayerType getLayerType() {
239 return this.layered;
240 }
241
242 public final boolean isLayered() {
243 return (this.layered == LayerType.LAYERED);
244 }
245
246 public final boolean isSecure() {
247 return this.secure;
248 }
249
250
251
252
253
254
255
256
257
258 public final HttpRoute toRoute() {
259 return !this.connected ?
260 null : new HttpRoute(this.targetHost, this.localAddress,
261 this.proxyChain, this.secure,
262 this.tunnelled, this.layered);
263 }
264
265
266
267
268
269
270
271
272
273 @Override
274 public final boolean equals(final Object o) {
275 if (o == this) {
276 return true;
277 }
278 if (!(o instanceof RouteTracker)) {
279 return false;
280 }
281
282 final RouteTracker that = (RouteTracker) o;
283 return
284
285 (this.connected == that.connected) &&
286 (this.secure == that.secure) &&
287 (this.tunnelled == that.tunnelled) &&
288 (this.layered == that.layered) &&
289 LangUtils.equals(this.targetHost, that.targetHost) &&
290 LangUtils.equals(this.localAddress, that.localAddress) &&
291 LangUtils.equals(this.proxyChain, that.proxyChain);
292 }
293
294
295
296
297
298
299
300
301
302 @Override
303 public final int hashCode() {
304 int hash = LangUtils.HASH_SEED;
305 hash = LangUtils.hashCode(hash, this.targetHost);
306 hash = LangUtils.hashCode(hash, this.localAddress);
307 if (this.proxyChain != null) {
308 for (final HttpHost element : this.proxyChain) {
309 hash = LangUtils.hashCode(hash, element);
310 }
311 }
312 hash = LangUtils.hashCode(hash, this.connected);
313 hash = LangUtils.hashCode(hash, this.secure);
314 hash = LangUtils.hashCode(hash, this.tunnelled);
315 hash = LangUtils.hashCode(hash, this.layered);
316 return hash;
317 }
318
319
320
321
322
323
324 @Override
325 public final String toString() {
326 final StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
327
328 cab.append("RouteTracker[");
329 if (this.localAddress != null) {
330 cab.append(this.localAddress);
331 cab.append("->");
332 }
333 cab.append('{');
334 if (this.connected) {
335 cab.append('c');
336 }
337 if (this.tunnelled == TunnelType.TUNNELLED) {
338 cab.append('t');
339 }
340 if (this.layered == LayerType.LAYERED) {
341 cab.append('l');
342 }
343 if (this.secure) {
344 cab.append('s');
345 }
346 cab.append("}->");
347 if (this.proxyChain != null) {
348 for (final HttpHost element : this.proxyChain) {
349 cab.append(element);
350 cab.append("->");
351 }
352 }
353 cab.append(this.targetHost);
354 cab.append(']');
355
356 return cab.toString();
357 }
358
359
360
361 @Override
362 public Object clone() throws CloneNotSupportedException {
363 return super.clone();
364 }
365
366 }