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 final 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              @Override
65              public void onComplete(AsyncEvent event) throws IOException
66              {
67              }
68  
69              @Override
70              public void onError(AsyncEvent event) throws IOException
71              {
72              }
73  
74              @Override
75              public void onStartAsync(AsyncEvent event) throws IOException
76              {
77                  event.getAsyncContext().addListener(this);
78              }
79  
80              @Override
81              public void onTimeout(AsyncEvent event) throws IOException
82              {
83                  _initial=false;
84                  event.getAsyncContext().dispatch();
85              }
86          });
87      }
88  
89      /* ------------------------------------------------------------ */
90      @Override
91      public void addContinuationListener(final ContinuationListener listener)
92      {
93          AsyncListener wrapped = new AsyncListener()
94          {
95              @Override
96              public void onComplete(final AsyncEvent event) throws IOException
97              {
98                  listener.onComplete(Servlet3Continuation.this);
99              }
100 
101             @Override
102             public void onError(AsyncEvent event) throws IOException
103             {
104                 listener.onComplete(Servlet3Continuation.this);
105             }
106 
107             @Override
108             public void onStartAsync(AsyncEvent event) throws IOException
109             {
110                 event.getAsyncContext().addListener(this);
111             }
112 
113             @Override
114             public void onTimeout(AsyncEvent event) throws IOException
115             {
116                 _expired=true;
117                 listener.onTimeout(Servlet3Continuation.this);
118             }
119         };
120 
121         if (_context!=null)
122             _context.addListener(wrapped);
123         else
124             _listeners.add(wrapped);
125     }
126 
127     /* ------------------------------------------------------------ */
128     @Override
129     public void complete()
130     {
131         AsyncContext context=_context;
132         if (context==null)
133             throw new IllegalStateException();
134         _context.complete();
135     }
136 
137     /* ------------------------------------------------------------ */
138     @Override
139     public ServletResponse getServletResponse()
140     {
141         return _response;
142     }
143 
144     /* ------------------------------------------------------------ */
145     @Override
146     public boolean isExpired()
147     {
148         return _expired;
149     }
150 
151     /* ------------------------------------------------------------ */
152     @Override
153     public boolean isInitial()
154     {
155         return _initial&&_request.getDispatcherType()!=DispatcherType.ASYNC;
156     }
157 
158     /* ------------------------------------------------------------ */
159     @Override
160     public boolean isResumed()
161     {
162         return _resumed;
163     }
164 
165     /* ------------------------------------------------------------ */
166     @Override
167     public boolean isSuspended()
168     {
169         return _request.isAsyncStarted();
170     }
171 
172     /* ------------------------------------------------------------ */
173     public void keepWrappers()
174     {
175         _responseWrapped=true;
176     }
177 
178     /* ------------------------------------------------------------ */
179     @Override
180     public void resume()
181     {
182         AsyncContext context=_context;
183         if (context==null)
184             throw new IllegalStateException();
185         _resumed=true;
186         _context.dispatch();
187     }
188 
189     /* ------------------------------------------------------------ */
190     @Override
191     public void setTimeout(long timeoutMs)
192     {
193         _timeoutMs=timeoutMs;
194         if (_context!=null)
195             _context.setTimeout(timeoutMs);
196     }
197 
198     /* ------------------------------------------------------------ */
199     @Override
200     public void suspend(ServletResponse response)
201     {
202         _response=response;
203         _responseWrapped=response instanceof ServletResponseWrapper;
204         _resumed=false;
205         _expired=false;
206         _context=_request.startAsync();
207         _context.setTimeout(_timeoutMs);
208 
209         for (AsyncListener listener:_listeners)
210             _context.addListener(listener);
211         _listeners.clear();
212     }
213 
214     /* ------------------------------------------------------------ */
215     @Override
216     public void suspend()
217     {
218         _resumed=false;
219         _expired=false;
220         _context=_request.startAsync();
221         _context.setTimeout(_timeoutMs);
222 
223         for (AsyncListener listener:_listeners)
224             _context.addListener(listener);
225         _listeners.clear();
226     }
227 
228     /* ------------------------------------------------------------ */
229     @Override
230     public boolean isResponseWrapped()
231     {
232         return _responseWrapped;
233     }
234 
235     /* ------------------------------------------------------------ */
236     /**
237      * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String)
238      */
239     @Override
240     public Object getAttribute(String name)
241     {
242         return _request.getAttribute(name);
243     }
244 
245     /* ------------------------------------------------------------ */
246     /**
247      * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String)
248      */
249     @Override
250     public void removeAttribute(String name)
251     {
252         _request.removeAttribute(name);
253     }
254 
255     /* ------------------------------------------------------------ */
256     /**
257      * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object)
258      */
259     @Override
260     public void setAttribute(String name, Object attribute)
261     {
262         _request.setAttribute(name,attribute);
263     }
264 
265     /* ------------------------------------------------------------ */
266     /**
267      * @see org.eclipse.jetty.continuation.Continuation#undispatch()
268      */
269     @Override
270     public void undispatch()
271     {
272         if (isSuspended())
273         {
274             if (ContinuationFilter.__debug)
275                 throw new ContinuationThrowable();
276             throw __exception;
277         }
278         throw new IllegalStateException("!suspended");
279     }
280 }