FELIX-4798 : Support async servlets (filters)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1661820 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
index 906426d..8750079 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
@@ -34,6 +34,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.servlet.AsyncContext;
 import javax.servlet.DispatcherType;
 import javax.servlet.FilterChain;
 import javax.servlet.RequestDispatcher;
@@ -91,7 +92,8 @@
 
             try
             {
-                ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.handler.getContext(), this.requestInfo, DispatcherType.FORWARD, this.handler.getContextServiceId());
+                ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.handler.getContext(), this.requestInfo, DispatcherType.FORWARD, this.handler.getContextServiceId(),
+                        handler.getServletInfo().isAsyncSupported());
                 Dispatcher.this.forward(this.handler, req, (HttpServletResponse) response);
             }
             finally
@@ -109,7 +111,8 @@
         @Override
         public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
         {
-            ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.handler.getContext(), this.requestInfo, DispatcherType.INCLUDE, this.handler.getContextServiceId());
+            ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.handler.getContext(), this.requestInfo, DispatcherType.INCLUDE,
+                    this.handler.getContextServiceId(), handler.getServletInfo().isAsyncSupported());
             Dispatcher.this.include(this.handler, req, (HttpServletResponse) response);
         }
     }
@@ -205,7 +208,8 @@
 
                                 final FilterHandler[] filterHandlers = handlerRegistry.getFilterHandlers(errorHandler, DispatcherType.ERROR, request.getRequestURI());
 
-                                invokeChain(filterHandlers, errorHandler, new ServletRequestWrapper(request, errorHandler.getContext(), requestInfo, this.serviceId), this);
+                                // TODO - is async = false correct?
+                                invokeChain(filterHandlers, errorHandler, new ServletRequestWrapper(request, errorHandler.getContext(), requestInfo, this.serviceId, false), this);
 
                                 invokeSuper = false;
                             }
@@ -239,17 +243,20 @@
         private final RequestInfo requestInfo;
         private final ExtServletContext servletContext;
         private final Long contextId;
+        private final boolean asyncSupported;
 
-        public ServletRequestWrapper(HttpServletRequest req, ExtServletContext servletContext, RequestInfo requestInfo, final Long contextId)
+        public ServletRequestWrapper(HttpServletRequest req, ExtServletContext servletContext, RequestInfo requestInfo, final Long contextId,
+                final boolean asyncSupported)
         {
-            this(req, servletContext, requestInfo, null /* type */, contextId);
+            this(req, servletContext, requestInfo, null /* type */, contextId, asyncSupported);
         }
 
         public ServletRequestWrapper(HttpServletRequest req, ExtServletContext servletContext, RequestInfo requestInfo,
-                DispatcherType type, final Long contextId)
+                DispatcherType type, final Long contextId, final boolean asyncSupported)
         {
             super(req);
 
+            this.asyncSupported = asyncSupported;
             this.servletContext = servletContext;
             this.requestInfo = requestInfo;
             this.type = type;
@@ -497,6 +504,33 @@
         {
             return (DispatcherType.INCLUDE == this.type) && (this.requestInfo != null);
         }
+
+        @Override
+        public AsyncContext startAsync() throws IllegalStateException
+        {
+            if ( !this.asyncSupported )
+            {
+                throw new IllegalStateException();
+            }
+            return super.startAsync();
+        }
+
+        @Override
+        public AsyncContext startAsync(final ServletRequest servletRequest,
+                final ServletResponse servletResponse) throws IllegalStateException
+        {
+            if ( !this.asyncSupported )
+            {
+                throw new IllegalStateException();
+            }
+            return super.startAsync(servletRequest, servletResponse);
+        }
+
+        @Override
+        public boolean isAsyncSupported()
+        {
+            return this.asyncSupported;
+        }
     }
 
     private static class RequestInfo
@@ -586,7 +620,8 @@
         ExtServletContext servletContext = (servletHandler != null) ? servletHandler.getContext() : null;
         final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
 
-        final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo, servletHandler.getContextServiceId());
+        final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo, servletHandler.getContextServiceId(),
+                servletHandler.getServletInfo().isAsyncSupported());
         final FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, req.getDispatcherType(), requestURI);
 
         try
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
index f0f0404..560234d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
@@ -117,7 +117,7 @@
             this.patterns = new String[] {pattern, pattern + "/*"};
         }
         this.initParams = initParams;
-        this.asyncSupported = false;
+        this.asyncSupported = true;
         this.errorPage = null;
     }
 
diff --git a/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java b/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
index 81a9055..fa6a1bd 100644
--- a/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
+++ b/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
@@ -247,7 +247,9 @@
             configureSessionManager(context);
             context.addEventListener(eventDispatcher);
             context.getSessionHandler().addEventListener(eventDispatcher);
-            context.addServlet(new ServletHolder(this.dispatcher), "/*");
+            final ServletHolder holder = new ServletHolder(this.dispatcher);
+            holder.setAsyncSupported(true);
+            context.addServlet(holder, "/*");
             context.setMaxFormContentSize(this.config.getMaxFormSize());
 
             if (this.config.isRegisterMBeans())