View Javadoc

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