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