View Javadoc

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