View Javadoc

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