View Javadoc

1   package org.eclipse.jetty.continuation;
2   
3   import java.io.IOException;
4   import java.util.ArrayList;
5   import java.util.List;
6   
7   import javax.servlet.AsyncContext;
8   import javax.servlet.AsyncEvent;
9   import javax.servlet.AsyncListener;
10  import javax.servlet.DispatcherType;
11  import javax.servlet.ServletRequest;
12  import javax.servlet.ServletResponse;
13  import javax.servlet.ServletResponseWrapper;
14  
15  
16  /* ------------------------------------------------------------ */
17  /**
18   * This implementation of Continuation is used by {@link ContinuationSupport}
19   * when it detects that the application has been deployed in a non-jetty Servlet 3 
20   * server.
21   */
22  public class Servlet3Continuation implements Continuation
23  {
24      // Exception reused for all continuations
25      // Turn on debug in ContinuationFilter to see real stack trace.
26      private final static ContinuationThrowable __exception = new ContinuationThrowable();
27      
28      private final ServletRequest _request;
29      private ServletResponse _response;
30      private AsyncContext _context;
31      private List<AsyncListener> _listeners=new ArrayList<AsyncListener>(); 
32      private volatile boolean _initial=true;
33      private volatile boolean _resumed=false;
34      private volatile boolean _expired=false;
35      private volatile boolean _responseWrapped=false;
36  
37      private long _timeoutMs=-1;
38  
39      /* ------------------------------------------------------------ */
40      public Servlet3Continuation(ServletRequest request)
41      {
42          _request=request;
43  
44          _listeners.add(new AsyncListener()
45          {
46              public void onComplete(AsyncEvent event) throws IOException
47              {
48              }
49  
50              public void onError(AsyncEvent event) throws IOException
51              {
52              }
53  
54              public void onStartAsync(AsyncEvent event) throws IOException
55              {
56                  event.getAsyncContext().addListener(this);
57              }
58  
59              public void onTimeout(AsyncEvent event) throws IOException
60              {
61                  _initial=false;
62                  System.err.println("Doing dispatch on timed out continuation for "+_request.getAttribute("FOO"));
63                  event.getAsyncContext().dispatch();
64              }
65          });
66      }
67  
68      /* ------------------------------------------------------------ */
69      public void addContinuationListener(final ContinuationListener listener)
70      {
71          AsyncListener wrapped = new AsyncListener()
72          {
73              public void onComplete(final AsyncEvent event) throws IOException
74              {
75                  listener.onComplete(Servlet3Continuation.this);
76              }
77  
78              public void onError(AsyncEvent event) throws IOException
79              {
80                  listener.onComplete(Servlet3Continuation.this);
81              }
82  
83              public void onStartAsync(AsyncEvent event) throws IOException
84              {
85                  event.getAsyncContext().addListener(this);
86              }
87  
88              public void onTimeout(AsyncEvent event) throws IOException
89              {
90                  _expired=true;
91                  listener.onTimeout(Servlet3Continuation.this);
92              }
93          };
94          
95          if (_context!=null)
96              _context.addListener(wrapped);
97          else
98              _listeners.add(wrapped);
99      }
100 
101     /* ------------------------------------------------------------ */
102     public void complete()
103     {
104         AsyncContext context=_context;
105         if (context==null)
106             throw new IllegalStateException();
107         _context.complete();
108     }
109 
110     /* ------------------------------------------------------------ */
111     public ServletResponse getServletResponse()
112     {
113         return _response;
114     }
115 
116     /* ------------------------------------------------------------ */
117     public boolean isExpired()
118     {
119         return _expired;
120     }
121 
122     /* ------------------------------------------------------------ */
123     public boolean isInitial()
124     {
125         // TODO - this is not perfect if non continuation API is used directly
126         return _initial&&_request.getDispatcherType()!=DispatcherType.ASYNC;
127     }
128 
129     /* ------------------------------------------------------------ */
130     public boolean isResumed()
131     {
132         return _resumed;
133     }
134 
135     /* ------------------------------------------------------------ */
136     public boolean isSuspended()
137     {
138         return _request.isAsyncStarted();
139     }
140 
141     /* ------------------------------------------------------------ */
142     public void keepWrappers()
143     {
144         _responseWrapped=true;
145     }
146 
147     /* ------------------------------------------------------------ */
148     public void resume()
149     {
150         AsyncContext context=_context;
151         if (context==null)
152             throw new IllegalStateException();
153         _resumed=true;
154         _context.dispatch();
155     }
156 
157     /* ------------------------------------------------------------ */
158     public void setTimeout(long timeoutMs)
159     {
160         _timeoutMs=timeoutMs;
161         if (_context!=null)
162             _context.setTimeout(timeoutMs);
163     }
164 
165     /* ------------------------------------------------------------ */
166     public void suspend(ServletResponse response)
167     {
168         _response=response;
169         _responseWrapped=response instanceof ServletResponseWrapper;
170         _resumed=false;
171         _expired=false;
172         _context=_request.startAsync();
173         _context.setTimeout(_timeoutMs);
174         
175         for (AsyncListener listener:_listeners)
176             _context.addListener(listener);
177         _listeners.clear();
178     }
179 
180     /* ------------------------------------------------------------ */
181     public void suspend()
182     {
183         _resumed=false;
184         _expired=false;
185         _context=_request.startAsync();
186         _context.setTimeout(_timeoutMs);
187                 
188         for (AsyncListener listener:_listeners)
189             _context.addListener(listener);
190         _listeners.clear();
191     }
192 
193     /* ------------------------------------------------------------ */
194     public boolean isResponseWrapped()
195     {
196         return _responseWrapped;
197     }
198 
199     /* ------------------------------------------------------------ */
200     /**
201      * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String)
202      */
203     public Object getAttribute(String name)
204     {
205         return _request.getAttribute(name);
206     }
207 
208     /* ------------------------------------------------------------ */
209     /**
210      * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String)
211      */
212     public void removeAttribute(String name)
213     {
214         _request.removeAttribute(name);
215     }
216 
217     /* ------------------------------------------------------------ */
218     /**
219      * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object)
220      */
221     public void setAttribute(String name, Object attribute)
222     {
223         _request.setAttribute(name,attribute);
224     }
225 
226     /* ------------------------------------------------------------ */
227     /**
228      * @see org.eclipse.jetty.continuation.Continuation#undispatch()
229      */
230     public void undispatch()
231     {
232         if (isSuspended())
233         {
234             if (ContinuationFilter.__debug)
235                 throw new ContinuationThrowable();
236             throw __exception;
237         }
238         throw new IllegalStateException("!suspended");
239     }
240 }