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