1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.jetty.client;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.net.InetSocketAddress;
20
21 import org.mortbay.io.Buffer;
22 import org.mortbay.io.BufferCache.CachedBuffer;
23 import org.mortbay.io.ByteArrayBuffer;
24 import org.mortbay.jetty.HttpFields;
25 import org.mortbay.jetty.HttpHeaders;
26 import org.mortbay.jetty.HttpMethods;
27 import org.mortbay.jetty.HttpSchemes;
28 import org.mortbay.jetty.HttpURI;
29 import org.mortbay.jetty.HttpVersions;
30 import org.mortbay.log.Log;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class HttpExchange
66 {
67 public static final int STATUS_START = 0;
68 public static final int STATUS_WAITING_FOR_CONNECTION = 1;
69 public static final int STATUS_WAITING_FOR_COMMIT = 2;
70 public static final int STATUS_SENDING_REQUEST = 3;
71 public static final int STATUS_WAITING_FOR_RESPONSE = 4;
72 public static final int STATUS_PARSING_HEADERS = 5;
73 public static final int STATUS_PARSING_CONTENT = 6;
74 public static final int STATUS_COMPLETED = 7;
75 public static final int STATUS_EXPIRED = 8;
76 public static final int STATUS_EXCEPTED = 9;
77
78 String _method = HttpMethods.GET;
79 Buffer _scheme = HttpSchemes.HTTP_BUFFER;
80 String _uri;
81 int _version = HttpVersions.HTTP_1_1_ORDINAL;
82 Address _address;
83 HttpFields _requestFields = new HttpFields();
84 Buffer _requestContent;
85 InputStream _requestContentSource;
86 long _timeout = -1;
87
88 volatile int _status = STATUS_START;
89 Buffer _requestContentChunk;
90 boolean _retryStatus = false;
91
92 boolean _configureListeners = true;
93 private HttpEventListener _listener = new Listener();
94
95 boolean _onRequestCompleteDone;
96 boolean _onResponseCompleteDone;
97 boolean _onDone;
98
99
100 public int getStatus()
101 {
102 return _status;
103 }
104
105
106
107
108
109 public void waitForStatus(int status) throws InterruptedException
110 {
111 synchronized (this)
112 {
113 while (_status < status)
114 {
115 this.wait();
116 }
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 public int waitForDone () throws InterruptedException
137 {
138 synchronized (this)
139 {
140 while (!isDone(_status))
141 this.wait();
142 return _status;
143 }
144 }
145
146
147
148
149
150 public void reset()
151 {
152
153
154 synchronized(this)
155 {
156 _onRequestCompleteDone=false;
157 _onResponseCompleteDone=false;
158 _onDone=false;
159 setStatus(STATUS_START);
160 }
161 }
162
163
164 void setStatus(int status)
165 {
166
167 _status = status;
168
169 try
170 {
171 switch (status)
172 {
173 case STATUS_WAITING_FOR_CONNECTION:
174 break;
175
176 case STATUS_WAITING_FOR_COMMIT:
177 break;
178
179 case STATUS_SENDING_REQUEST:
180 break;
181
182 case HttpExchange.STATUS_WAITING_FOR_RESPONSE:
183 getEventListener().onRequestCommitted();
184 break;
185
186 case STATUS_PARSING_HEADERS:
187 break;
188
189 case STATUS_PARSING_CONTENT:
190 getEventListener().onResponseHeaderComplete();
191 break;
192
193 case STATUS_COMPLETED:
194 getEventListener().onResponseComplete();
195 break;
196
197 case STATUS_EXPIRED:
198 getEventListener().onExpire();
199 break;
200
201 }
202 }
203 catch (IOException e)
204 {
205 Log.warn(e);
206 }
207 }
208
209
210 public boolean isDone (int status)
211 {
212 synchronized (this)
213 {
214 return _onDone;
215 }
216 }
217
218
219 public HttpEventListener getEventListener()
220 {
221 return _listener;
222 }
223
224
225 public void setEventListener(HttpEventListener listener)
226 {
227 _listener=listener;
228 }
229
230
231
232
233
234 public void setURL(String url)
235 {
236 HttpURI uri = new HttpURI(url);
237 String scheme = uri.getScheme();
238 if (scheme != null)
239 {
240 if (HttpSchemes.HTTP.equalsIgnoreCase(scheme))
241 setScheme(HttpSchemes.HTTP_BUFFER);
242 else if (HttpSchemes.HTTPS.equalsIgnoreCase(scheme))
243 setScheme(HttpSchemes.HTTPS_BUFFER);
244 else
245 setScheme(new ByteArrayBuffer(scheme));
246 }
247
248 int port = uri.getPort();
249 if (port <= 0)
250 port = "https".equalsIgnoreCase(scheme)?443:80;
251
252 setAddress(new Address(uri.getHost(),port));
253
254 String completePath = uri.getCompletePath();
255 if (completePath == null)
256 completePath = "/";
257
258 setURI(completePath);
259 }
260
261
262
263
264
265 public void setAddress(Address address)
266 {
267 _address = address;
268 }
269
270
271
272
273
274 public Address getAddress()
275 {
276 return _address;
277 }
278
279
280
281
282
283 public void setScheme(Buffer scheme)
284 {
285 _scheme = scheme;
286 }
287
288
289
290
291
292 public Buffer getScheme()
293 {
294 return _scheme;
295 }
296
297
298
299
300
301 public void setVersion(int version)
302 {
303 _version = version;
304 }
305
306
307 public void setVersion(String version)
308 {
309 CachedBuffer v = HttpVersions.CACHE.get(version);
310 if (v == null)
311 _version = 10;
312 else
313 _version = v.getOrdinal();
314 }
315
316
317
318
319
320 public int getVersion()
321 {
322 return _version;
323 }
324
325
326
327
328
329 public void setMethod(String method)
330 {
331 _method = method;
332 }
333
334
335
336
337
338 public String getMethod()
339 {
340 return _method;
341 }
342
343
344
345
346
347 public String getURI()
348 {
349 return _uri;
350 }
351
352
353
354
355
356 public void setURI(String uri)
357 {
358 _uri = uri;
359 }
360
361
362
363
364
365
366 public void addRequestHeader(String name, String value)
367 {
368 getRequestFields().add(name,value);
369 }
370
371
372
373
374
375
376 public void addRequestHeader(Buffer name, Buffer value)
377 {
378 getRequestFields().add(name,value);
379 }
380
381
382
383
384
385
386 public void setRequestHeader(String name, String value)
387 {
388 getRequestFields().put(name,value);
389 }
390
391
392
393
394
395
396 public void setRequestHeader(Buffer name, Buffer value)
397 {
398 getRequestFields().put(name,value);
399 }
400
401
402
403
404
405 public void setRequestContentType(String value)
406 {
407 getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,value);
408 }
409
410
411
412
413
414 public HttpFields getRequestFields()
415 {
416 return _requestFields;
417 }
418
419
420
421
422
423
424
425
426
427
428 public void setRequestContent(Buffer requestContent)
429 {
430 _requestContent = requestContent;
431 }
432
433
434
435
436
437 public void setRequestContentSource(InputStream in)
438 {
439 _requestContentSource = in;
440 if (_requestContentSource.markSupported())
441 _requestContentSource.mark(Integer.MAX_VALUE);
442 }
443
444
445 public InputStream getRequestContentSource()
446 {
447 return _requestContentSource;
448 }
449
450
451 public Buffer getRequestContentChunk() throws IOException
452 {
453 synchronized (this)
454 {
455 if (_requestContentChunk == null)
456 _requestContentChunk = new ByteArrayBuffer(4096);
457 else
458 {
459 if (_requestContentChunk.hasContent())
460 throw new IllegalStateException();
461 _requestContentChunk.clear();
462 }
463
464 int read = _requestContentChunk.capacity();
465 int length = _requestContentSource.read(_requestContentChunk.array(),0,read);
466 if (length >= 0)
467 {
468 _requestContentChunk.setPutIndex(length);
469 return _requestContentChunk;
470 }
471 return null;
472 }
473 }
474
475
476 public Buffer getRequestContent()
477 {
478 return _requestContent;
479 }
480
481
482 public boolean getRetryStatus()
483 {
484 return _retryStatus;
485 }
486
487
488 public void setRetryStatus( boolean retryStatus )
489 {
490 _retryStatus = retryStatus;
491 }
492
493
494 public long getTimeout()
495 {
496 return _timeout;
497 }
498
499
500 public void setTimeout(long timeout)
501 {
502 _timeout = timeout;
503 }
504
505
506
507
508
509 public void cancel()
510 {
511
512 }
513
514
515 public String toString()
516 {
517 return getClass().getName() + "@" + hashCode() + "=" + _method + "//" + _address + _uri + "#" + _status;
518 }
519
520
521
522
523
524
525
526
527
528
529
530
531 protected void onRequestCommitted() throws IOException
532 {
533 }
534
535
536
537
538
539 protected void onRequestComplete() throws IOException
540 {
541 }
542
543
544
545
546
547
548
549
550 protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
551 {
552 }
553
554
555
556
557
558
559
560 protected void onResponseHeader(Buffer name, Buffer value) throws IOException
561 {
562 }
563
564
565
566
567
568 protected void onResponseHeaderComplete() throws IOException
569 {
570 }
571
572
573
574
575
576
577 protected void onResponseContent(Buffer content) throws IOException
578 {
579 }
580
581
582
583
584
585 protected void onResponseComplete() throws IOException
586 {
587 }
588
589
590
591
592
593 protected void onConnectionFailed(Throwable ex)
594 {
595 Log.warn("CONNECTION FAILED on " + this,ex);
596 }
597
598
599
600
601
602 protected void onException(Throwable ex)
603 {
604 Log.warn("EXCEPTION on " + this,ex);
605 }
606
607
608
609
610 protected void onExpire()
611 {
612 Log.warn("EXPIRED " + this);
613 }
614
615
616
617
618
619
620
621 protected void onRetry() throws IOException
622 {
623 if (_requestContentSource != null)
624 {
625 if (_requestContentSource.markSupported())
626 {
627 _requestContent = null;
628 _requestContentSource.reset();
629 }
630 else
631 {
632 throw new IOException("Unsupported retry attempt");
633 }
634 }
635 }
636
637
638
639
640
641
642
643
644 public boolean configureListeners()
645 {
646 return _configureListeners;
647 }
648
649 public void setConfigureListeners(boolean autoConfigure )
650 {
651 this._configureListeners = autoConfigure;
652 }
653
654 private class Listener implements HttpEventListener
655 {
656 public void onConnectionFailed(Throwable ex)
657 {
658 try
659 {
660 HttpExchange.this.onConnectionFailed(ex);
661 }
662 finally
663 {
664 synchronized(HttpExchange.this)
665 {
666 _onDone=true;
667 HttpExchange.this.notifyAll();
668 }
669 }
670 }
671
672 public void onException(Throwable ex)
673 {
674 try
675 {
676 HttpExchange.this.onException(ex);
677 }
678 finally
679 {
680 synchronized(HttpExchange.this)
681 {
682 _onDone=true;
683 HttpExchange.this.notifyAll();
684 }
685 }
686 }
687
688 public void onExpire()
689 {
690 try
691 {
692 HttpExchange.this.onExpire();
693 }
694 finally
695 {
696 synchronized(HttpExchange.this)
697 {
698 _onDone=true;
699 HttpExchange.this.notifyAll();
700 }
701 }
702 }
703
704 public void onRequestCommitted() throws IOException
705 {
706 HttpExchange.this.onRequestCommitted();
707 }
708
709 public void onRequestComplete() throws IOException
710 {
711 try
712 {
713 HttpExchange.this.onRequestComplete();
714 }
715 finally
716 {
717 synchronized(HttpExchange.this)
718 {
719 _onRequestCompleteDone=true;
720 _onDone=_onResponseCompleteDone;
721 HttpExchange.this.notifyAll();
722 }
723 }
724 }
725
726 public void onResponseComplete() throws IOException
727 {
728 try
729 {
730 HttpExchange.this.onResponseComplete();
731 }
732 finally
733 {
734 synchronized(HttpExchange.this)
735 {
736 _onResponseCompleteDone=true;
737 _onDone=_onRequestCompleteDone;
738 HttpExchange.this.notifyAll();
739 }
740 }
741 }
742
743 public void onResponseContent(Buffer content) throws IOException
744 {
745 HttpExchange.this.onResponseContent(content);
746 }
747
748 public void onResponseHeader(Buffer name, Buffer value) throws IOException
749 {
750 HttpExchange.this.onResponseHeader(name,value);
751 }
752
753 public void onResponseHeaderComplete() throws IOException
754 {
755 HttpExchange.this.onResponseHeaderComplete();
756 }
757
758 public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
759 {
760 HttpExchange.this.onResponseStatus(version,status,reason);
761 }
762
763 public void onRetry()
764 {
765 HttpExchange.this.setRetryStatus( true );
766 try
767 {
768 HttpExchange.this.onRetry();
769 }
770 catch (IOException e)
771 {
772 onException(e);
773 }
774 }
775 }
776
777
778
779
780
781 public static class CachedExchange extends org.mortbay.jetty.client.CachedExchange
782 {
783 public CachedExchange(boolean cacheFields)
784 {
785 super(cacheFields);
786 }
787 }
788
789
790
791
792
793 public static class ContentExchange extends org.mortbay.jetty.client.ContentExchange
794 {
795
796 }
797
798
799
800 }