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 19package org.eclipse.jetty.continuation; 20 21import java.io.IOException; 22 23import javax.servlet.Filter; 24import javax.servlet.FilterChain; 25import javax.servlet.FilterConfig; 26import javax.servlet.ServletContext; 27import javax.servlet.ServletException; 28import javax.servlet.ServletRequest; 29import 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 */ 53public 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} 175