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