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.util.ArrayList;
22  import java.util.List;
23  
24  import javax.servlet.ServletRequest;
25  import javax.servlet.ServletResponse;
26  import javax.servlet.ServletResponseWrapper;
27  
28  import org.mortbay.log.Log;
29  import org.mortbay.log.Logger;
30  
31  /* ------------------------------------------------------------ */
32  /**
33   * This implementation of Continuation is used by {@link ContinuationSupport}
34   * when it detects that the application is deployed in a jetty-6 server.
35   * This continuation requires the {@link ContinuationFilter} to be deployed.
36   */
37  public class Jetty6Continuation implements ContinuationFilter.FilteredContinuation
38  {
39      private static final Logger LOG = Log.getLogger(Jetty6Continuation.class.getName());
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 final org.mortbay.util.ajax.Continuation _j6Continuation;
48  
49      private Throwable _retry;
50      private int _timeout;
51      private boolean _initial=true;
52      private volatile boolean _completed=false;
53      private volatile boolean _resumed=false;
54      private volatile boolean _expired=false;
55      private boolean _responseWrapped=false;
56      private List<ContinuationListener> _listeners;
57  
58      public Jetty6Continuation(ServletRequest request, org.mortbay.util.ajax.Continuation continuation)
59      {
60          if (!ContinuationFilter._initialized)
61          {
62              LOG.warn("!ContinuationFilter installed",null,null);
63              throw new IllegalStateException("!ContinuationFilter installed");
64          }
65          _request=request;
66          _j6Continuation=continuation;
67      }
68  
69      public void addContinuationListener(final ContinuationListener listener)
70      {
71          if (_listeners==null)
72              _listeners=new ArrayList<ContinuationListener>();
73          _listeners.add(listener);
74      }
75  
76      public void complete()
77      {
78          synchronized(this)
79          {
80              if (_resumed)
81                  throw new IllegalStateException();
82              _completed=true;
83              if (_j6Continuation.isPending())
84                  _j6Continuation.resume();
85          }
86      }
87  
88      /* ------------------------------------------------------------ */
89      /**
90       * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String)
91       */
92      public Object getAttribute(String name)
93      {
94          return _request.getAttribute(name);
95      }
96  
97      /* ------------------------------------------------------------ */
98      /**
99       * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String)
100      */
101     public void removeAttribute(String name)
102     {
103         _request.removeAttribute(name);
104     }
105 
106     /* ------------------------------------------------------------ */
107     /**
108      * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object)
109      */
110     public void setAttribute(String name, Object attribute)
111     {
112         _request.setAttribute(name,attribute);
113     }
114 
115     /* ------------------------------------------------------------ */
116     public ServletResponse getServletResponse()
117     {
118         return _response;
119     }
120 
121     /* ------------------------------------------------------------ */
122     public boolean isExpired()
123     {
124         return _expired;
125     }
126 
127     /* ------------------------------------------------------------ */
128     public boolean isInitial()
129     {
130         return _initial;
131     }
132 
133     /* ------------------------------------------------------------ */
134     public boolean isResumed()
135     {
136         return _resumed;
137     }
138 
139     /* ------------------------------------------------------------ */
140     public boolean isSuspended()
141     {
142         return _retry!=null;
143     }
144 
145     /* ------------------------------------------------------------ */
146     public void resume()
147     {
148         synchronized(this)
149         {
150             if (_completed)
151                 throw new IllegalStateException();
152             _resumed=true;
153             if (_j6Continuation.isPending())
154                 _j6Continuation.resume();
155         }
156     }
157 
158     /* ------------------------------------------------------------ */
159     public void setTimeout(long timeoutMs)
160     {
161         _timeout=(timeoutMs>Integer.MAX_VALUE)?Integer.MAX_VALUE:(int)timeoutMs;
162     }
163 
164     /* ------------------------------------------------------------ */
165     /**
166      * @see org.eclipse.jetty.continuation.Continuation#suspend(javax.servlet.ServletResponse)
167      */
168     public void suspend(ServletResponse response)
169     {
170         try
171         {
172             _response=response;
173             _responseWrapped=_response instanceof ServletResponseWrapper;
174             _resumed=false;
175             _expired=false;
176             _completed=false;
177             _j6Continuation.suspend(_timeout);
178         }
179         catch(Throwable retry)
180         {
181             _retry=retry;
182         }
183     }
184 
185     /* ------------------------------------------------------------ */
186     public void suspend()
187     {
188         try
189         {
190             _response=null;
191             _responseWrapped=false;
192             _resumed=false;
193             _expired=false;
194             _completed=false;
195             _j6Continuation.suspend(_timeout);
196         }
197         catch(Throwable retry)
198         {
199             _retry=retry;
200         }
201     }
202 
203     /* ------------------------------------------------------------ */
204     public boolean isResponseWrapped()
205     {
206         return _responseWrapped;
207     }
208 
209     /* ------------------------------------------------------------ */
210     /**
211      * @see org.eclipse.jetty.continuation.Continuation#undispatch()
212      */
213     public void undispatch()
214     {
215         if (isSuspended())
216         {
217             if (ContinuationFilter.__debug)
218                 throw new ContinuationThrowable();
219             throw __exception;
220         }
221         throw new IllegalStateException("!suspended");
222     }
223 
224     /* ------------------------------------------------------------ */
225     public boolean enter(ServletResponse response)
226     {
227         _response=response;
228         _expired=!_j6Continuation.isResumed();
229 
230         if (_initial)
231             return true;
232 
233         _j6Continuation.reset();
234 
235         if (_expired)
236         {
237             if (_listeners!=null)
238             {
239                 for (ContinuationListener l: _listeners)
240                     l.onTimeout(this);
241             }
242         }
243 
244         return !_completed;
245     }
246 
247     /* ------------------------------------------------------------ */
248     public boolean exit()
249     {
250         _initial=false;
251 
252         Throwable th=_retry;
253         _retry=null;
254         if (th instanceof Error)
255             throw (Error)th;
256         if (th instanceof RuntimeException)
257             throw (RuntimeException)th;
258 
259         if (_listeners!=null)
260         {
261             for (ContinuationListener l: _listeners)
262                 l.onComplete(this);
263         }
264 
265         return true;
266     }
267 }