View Javadoc

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