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 return false;
716
717 default:
718 return true;
719 }
720 }
721 }
722
723
724 public void dispatch(ServletContext context, String path)
725 {
726 _event._dispatchContext=context;
727 _event._path=path;
728 dispatch();
729 }
730
731
732 public void dispatch(String path)
733 {
734 _event._path=path;
735 dispatch();
736 }
737
738
739 public ServletRequest getRequest()
740 {
741 if (_event!=null)
742 return _event.getRequest();
743 return _connection.getRequest();
744 }
745
746
747 public ServletResponse getResponse()
748 {
749 if (_event!=null)
750 return _event.getResponse();
751 return _connection.getResponse();
752 }
753
754
755 public void start(Runnable run)
756 {
757 final AsyncEventState event=_event;
758 if (event!=null)
759 ((Context)event.getServletContext()).getContextHandler().handle(run);
760 }
761
762
763 public boolean hasOriginalRequestAndResponse()
764 {
765 synchronized (this)
766 {
767 return (_event!=null && _event.getRequest()==_connection._request && _event.getResponse()==_connection._response);
768 }
769 }
770
771
772 public ContextHandler getContextHandler()
773 {
774 final AsyncEventState event=_event;
775 if (event!=null)
776 return ((Context)event.getServletContext()).getContextHandler();
777 return null;
778 }
779
780
781
782
783
784
785 public boolean isResumed()
786 {
787 synchronized (this)
788 {
789 return _resumed;
790 }
791 }
792
793
794
795
796 public boolean isExpired()
797 {
798 synchronized (this)
799 {
800 return _expired;
801 }
802 }
803
804
805
806
807
808 public void resume()
809 {
810 dispatch();
811 }
812
813
814
815
816
817 public void setTimeout(long timeoutMs)
818 {
819 setAsyncTimeout(timeoutMs);
820 }
821
822
823
824
825
826 public void suspend(ServletResponse response)
827 {
828 if (response instanceof ServletResponseWrapper)
829 {
830 _responseWrapped=true;
831 AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),response);
832 }
833 else
834 {
835 _responseWrapped=false;
836 AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
837 }
838 }
839
840
841
842
843
844 public void suspend()
845 {
846
847 _responseWrapped=false;
848 AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
849 }
850
851
852
853
854
855 public ServletResponse getServletResponse()
856 {
857 if (_responseWrapped && _event!=null && _event.getResponse()!=null)
858 return _event.getResponse();
859 return _connection.getResponse();
860 }
861
862
863
864
865
866 public Object getAttribute(String name)
867 {
868 return _connection.getRequest().getAttribute(name);
869 }
870
871
872
873
874
875 public void removeAttribute(String name)
876 {
877 _connection.getRequest().removeAttribute(name);
878 }
879
880
881
882
883
884 public void setAttribute(String name, Object attribute)
885 {
886 _connection.getRequest().setAttribute(name,attribute);
887 }
888
889
890
891
892
893 public void undispatch()
894 {
895 if (isSuspended())
896 {
897 if (Log.isDebugEnabled())
898 throw new ContinuationThrowable();
899 else
900 throw __exception;
901 }
902 throw new IllegalStateException("!suspended");
903 }
904
905
906
907 public class AsyncEventState
908 {
909 private final ServletContext _suspendedContext;
910 private final ServletRequest _request;
911 private final ServletResponse _response;
912
913 ServletContext _dispatchContext;
914
915 String _path;
916 final Timeout.Task _timeout = new Timeout.Task()
917 {
918 public void expired()
919 {
920 AsyncContinuation.this.expired();
921 }
922 };
923
924 public AsyncEventState(ServletContext context, ServletRequest request, ServletResponse response)
925 {
926 _suspendedContext=context;
927 _request=request;
928 _response=response;
929 }
930
931 public ServletContext getSuspendedContext()
932 {
933 return _suspendedContext;
934 }
935
936 public ServletContext getDispatchContext()
937 {
938 return _dispatchContext;
939 }
940
941 public ServletContext getServletContext()
942 {
943 return _dispatchContext==null?_suspendedContext:_dispatchContext;
944 }
945
946 public ServletRequest getRequest()
947 {
948 return _request;
949 }
950
951 public ServletResponse getResponse()
952 {
953 return _response;
954 }
955
956 public String getPath()
957 {
958 return _path;
959 }
960 }
961
962 public String getHistory()
963 {
964
965
966
967
968 return null;
969 }
970 }