1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.server;
15
16 import javax.servlet.ServletContext;
17 import javax.servlet.ServletRequest;
18 import javax.servlet.ServletResponse;
19 import javax.servlet.ServletResponseWrapper;
20
21 import org.eclipse.jetty.continuation.ContinuationThrowable;
22 import org.eclipse.jetty.continuation.ContinuationListener;
23 import org.eclipse.jetty.continuation.Continuation;
24 import org.eclipse.jetty.io.AsyncEndPoint;
25 import org.eclipse.jetty.io.EndPoint;
26 import org.eclipse.jetty.server.handler.ContextHandler;
27 import org.eclipse.jetty.server.handler.ContextHandler.Context;
28 import org.eclipse.jetty.util.LazyList;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.thread.Timeout;
31
32
33
34
35
36 public class AsyncContinuation implements AsyncContext, Continuation
37 {
38 private final static long DEFAULT_TIMEOUT=30000L;
39
40 private final static ContinuationThrowable __exception = new ContinuationThrowable();
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 private static final int __IDLE=0;
56 private static final int __DISPATCHED=1;
57 private static final int __ASYNCSTARTED=2;
58 private static final int __REDISPATCHING=3;
59 private static final int __ASYNCWAIT=4;
60 private static final int __REDISPATCH=5;
61 private static final int __REDISPATCHED=6;
62 private static final int __COMPLETING=7;
63 private static final int __UNCOMPLETED=8;
64 private static final int __COMPLETED=9;
65
66
67
68 protected HttpConnection _connection;
69 private Object _listeners;
70
71
72 private int _state;
73 private boolean _initial;
74 private boolean _resumed;
75 private boolean _expired;
76 private volatile boolean _responseWrapped;
77 private long _timeoutMs=DEFAULT_TIMEOUT;
78 private AsyncEventState _event;
79 private volatile long _expireAt;
80
81
82
83
84 protected AsyncContinuation()
85 {
86 _state=__IDLE;
87 _initial=true;
88
89
90 }
91
92
93 protected void setConnection(final HttpConnection connection)
94 {
95 synchronized(this)
96 {
97 _connection=connection;
98
99
100 }
101 }
102
103
104 public void addContinuationListener(ContinuationListener listener)
105 {
106 synchronized(this)
107 {
108 _listeners=LazyList.add(_listeners,listener);
109
110 }
111 }
112
113
114 public void setAsyncTimeout(long ms)
115 {
116 synchronized(this)
117 {
118 _timeoutMs=ms;
119
120
121 }
122 }
123
124
125 public long getAsyncTimeout()
126 {
127 synchronized(this)
128 {
129 return _timeoutMs;
130 }
131 }
132
133
134 public AsyncEventState getAsyncEventState()
135 {
136 synchronized(this)
137 {
138 return _event;
139 }
140 }
141
142
143
144
145
146
147
148
149
150
151 public boolean isResponseWrapped()
152 {
153 return _responseWrapped;
154 }
155
156
157
158
159
160 public boolean isInitial()
161 {
162 synchronized(this)
163 {
164 return _initial;
165 }
166 }
167
168
169
170
171
172 public boolean isSuspended()
173 {
174 synchronized(this)
175 {
176 switch(_state)
177 {
178 case __ASYNCSTARTED:
179 case __REDISPATCHING:
180 case __COMPLETING:
181 case __ASYNCWAIT:
182 return true;
183
184 default:
185 return false;
186 }
187 }
188 }
189
190
191 public String toString()
192 {
193 synchronized (this)
194 {
195 return super.toString()+"@"+getStatusString();
196 }
197 }
198
199
200 public String getStatusString()
201 {
202 synchronized (this)
203 {
204 return
205 ((_state==__IDLE)?"IDLE":
206 (_state==__DISPATCHED)?"DISPATCHED":
207 (_state==__ASYNCSTARTED)?"ASYNCSTARTED":
208 (_state==__ASYNCWAIT)?"ASYNCWAIT":
209 (_state==__REDISPATCHING)?"REDISPATCHING":
210 (_state==__REDISPATCH)?"REDISPATCH":
211 (_state==__REDISPATCHED)?"REDISPATCHED":
212 (_state==__COMPLETING)?"COMPLETING":
213 (_state==__UNCOMPLETED)?"UNCOMPLETED":
214 (_state==__COMPLETED)?"COMPLETE":
215 ("UNKNOWN?"+_state))+
216 (_initial?",initial":"")+
217 (_resumed?",resumed":"")+
218 (_expired?",expired":"");
219 }
220 }
221
222
223
224
225
226 protected boolean handling()
227 {
228 synchronized (this)
229 {
230
231
232
233 _responseWrapped=false;
234
235 switch(_state)
236 {
237 case __DISPATCHED:
238 case __REDISPATCHED:
239 case __COMPLETED:
240 throw new IllegalStateException(this.getStatusString());
241
242 case __IDLE:
243 _initial=true;
244 _state=__DISPATCHED;
245 return true;
246
247 case __ASYNCSTARTED:
248 case __REDISPATCHING:
249 throw new IllegalStateException(this.getStatusString());
250
251 case __COMPLETING:
252 _state=__UNCOMPLETED;
253 return false;
254
255 case __ASYNCWAIT:
256 return false;
257
258 case __REDISPATCH:
259 _state=__REDISPATCHED;
260 return true;
261
262 default:
263 throw new IllegalStateException(""+_state);
264 }
265 }
266 }
267
268
269
270
271
272 protected void suspend(final ServletContext context,
273 final ServletRequest request,
274 final ServletResponse response)
275 {
276 synchronized (this)
277 {
278
279 _resumed=false;
280 _expired=false;
281
282
283 if (_event==null || request!=_event.getRequest() || response != _event.getResponse() || context != _event.getServletContext())
284 _event=new AsyncEventState(context,request,response);
285 else
286 {
287 _event._dispatchContext=null;
288 _event._path=null;
289 }
290
291 switch(_state)
292 {
293 case __DISPATCHED:
294 case __REDISPATCHED:
295 _state=__ASYNCSTARTED;
296 return;
297
298 case __IDLE:
299 throw new IllegalStateException(this.getStatusString());
300
301 case __ASYNCSTARTED:
302 case __REDISPATCHING:
303 return;
304
305 case __COMPLETING:
306 case __ASYNCWAIT:
307 case __REDISPATCH:
308 case __COMPLETED:
309 throw new IllegalStateException(this.getStatusString());
310
311 default:
312 throw new IllegalStateException(""+_state);
313 }
314 }
315 }
316
317
318
319
320
321
322
323
324
325 protected boolean unhandle()
326 {
327 synchronized (this)
328 {
329
330 switch(_state)
331 {
332 case __REDISPATCHED:
333 case __DISPATCHED:
334 _state=__UNCOMPLETED;
335 return true;
336
337 case __IDLE:
338 throw new IllegalStateException(this.getStatusString());
339
340 case __ASYNCSTARTED:
341 _initial=false;
342 _state=__ASYNCWAIT;
343 scheduleTimeout();
344 if (_state==__ASYNCWAIT)
345 return true;
346 else if (_state==__COMPLETING)
347 {
348 _state=__UNCOMPLETED;
349 return true;
350 }
351 _initial=false;
352 _state=__REDISPATCHED;
353 return false;
354
355 case __REDISPATCHING:
356 _initial=false;
357 _state=__REDISPATCHED;
358 return false;
359
360 case __COMPLETING:
361 _initial=false;
362 _state=__UNCOMPLETED;
363 return true;
364
365 case __ASYNCWAIT:
366 case __REDISPATCH:
367 default:
368 throw new IllegalStateException(this.getStatusString());
369 }
370 }
371 }
372
373
374 public void dispatch()
375 {
376 boolean dispatch=false;
377 synchronized (this)
378 {
379
380 switch(_state)
381 {
382 case __REDISPATCHED:
383 case __DISPATCHED:
384 case __IDLE:
385 case __REDISPATCHING:
386 case __COMPLETING:
387 case __COMPLETED:
388 case __UNCOMPLETED:
389 return;
390
391 case __ASYNCSTARTED:
392 _state=__REDISPATCHING;
393 _resumed=true;
394 return;
395
396 case __ASYNCWAIT:
397 dispatch=!_expired;
398 _state=__REDISPATCH;
399 _resumed=true;
400 break;
401
402 case __REDISPATCH:
403 return;
404
405 default:
406 throw new IllegalStateException(this.getStatusString());
407 }
408 }
409
410 if (dispatch)
411 {
412 cancelTimeout();
413 scheduleDispatch();
414 }
415 }
416
417
418 protected void expired()
419 {
420 Object listeners=null;
421 synchronized (this)
422 {
423
424 switch(_state)
425 {
426 case __ASYNCSTARTED:
427 case __ASYNCWAIT:
428 listeners=_listeners;
429 break;
430 default:
431 return;
432 }
433 _expired=true;
434 }
435
436 if (listeners!=null)
437 {
438 for(int i=0;i<LazyList.size(listeners);i++)
439 {
440 try
441 {
442
443
444
445
446
447 ContinuationListener listener=((ContinuationListener)LazyList.get(listeners,i));
448 listener.onTimeout(this);
449 }
450 catch(Exception e)
451 {
452 Log.warn(e);
453 }
454 }
455 }
456
457 synchronized (this)
458 {
459
460 switch(_state)
461 {
462 case __ASYNCSTARTED:
463 case __ASYNCWAIT:
464 dispatch();
465 }
466 }
467
468 scheduleDispatch();
469 }
470
471
472
473
474
475 public void complete()
476 {
477
478 boolean dispatch=false;
479 synchronized (this)
480 {
481
482 switch(_state)
483 {
484 case __IDLE:
485 case __COMPLETED:
486 case __REDISPATCHING:
487 case __COMPLETING:
488 case __REDISPATCH:
489 return;
490
491 case __DISPATCHED:
492 case __REDISPATCHED:
493 throw new IllegalStateException(this.getStatusString());
494
495 case __ASYNCSTARTED:
496 _state=__COMPLETING;
497 return;
498
499 case __ASYNCWAIT:
500 _state=__COMPLETING;
501 dispatch=!_expired;
502 break;
503
504 default:
505 throw new IllegalStateException(this.getStatusString());
506 }
507 }
508
509 if (dispatch)
510 {
511 cancelTimeout();
512 scheduleDispatch();
513 }
514 }
515
516
517
518
519
520
521 protected void doComplete()
522 {
523 Object listeners=null;
524 synchronized (this)
525 {
526
527 switch(_state)
528 {
529 case __UNCOMPLETED:
530 _state=__COMPLETED;
531 listeners=_listeners;
532 break;
533
534 default:
535 throw new IllegalStateException(this.getStatusString());
536 }
537 }
538
539 if (listeners!=null)
540 {
541 for(int i=0;i<LazyList.size(listeners);i++)
542 {
543 try
544 {
545
546
547
548
549
550 ((ContinuationListener)LazyList.get(listeners,i)).onComplete(this);
551 }
552 catch(Exception e)
553 {
554 Log.warn(e);
555 }
556 }
557 }
558 }
559
560
561 protected void recycle()
562 {
563 synchronized (this)
564 {
565
566 switch(_state)
567 {
568 case __DISPATCHED:
569 case __REDISPATCHED:
570 throw new IllegalStateException(getStatusString());
571 default:
572 _state=__IDLE;
573 }
574 _initial = true;
575 _resumed=false;
576 _expired=false;
577 _responseWrapped=false;
578 cancelTimeout();
579 _timeoutMs=DEFAULT_TIMEOUT;
580 _listeners=null;
581 }
582 }
583
584
585 public void cancel()
586 {
587 synchronized (this)
588 {
589
590 cancelTimeout();
591 _listeners=null;
592 }
593 }
594
595
596 protected void scheduleDispatch()
597 {
598 EndPoint endp=_connection.getEndPoint();
599 if (!endp.isBlocking())
600 {
601 ((AsyncEndPoint)endp).dispatch();
602 }
603 }
604
605
606 protected void scheduleTimeout()
607 {
608 EndPoint endp=_connection.getEndPoint();
609 if (endp.isBlocking())
610 {
611 synchronized(this)
612 {
613 _expireAt = System.currentTimeMillis()+_timeoutMs;
614 long wait=_timeoutMs;
615 while (_expireAt>0 && wait>0)
616 {
617 try
618 {
619 this.wait(wait);
620 }
621 catch (InterruptedException e)
622 {
623 Log.ignore(e);
624 }
625 wait=_expireAt-System.currentTimeMillis();
626 }
627
628 if (_expireAt>0 && wait<=0)
629 {
630 expired();
631 }
632 }
633 }
634 else
635 _connection.scheduleTimeout(_event._timeout,_timeoutMs);
636 }
637
638
639 protected void cancelTimeout()
640 {
641 EndPoint endp=_connection.getEndPoint();
642 if (endp.isBlocking())
643 {
644 synchronized(this)
645 {
646 _expireAt=0;
647 this.notifyAll();
648 }
649 }
650 else
651 {
652 final AsyncEventState event=_event;
653 if (event!=null)
654 _connection.cancelTimeout(event._timeout);
655 }
656 }
657
658
659 public boolean isCompleting()
660 {
661 synchronized (this)
662 {
663 return _state==__COMPLETING;
664 }
665 }
666
667
668 boolean isUncompleted()
669 {
670 synchronized (this)
671 {
672 return _state==__UNCOMPLETED;
673 }
674 }
675
676
677 public boolean isComplete()
678 {
679 synchronized (this)
680 {
681 return _state==__COMPLETED;
682 }
683 }
684
685
686
687 public boolean isAsyncStarted()
688 {
689 synchronized (this)
690 {
691 switch(_state)
692 {
693 case __ASYNCSTARTED:
694 case __REDISPATCHING:
695 case __REDISPATCH:
696 case __ASYNCWAIT:
697 return true;
698
699 default:
700 return false;
701 }
702 }
703 }
704
705
706
707 public boolean isAsync()
708 {
709 synchronized (this)
710 {
711 switch(_state)
712 {
713 case __IDLE:
714 case __DISPATCHED:
715 case __UNCOMPLETED:
716 case __COMPLETED:
717 return false;
718
719 default:
720 return true;
721 }
722 }
723 }
724
725
726 public void dispatch(ServletContext context, String path)
727 {
728 _event._dispatchContext=context;
729 _event._path=path;
730 dispatch();
731 }
732
733
734 public void dispatch(String path)
735 {
736 _event._path=path;
737 dispatch();
738 }
739
740
741 public ServletRequest getRequest()
742 {
743 if (_event!=null)
744 return _event.getRequest();
745 return _connection.getRequest();
746 }
747
748
749 public ServletResponse getResponse()
750 {
751 if (_event!=null)
752 return _event.getResponse();
753 return _connection.getResponse();
754 }
755
756
757 public void start(Runnable run)
758 {
759 final AsyncEventState event=_event;
760 if (event!=null)
761 ((Context)event.getServletContext()).getContextHandler().handle(run);
762 }
763
764
765 public boolean hasOriginalRequestAndResponse()
766 {
767 synchronized (this)
768 {
769 return (_event!=null && _event.getRequest()==_connection._request && _event.getResponse()==_connection._response);
770 }
771 }
772
773
774 public ContextHandler getContextHandler()
775 {
776 final AsyncEventState event=_event;
777 if (event!=null)
778 return ((Context)event.getServletContext()).getContextHandler();
779 return null;
780 }
781
782
783
784
785
786
787 public boolean isResumed()
788 {
789 synchronized (this)
790 {
791 return _resumed;
792 }
793 }
794
795
796
797
798 public boolean isExpired()
799 {
800 synchronized (this)
801 {
802 return _expired;
803 }
804 }
805
806
807
808
809
810 public void resume()
811 {
812 dispatch();
813 }
814
815
816
817
818
819 public void setTimeout(long timeoutMs)
820 {
821 setAsyncTimeout(timeoutMs);
822 }
823
824
825
826
827
828 public void suspend(ServletResponse response)
829 {
830 if (response instanceof ServletResponseWrapper)
831 {
832 _responseWrapped=true;
833 AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),response);
834 }
835 else
836 {
837 _responseWrapped=false;
838 AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
839 }
840 }
841
842
843
844
845
846 public void suspend()
847 {
848
849 _responseWrapped=false;
850 AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
851 }
852
853
854
855
856
857 public ServletResponse getServletResponse()
858 {
859 if (_responseWrapped && _event!=null && _event.getResponse()!=null)
860 return _event.getResponse();
861 return _connection.getResponse();
862 }
863
864
865
866
867
868 public Object getAttribute(String name)
869 {
870 return _connection.getRequest().getAttribute(name);
871 }
872
873
874
875
876
877 public void removeAttribute(String name)
878 {
879 _connection.getRequest().removeAttribute(name);
880 }
881
882
883
884
885
886 public void setAttribute(String name, Object attribute)
887 {
888 _connection.getRequest().setAttribute(name,attribute);
889 }
890
891
892
893
894
895 public void undispatch()
896 {
897 if (isSuspended())
898 {
899 if (Log.isDebugEnabled())
900 throw new ContinuationThrowable();
901 else
902 throw __exception;
903 }
904 throw new IllegalStateException("!suspended");
905 }
906
907
908
909 public class AsyncEventState
910 {
911 private final ServletContext _suspendedContext;
912 private final ServletRequest _request;
913 private final ServletResponse _response;
914
915 ServletContext _dispatchContext;
916
917 String _path;
918 final Timeout.Task _timeout = new Timeout.Task()
919 {
920 public void expired()
921 {
922 AsyncContinuation.this.expired();
923 }
924 };
925
926 public AsyncEventState(ServletContext context, ServletRequest request, ServletResponse response)
927 {
928 _suspendedContext=context;
929 _request=request;
930 _response=response;
931 }
932
933 public ServletContext getSuspendedContext()
934 {
935 return _suspendedContext;
936 }
937
938 public ServletContext getDispatchContext()
939 {
940 return _dispatchContext;
941 }
942
943 public ServletContext getServletContext()
944 {
945 return _dispatchContext==null?_suspendedContext:_dispatchContext;
946 }
947
948 public ServletRequest getRequest()
949 {
950 return _request;
951 }
952
953 public ServletResponse getResponse()
954 {
955 return _response;
956 }
957
958 public String getPath()
959 {
960 return _path;
961 }
962 }
963
964 public String getHistory()
965 {
966
967
968
969
970 return null;
971 }
972 }