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  
23  import javax.servlet.Filter;
24  import javax.servlet.FilterChain;
25  import javax.servlet.FilterConfig;
26  import javax.servlet.ServletContext;
27  import javax.servlet.ServletException;
28  import javax.servlet.ServletRequest;
29  import javax.servlet.ServletResponse;
30  
31  
32  
33  /* ------------------------------------------------------------ */
34  /**
35   * <p>ContinuationFilter must be applied to servlet paths that make use of
36   * the asynchronous features provided by {@link Continuation} APIs, but that
37   * are deployed in servlet containers that are neither Jetty (>= 7) nor a
38   * compliant Servlet 3.0 container.</p>
39   * <p>The following init parameters may be used to configure the filter (these are mostly for testing):</p>
40   * <dl>
41   * <dt>debug</dt><dd>Boolean controlling debug output</dd>
42   * <dt>jetty6</dt><dd>Boolean to force use of Jetty 6 continuations</dd>
43   * <dt>faux</dt><dd>Boolean to force use of faux continuations</dd>
44   * </dl>
45   * <p>If the servlet container is not Jetty (either 6 or 7) nor a Servlet 3
46   * container, then "faux" continuations will be used.</p>
47   * <p>Faux continuations will just put the thread that called {@link Continuation#suspend()}
48   * in wait, and will notify that thread when {@link Continuation#resume()} or
49   * {@link Continuation#complete()} is called.</p>
50   * <p>Faux continuations are not threadless continuations (they are "faux" - fake - for this reason)
51   * and as such they will scale less than proper continuations.</p>
52   */
53  public class ContinuationFilter implements Filter
54  {
55      static boolean _initialized;
56      static boolean __debug; // shared debug status
57      private boolean _faux;
58      private boolean _jetty6;
59      private boolean _filtered;
60      ServletContext _context;
61      private boolean _debug;
62  
63      public void init(FilterConfig filterConfig) throws ServletException
64      {
65          boolean jetty_7_or_greater="org.eclipse.jetty.servlet".equals(filterConfig.getClass().getPackage().getName());
66          _context = filterConfig.getServletContext();
67  
68          String param=filterConfig.getInitParameter("debug");
69          _debug=param!=null&&Boolean.parseBoolean(param);
70          if (_debug)
71              __debug=true;
72  
73          param=filterConfig.getInitParameter("jetty6");
74          if (param==null)
75              param=filterConfig.getInitParameter("partial");
76          if (param!=null)
77              _jetty6=Boolean.parseBoolean(param);
78          else
79              _jetty6=ContinuationSupport.__jetty6 && !jetty_7_or_greater;
80  
81          param=filterConfig.getInitParameter("faux");
82          if (param!=null)
83              _faux=Boolean.parseBoolean(param);
84          else
85              _faux=!(jetty_7_or_greater || _jetty6 || _context.getMajorVersion()>=3);
86  
87          _filtered=_faux||_jetty6;
88          if (_debug)
89              _context.log("ContinuationFilter "+
90                      " jetty="+jetty_7_or_greater+
91                      " jetty6="+_jetty6+
92                      " faux="+_faux+
93                      " filtered="+_filtered+
94                      " servlet3="+ContinuationSupport.__servlet3);
95          _initialized=true;
96      }
97  
98      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
99      {
100         if (_filtered)
101         {
102             Continuation c = (Continuation) request.getAttribute(Continuation.ATTRIBUTE);
103             FilteredContinuation fc;
104             if (_faux && (c==null || !(c instanceof FauxContinuation)))
105             {
106                 fc = new FauxContinuation(request);
107                 request.setAttribute(Continuation.ATTRIBUTE,fc);
108             }
109             else
110                 fc=(FilteredContinuation)c;
111 
112             boolean complete=false;
113             while (!complete)
114             {
115                 try
116                 {
117                     if (fc==null || (fc).enter(response))
118                         chain.doFilter(request,response);
119                 }
120                 catch (ContinuationThrowable e)
121                 {
122                     debug("faux",e);
123                 }
124                 finally
125                 {
126                     if (fc==null)
127                         fc = (FilteredContinuation) request.getAttribute(Continuation.ATTRIBUTE);
128 
129                     complete=fc==null || (fc).exit();
130                 }
131             }
132         }
133         else
134         {
135             try
136             {
137                 chain.doFilter(request,response);
138             }
139             catch (ContinuationThrowable e)
140             {
141                 debug("caught",e);
142             }
143         }
144     }
145 
146     private void debug(String string)
147     {
148         if (_debug)
149         {
150             _context.log(string);
151         }
152     }
153 
154     private void debug(String string, Throwable th)
155     {
156         if (_debug)
157         {
158             if (th instanceof ContinuationThrowable)
159                 _context.log(string+":"+th);
160             else
161                 _context.log(string,th);
162         }
163     }
164 
165     public void destroy()
166     {
167     }
168 
169     public interface FilteredContinuation extends Continuation
170     {
171         boolean enter(ServletResponse response);
172         boolean exit();
173     }
174 }