comparison src/org/eclipse/jetty/server/AsyncContinuation.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 8e9db0bbf4f9
comparison
equal deleted inserted replaced
801:6a21393191c1 802:3428c60d7cfc
1 //
2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
21 import javax.servlet.AsyncContext;
22 import javax.servlet.AsyncEvent;
23 import javax.servlet.AsyncListener;
24 import javax.servlet.RequestDispatcher;
25 import javax.servlet.ServletException;
26
27 import java.util.ArrayList;
28 import java.util.List;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.ServletRequest;
32 import javax.servlet.ServletResponse;
33 import javax.servlet.http.HttpServletRequest;
34
35 import org.eclipse.jetty.continuation.Continuation;
36 import org.eclipse.jetty.continuation.ContinuationThrowable;
37 import org.eclipse.jetty.continuation.ContinuationListener;
38 import org.eclipse.jetty.io.AsyncEndPoint;
39 import org.eclipse.jetty.io.EndPoint;
40 import org.eclipse.jetty.server.handler.ContextHandler;
41 import org.eclipse.jetty.server.handler.ContextHandler.Context;
42 import org.eclipse.jetty.util.URIUtil;
43 import org.eclipse.jetty.util.log.Log;
44 import org.eclipse.jetty.util.log.Logger;
45 import org.eclipse.jetty.util.thread.Timeout;
46
47 /* ------------------------------------------------------------ */
48 /** Implementation of Continuation and AsyncContext interfaces
49 *
50 */
51 public class AsyncContinuation implements AsyncContext, Continuation
52 {
53 private static final Logger LOG = Log.getLogger(AsyncContinuation.class);
54
55 private final static long DEFAULT_TIMEOUT=30000L;
56
57 private final static ContinuationThrowable __exception = new ContinuationThrowable();
58
59 // STATES:
60 // handling() suspend() unhandle() resume() complete() doComplete()
61 // startAsync() dispatch()
62 // IDLE DISPATCHED
63 // DISPATCHED ASYNCSTARTED UNCOMPLETED
64 // ASYNCSTARTED ASYNCWAIT REDISPATCHING COMPLETING
65 // REDISPATCHING REDISPATCHED
66 // ASYNCWAIT REDISPATCH COMPLETING
67 // REDISPATCH REDISPATCHED
68 // REDISPATCHED ASYNCSTARTED UNCOMPLETED
69 // COMPLETING UNCOMPLETED UNCOMPLETED
70 // UNCOMPLETED COMPLETED
71 // COMPLETED
72 private static final int __IDLE=0; // Idle request
73 private static final int __DISPATCHED=1; // Request dispatched to filter/servlet
74 private static final int __ASYNCSTARTED=2; // Suspend called, but not yet returned to container
75 private static final int __REDISPATCHING=3;// resumed while dispatched
76 private static final int __ASYNCWAIT=4; // Suspended and parked
77 private static final int __REDISPATCH=5; // Has been scheduled
78 private static final int __REDISPATCHED=6; // Request redispatched to filter/servlet
79 private static final int __COMPLETING=7; // complete while dispatched
80 private static final int __UNCOMPLETED=8; // Request is completable
81 private static final int __COMPLETED=9; // Request is complete
82
83 /* ------------------------------------------------------------ */
84 protected AbstractHttpConnection _connection;
85 private List<AsyncListener> _lastAsyncListeners;
86 private List<AsyncListener> _asyncListeners;
87 private List<ContinuationListener> _continuationListeners;
88
89 /* ------------------------------------------------------------ */
90 private int _state;
91 private boolean _initial;
92 private boolean _resumed;
93 private boolean _expired;
94 private volatile boolean _responseWrapped;
95 private long _timeoutMs=DEFAULT_TIMEOUT;
96 private AsyncEventState _event;
97 private volatile long _expireAt;
98 private volatile boolean _continuation;
99
100 /* ------------------------------------------------------------ */
101 protected AsyncContinuation()
102 {
103 _state=__IDLE;
104 _initial=true;
105 }
106
107 /* ------------------------------------------------------------ */
108 protected void setConnection(final AbstractHttpConnection connection)
109 {
110 synchronized(this)
111 {
112 _connection=connection;
113 }
114 }
115
116 /* ------------------------------------------------------------ */
117 public void addListener(AsyncListener listener)
118 {
119 synchronized(this)
120 {
121 if (_asyncListeners==null)
122 _asyncListeners=new ArrayList<AsyncListener>();
123 _asyncListeners.add(listener);
124 }
125 }
126
127 /* ------------------------------------------------------------ */
128 public void addListener(AsyncListener listener,ServletRequest request, ServletResponse response)
129 {
130 synchronized(this)
131 {
132 // TODO handle the request/response ???
133 if (_asyncListeners==null)
134 _asyncListeners=new ArrayList<AsyncListener>();
135 _asyncListeners.add(listener);
136 }
137 }
138
139 /* ------------------------------------------------------------ */
140 public void addContinuationListener(ContinuationListener listener)
141 {
142 synchronized(this)
143 {
144 if (_continuationListeners==null)
145 _continuationListeners=new ArrayList<ContinuationListener>();
146 _continuationListeners.add(listener);
147 }
148 }
149
150 /* ------------------------------------------------------------ */
151 public void setTimeout(long ms)
152 {
153 synchronized(this)
154 {
155 _timeoutMs=ms;
156 }
157 }
158
159 /* ------------------------------------------------------------ */
160 public long getTimeout()
161 {
162 synchronized(this)
163 {
164 return _timeoutMs;
165 }
166 }
167
168 /* ------------------------------------------------------------ */
169 public AsyncEventState getAsyncEventState()
170 {
171 synchronized(this)
172 {
173 return _event;
174 }
175 }
176
177 /* ------------------------------------------------------------ */
178 /**
179 * @see org.eclipse.jetty.continuation.Continuation#keepWrappers()
180 */
181
182 /* ------------------------------------------------------------ */
183 /**
184 * @see org.eclipse.jetty.continuation.Continuation#isResponseWrapped()
185 */
186 public boolean isResponseWrapped()
187 {
188 return _responseWrapped;
189 }
190
191 /* ------------------------------------------------------------ */
192 /* (non-Javadoc)
193 * @see javax.servlet.ServletRequest#isInitial()
194 */
195 public boolean isInitial()
196 {
197 synchronized(this)
198 {
199 return _initial;
200 }
201 }
202
203 public boolean isContinuation()
204 {
205 return _continuation;
206 }
207
208 /* ------------------------------------------------------------ */
209 /* (non-Javadoc)
210 * @see javax.servlet.ServletRequest#isSuspended()
211 */
212 public boolean isSuspended()
213 {
214 synchronized(this)
215 {
216 switch(_state)
217 {
218 case __ASYNCSTARTED:
219 case __REDISPATCHING:
220 case __COMPLETING:
221 case __ASYNCWAIT:
222 return true;
223
224 default:
225 return false;
226 }
227 }
228 }
229
230 /* ------------------------------------------------------------ */
231 public boolean isSuspending()
232 {
233 synchronized(this)
234 {
235 switch(_state)
236 {
237 case __ASYNCSTARTED:
238 case __ASYNCWAIT:
239 return true;
240
241 default:
242 return false;
243 }
244 }
245 }
246
247 /* ------------------------------------------------------------ */
248 public boolean isDispatchable()
249 {
250 synchronized(this)
251 {
252 switch(_state)
253 {
254 case __REDISPATCH:
255 case __REDISPATCHED:
256 case __REDISPATCHING:
257 case __COMPLETING:
258 return true;
259
260 default:
261 return false;
262 }
263 }
264 }
265
266 /* ------------------------------------------------------------ */
267 @Override
268 public String toString()
269 {
270 synchronized (this)
271 {
272 return super.toString()+"@"+getStatusString();
273 }
274 }
275
276 /* ------------------------------------------------------------ */
277 public String getStatusString()
278 {
279 synchronized (this)
280 {
281 return
282 ((_state==__IDLE)?"IDLE":
283 (_state==__DISPATCHED)?"DISPATCHED":
284 (_state==__ASYNCSTARTED)?"ASYNCSTARTED":
285 (_state==__ASYNCWAIT)?"ASYNCWAIT":
286 (_state==__REDISPATCHING)?"REDISPATCHING":
287 (_state==__REDISPATCH)?"REDISPATCH":
288 (_state==__REDISPATCHED)?"REDISPATCHED":
289 (_state==__COMPLETING)?"COMPLETING":
290 (_state==__UNCOMPLETED)?"UNCOMPLETED":
291 (_state==__COMPLETED)?"COMPLETE":
292 ("UNKNOWN?"+_state))+
293 (_initial?",initial":"")+
294 (_resumed?",resumed":"")+
295 (_expired?",expired":"");
296 }
297 }
298
299 /* ------------------------------------------------------------ */
300 /**
301 * @return false if the handling of the request should not proceed
302 */
303 protected boolean handling()
304 {
305 synchronized (this)
306 {
307 _continuation=false;
308
309 switch(_state)
310 {
311 case __IDLE:
312 _initial=true;
313 _state=__DISPATCHED;
314 if (_lastAsyncListeners!=null)
315 _lastAsyncListeners.clear();
316 if (_asyncListeners!=null)
317 _asyncListeners.clear();
318 else
319 {
320 _asyncListeners=_lastAsyncListeners;
321 _lastAsyncListeners=null;
322 }
323 return true;
324
325 case __COMPLETING:
326 _state=__UNCOMPLETED;
327 return false;
328
329 case __ASYNCWAIT:
330 return false;
331
332 case __REDISPATCH:
333 _state=__REDISPATCHED;
334 return true;
335
336 default:
337 throw new IllegalStateException(this.getStatusString());
338 }
339 }
340 }
341
342 /* ------------------------------------------------------------ */
343 /* (non-Javadoc)
344 * @see javax.servlet.ServletRequest#suspend(long)
345 */
346 private void doSuspend(final ServletContext context,
347 final ServletRequest request,
348 final ServletResponse response)
349 {
350 synchronized (this)
351 {
352 switch(_state)
353 {
354 case __DISPATCHED:
355 case __REDISPATCHED:
356 _resumed=false;
357 _expired=false;
358
359 if (_event==null || request!=_event.getSuppliedRequest() || response != _event.getSuppliedResponse() || context != _event.getServletContext())
360 _event=new AsyncEventState(context,request,response);
361 else
362 {
363 _event._dispatchContext=null;
364 _event._pathInContext=null;
365 }
366 _state=__ASYNCSTARTED;
367 List<AsyncListener> recycle=_lastAsyncListeners;
368 _lastAsyncListeners=_asyncListeners;
369 _asyncListeners=recycle;
370 if (_asyncListeners!=null)
371 _asyncListeners.clear();
372 break;
373
374 default:
375 throw new IllegalStateException(this.getStatusString());
376 }
377 }
378
379 if (_lastAsyncListeners!=null)
380 {
381 for (AsyncListener listener : _lastAsyncListeners)
382 {
383 try
384 {
385 listener.onStartAsync(_event);
386 }
387 catch(Exception e)
388 {
389 LOG.warn(e);
390 }
391 }
392 }
393 }
394
395 /* ------------------------------------------------------------ */
396 /**
397 * Signal that the HttpConnection has finished handling the request.
398 * For blocking connectors, this call may block if the request has
399 * been suspended (startAsync called).
400 * @return true if handling is complete, false if the request should
401 * be handled again (eg because of a resume that happened before unhandle was called)
402 */
403 protected boolean unhandle()
404 {
405 synchronized (this)
406 {
407 switch(_state)
408 {
409 case __REDISPATCHED:
410 case __DISPATCHED:
411 _state=__UNCOMPLETED;
412 return true;
413
414 case __IDLE:
415 throw new IllegalStateException(this.getStatusString());
416
417 case __ASYNCSTARTED:
418 _initial=false;
419 _state=__ASYNCWAIT;
420 scheduleTimeout(); // could block and change state.
421 if (_state==__ASYNCWAIT)
422 return true;
423 else if (_state==__COMPLETING)
424 {
425 _state=__UNCOMPLETED;
426 return true;
427 }
428 _initial=false;
429 _state=__REDISPATCHED;
430 return false;
431
432 case __REDISPATCHING:
433 _initial=false;
434 _state=__REDISPATCHED;
435 return false;
436
437 case __COMPLETING:
438 _initial=false;
439 _state=__UNCOMPLETED;
440 return true;
441
442 default:
443 throw new IllegalStateException(this.getStatusString());
444 }
445 }
446 }
447
448 /* ------------------------------------------------------------ */
449 public void dispatch()
450 {
451 boolean dispatch=false;
452 synchronized (this)
453 {
454 switch(_state)
455 {
456 case __ASYNCSTARTED:
457 _state=__REDISPATCHING;
458 _resumed=true;
459 return;
460
461 case __ASYNCWAIT:
462 dispatch=!_expired;
463 _state=__REDISPATCH;
464 _resumed=true;
465 break;
466
467 case __REDISPATCH:
468 return;
469
470 default:
471 throw new IllegalStateException(this.getStatusString());
472 }
473 }
474
475 if (dispatch)
476 {
477 cancelTimeout();
478 scheduleDispatch();
479 }
480 }
481
482 /* ------------------------------------------------------------ */
483 protected void expired()
484 {
485 final List<ContinuationListener> cListeners;
486 final List<AsyncListener> aListeners;
487 synchronized (this)
488 {
489 switch(_state)
490 {
491 case __ASYNCSTARTED:
492 case __ASYNCWAIT:
493 cListeners=_continuationListeners;
494 aListeners=_asyncListeners;
495 break;
496 default:
497 cListeners=null;
498 aListeners=null;
499 return;
500 }
501 _expired=true;
502 }
503
504 if (aListeners!=null)
505 {
506 for (AsyncListener listener : aListeners)
507 {
508 try
509 {
510 listener.onTimeout(_event);
511 }
512 catch(Exception e)
513 {
514 LOG.debug(e);
515 _connection.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
516 break;
517 }
518 }
519 }
520 if (cListeners!=null)
521 {
522 for (ContinuationListener listener : cListeners)
523 {
524 try
525 {
526 listener.onTimeout(this);
527 }
528 catch(Exception e)
529 {
530 LOG.warn(e);
531 }
532 }
533 }
534
535 synchronized (this)
536 {
537 switch(_state)
538 {
539 case __ASYNCSTARTED:
540 case __ASYNCWAIT:
541 dispatch();
542 break;
543
544 default:
545 if (!_continuation)
546 _expired=false;
547 }
548 }
549
550 scheduleDispatch();
551 }
552
553 /* ------------------------------------------------------------ */
554 /* (non-Javadoc)
555 * @see javax.servlet.ServletRequest#complete()
556 */
557 public void complete()
558 {
559 // just like resume, except don't set _resumed=true;
560 boolean dispatch=false;
561 synchronized (this)
562 {
563 switch(_state)
564 {
565 case __DISPATCHED:
566 case __REDISPATCHED:
567 throw new IllegalStateException(this.getStatusString());
568
569 case __ASYNCSTARTED:
570 _state=__COMPLETING;
571 return;
572
573 case __ASYNCWAIT:
574 _state=__COMPLETING;
575 dispatch=!_expired;
576 break;
577
578 default:
579 throw new IllegalStateException(this.getStatusString());
580 }
581 }
582
583 if (dispatch)
584 {
585 cancelTimeout();
586 scheduleDispatch();
587 }
588 }
589
590 /* ------------------------------------------------------------ */
591 /* (non-Javadoc)
592 * @see javax.servlet.ServletRequest#complete()
593 */
594 public void errorComplete()
595 {
596 // just like complete except can overrule a prior dispatch call;
597 synchronized (this)
598 {
599 switch(_state)
600 {
601 case __REDISPATCHING:
602 case __ASYNCSTARTED:
603 _state=__COMPLETING;
604 _resumed=false;
605 return;
606
607 case __COMPLETING:
608 return;
609
610 default:
611 throw new IllegalStateException(this.getStatusString());
612 }
613 }
614 }
615
616 /* ------------------------------------------------------------ */
617 @Override
618 public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException
619 {
620 try
621 {
622 // TODO inject
623 return clazz.newInstance();
624 }
625 catch(Exception e)
626 {
627 throw new ServletException(e);
628 }
629 }
630
631
632 /* ------------------------------------------------------------ */
633 /* (non-Javadoc)
634 * @see javax.servlet.ServletRequest#complete()
635 */
636 protected void doComplete(Throwable ex)
637 {
638 final List<ContinuationListener> cListeners;
639 final List<AsyncListener> aListeners;
640 synchronized (this)
641 {
642 switch(_state)
643 {
644 case __UNCOMPLETED:
645 _state=__COMPLETED;
646 cListeners=_continuationListeners;
647 aListeners=_asyncListeners;
648 break;
649
650 default:
651 cListeners=null;
652 aListeners=null;
653 throw new IllegalStateException(this.getStatusString());
654 }
655 }
656
657 if (aListeners!=null)
658 {
659 for (AsyncListener listener : aListeners)
660 {
661 try
662 {
663 if (ex!=null)
664 {
665 _event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,ex);
666 _event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_MESSAGE,ex.getMessage());
667 listener.onError(_event);
668 }
669 else
670 listener.onComplete(_event);
671 }
672 catch(Exception e)
673 {
674 LOG.warn(e);
675 }
676 }
677 }
678 if (cListeners!=null)
679 {
680 for (ContinuationListener listener : cListeners)
681 {
682 try
683 {
684 listener.onComplete(this);
685 }
686 catch(Exception e)
687 {
688 LOG.warn(e);
689 }
690 }
691 }
692 }
693
694 /* ------------------------------------------------------------ */
695 protected void recycle()
696 {
697 synchronized (this)
698 {
699 switch(_state)
700 {
701 case __DISPATCHED:
702 case __REDISPATCHED:
703 throw new IllegalStateException(getStatusString());
704 default:
705 _state=__IDLE;
706 }
707 _initial = true;
708 _resumed=false;
709 _expired=false;
710 _responseWrapped=false;
711 cancelTimeout();
712 _timeoutMs=DEFAULT_TIMEOUT;
713 _continuationListeners=null;
714 }
715 }
716
717 /* ------------------------------------------------------------ */
718 public void cancel()
719 {
720 synchronized (this)
721 {
722 cancelTimeout();
723 _continuationListeners=null;
724 }
725 }
726
727 /* ------------------------------------------------------------ */
728 protected void scheduleDispatch()
729 {
730 EndPoint endp=_connection.getEndPoint();
731 if (!endp.isBlocking())
732 {
733 ((AsyncEndPoint)endp).asyncDispatch();
734 }
735 }
736
737 /* ------------------------------------------------------------ */
738 protected void scheduleTimeout()
739 {
740 EndPoint endp=_connection.getEndPoint();
741 if (_timeoutMs>0)
742 {
743 if (endp.isBlocking())
744 {
745 synchronized(this)
746 {
747 _expireAt = System.currentTimeMillis()+_timeoutMs;
748 long wait=_timeoutMs;
749 while (_expireAt>0 && wait>0 && _connection.getServer().isRunning())
750 {
751 try
752 {
753 this.wait(wait);
754 }
755 catch (InterruptedException e)
756 {
757 LOG.ignore(e);
758 }
759 wait=_expireAt-System.currentTimeMillis();
760 }
761
762 if (_expireAt>0 && wait<=0 && _connection.getServer().isRunning())
763 {
764 expired();
765 }
766 }
767 }
768 else
769 {
770 ((AsyncEndPoint)endp).scheduleTimeout(_event._timeout,_timeoutMs);
771 }
772 }
773 }
774
775 /* ------------------------------------------------------------ */
776 protected void cancelTimeout()
777 {
778 EndPoint endp=_connection.getEndPoint();
779 if (endp.isBlocking())
780 {
781 synchronized(this)
782 {
783 _expireAt=0;
784 this.notifyAll();
785 }
786 }
787 else
788 {
789 final AsyncEventState event=_event;
790 if (event!=null)
791 {
792 ((AsyncEndPoint)endp).cancelTimeout(event._timeout);
793 }
794 }
795 }
796
797 /* ------------------------------------------------------------ */
798 public boolean isCompleting()
799 {
800 synchronized (this)
801 {
802 return _state==__COMPLETING;
803 }
804 }
805
806 /* ------------------------------------------------------------ */
807 boolean isUncompleted()
808 {
809 synchronized (this)
810 {
811 return _state==__UNCOMPLETED;
812 }
813 }
814
815 /* ------------------------------------------------------------ */
816 public boolean isComplete()
817 {
818 synchronized (this)
819 {
820 return _state==__COMPLETED;
821 }
822 }
823
824
825 /* ------------------------------------------------------------ */
826 public boolean isAsyncStarted()
827 {
828 synchronized (this)
829 {
830 switch(_state)
831 {
832 case __ASYNCSTARTED:
833 case __REDISPATCHING:
834 case __REDISPATCH:
835 case __ASYNCWAIT:
836 return true;
837
838 default:
839 return false;
840 }
841 }
842 }
843
844
845 /* ------------------------------------------------------------ */
846 public boolean isAsync()
847 {
848 synchronized (this)
849 {
850 switch(_state)
851 {
852 case __IDLE:
853 case __DISPATCHED:
854 case __UNCOMPLETED:
855 case __COMPLETED:
856 return false;
857
858 default:
859 return true;
860 }
861 }
862 }
863
864 /* ------------------------------------------------------------ */
865 public void dispatch(ServletContext context, String path)
866 {
867 _event._dispatchContext=context;
868 _event.setPath(path);
869 dispatch();
870 }
871
872 /* ------------------------------------------------------------ */
873 public void dispatch(String path)
874 {
875 _event.setPath(path);
876 dispatch();
877 }
878
879 /* ------------------------------------------------------------ */
880 public Request getBaseRequest()
881 {
882 return _connection.getRequest();
883 }
884
885 /* ------------------------------------------------------------ */
886 public ServletRequest getRequest()
887 {
888 if (_event!=null)
889 return _event.getSuppliedRequest();
890 return _connection.getRequest();
891 }
892
893 /* ------------------------------------------------------------ */
894 public ServletResponse getResponse()
895 {
896 if (_responseWrapped && _event!=null && _event.getSuppliedResponse()!=null)
897 return _event.getSuppliedResponse();
898 return _connection.getResponse();
899 }
900
901 /* ------------------------------------------------------------ */
902 public void start(final Runnable run)
903 {
904 final AsyncEventState event=_event;
905 if (event!=null)
906 {
907 _connection.getServer().getThreadPool().dispatch(new Runnable()
908 {
909 public void run()
910 {
911 ((Context)event.getServletContext()).getContextHandler().handle(run);
912 }
913 });
914 }
915 }
916
917 /* ------------------------------------------------------------ */
918 public boolean hasOriginalRequestAndResponse()
919 {
920 synchronized (this)
921 {
922 return (_event!=null && _event.getSuppliedRequest()==_connection._request && _event.getSuppliedResponse()==_connection._response);
923 }
924 }
925
926 /* ------------------------------------------------------------ */
927 public ContextHandler getContextHandler()
928 {
929 final AsyncEventState event=_event;
930 if (event!=null)
931 return ((Context)event.getServletContext()).getContextHandler();
932 return null;
933 }
934
935
936 /* ------------------------------------------------------------ */
937 /**
938 * @see Continuation#isResumed()
939 */
940 public boolean isResumed()
941 {
942 synchronized (this)
943 {
944 return _resumed;
945 }
946 }
947 /* ------------------------------------------------------------ */
948 /**
949 * @see Continuation#isExpired()
950 */
951 public boolean isExpired()
952 {
953 synchronized (this)
954 {
955 return _expired;
956 }
957 }
958
959 /* ------------------------------------------------------------ */
960 /**
961 * @see Continuation#resume()
962 */
963 public void resume()
964 {
965 dispatch();
966 }
967
968
969
970 /* ------------------------------------------------------------ */
971 protected void startAsync(final ServletContext context,
972 final ServletRequest request,
973 final ServletResponse response)
974 {
975 synchronized (this)
976 {
977 _responseWrapped=!(response instanceof Response);
978 doSuspend(context,request,response);
979 if (request instanceof HttpServletRequest)
980 {
981 _event._pathInContext = URIUtil.addPaths(((HttpServletRequest)request).getServletPath(),((HttpServletRequest)request).getPathInfo());
982 }
983 }
984 }
985
986 /* ------------------------------------------------------------ */
987 protected void startAsync()
988 {
989 _responseWrapped=false;
990 _continuation=false;
991 doSuspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
992 }
993
994
995 /* ------------------------------------------------------------ */
996 /**
997 * @see Continuation#suspend()
998 */
999 public void suspend(ServletResponse response)
1000 {
1001 _continuation=true;
1002 _responseWrapped=!(response instanceof Response);
1003 doSuspend(_connection.getRequest().getServletContext(),_connection.getRequest(),response);
1004 }
1005
1006 /* ------------------------------------------------------------ */
1007 /**
1008 * @see Continuation#suspend()
1009 */
1010 public void suspend()
1011 {
1012 _responseWrapped=false;
1013 _continuation=true;
1014 doSuspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
1015 }
1016
1017 /* ------------------------------------------------------------ */
1018 /**
1019 * @see org.eclipse.jetty.continuation.Continuation#getServletResponse()
1020 */
1021 public ServletResponse getServletResponse()
1022 {
1023 if (_responseWrapped && _event!=null && _event.getSuppliedResponse()!=null)
1024 return _event.getSuppliedResponse();
1025 return _connection.getResponse();
1026 }
1027
1028 /* ------------------------------------------------------------ */
1029 /**
1030 * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String)
1031 */
1032 public Object getAttribute(String name)
1033 {
1034 return _connection.getRequest().getAttribute(name);
1035 }
1036
1037 /* ------------------------------------------------------------ */
1038 /**
1039 * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String)
1040 */
1041 public void removeAttribute(String name)
1042 {
1043 _connection.getRequest().removeAttribute(name);
1044 }
1045
1046 /* ------------------------------------------------------------ */
1047 /**
1048 * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object)
1049 */
1050 public void setAttribute(String name, Object attribute)
1051 {
1052 _connection.getRequest().setAttribute(name,attribute);
1053 }
1054
1055 /* ------------------------------------------------------------ */
1056 /**
1057 * @see org.eclipse.jetty.continuation.Continuation#undispatch()
1058 */
1059 public void undispatch()
1060 {
1061 if (isSuspended())
1062 {
1063 if (LOG.isDebugEnabled())
1064 throw new ContinuationThrowable();
1065 else
1066 throw __exception;
1067 }
1068 throw new IllegalStateException("!suspended");
1069 }
1070
1071 /* ------------------------------------------------------------ */
1072 /* ------------------------------------------------------------ */
1073 public class AsyncTimeout extends Timeout.Task implements Runnable
1074 {
1075 @Override
1076 public void expired()
1077 {
1078 AsyncContinuation.this.expired();
1079 }
1080
1081 @Override
1082 public void run()
1083 {
1084 AsyncContinuation.this.expired();
1085 }
1086 }
1087
1088 /* ------------------------------------------------------------ */
1089 /* ------------------------------------------------------------ */
1090 public class AsyncEventState extends AsyncEvent
1091 {
1092 private final ServletContext _suspendedContext;
1093 private ServletContext _dispatchContext;
1094 private String _pathInContext;
1095 private Timeout.Task _timeout= new AsyncTimeout();
1096
1097 public AsyncEventState(ServletContext context, ServletRequest request, ServletResponse response)
1098 {
1099 super(AsyncContinuation.this, request,response);
1100 _suspendedContext=context;
1101 // Get the base request So we can remember the initial paths
1102 Request r=_connection.getRequest();
1103
1104 // If we haven't been async dispatched before
1105 if (r.getAttribute(AsyncContext.ASYNC_REQUEST_URI)==null)
1106 {
1107 // We are setting these attributes during startAsync, when the spec implies that
1108 // they are only available after a call to AsyncContext.dispatch(...);
1109
1110 // have we been forwarded before?
1111 String uri=(String)r.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
1112 if (uri!=null)
1113 {
1114 r.setAttribute(AsyncContext.ASYNC_REQUEST_URI,uri);
1115 r.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,r.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
1116 r.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,r.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
1117 r.setAttribute(AsyncContext.ASYNC_PATH_INFO,r.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
1118 r.setAttribute(AsyncContext.ASYNC_QUERY_STRING,r.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
1119 }
1120 else
1121 {
1122 r.setAttribute(AsyncContext.ASYNC_REQUEST_URI,r.getRequestURI());
1123 r.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,r.getContextPath());
1124 r.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,r.getServletPath());
1125 r.setAttribute(AsyncContext.ASYNC_PATH_INFO,r.getPathInfo());
1126 r.setAttribute(AsyncContext.ASYNC_QUERY_STRING,r.getQueryString());
1127 }
1128 }
1129 }
1130
1131 public ServletContext getSuspendedContext()
1132 {
1133 return _suspendedContext;
1134 }
1135
1136 public ServletContext getDispatchContext()
1137 {
1138 return _dispatchContext;
1139 }
1140
1141 public ServletContext getServletContext()
1142 {
1143 return _dispatchContext==null?_suspendedContext:_dispatchContext;
1144 }
1145
1146 public void setPath(String path)
1147 {
1148 _pathInContext=path;
1149 }
1150
1151 /* ------------------------------------------------------------ */
1152 /**
1153 * @return The path in the context
1154 */
1155 public String getPath()
1156 {
1157 return _pathInContext;
1158 }
1159 }
1160 }