You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/04/22 08:29:59 UTC

[1/2] camel git commit: CAMEL-6707: fix issues reported by @davsclaus

Repository: camel
Updated Branches:
  refs/heads/master 2bd185e92 -> e6da66a69


CAMEL-6707: fix issues reported by @davsclaus


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e6da66a6
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e6da66a6
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e6da66a6

Branch: refs/heads/master
Commit: e6da66a69840d8aa5ab1926974a92b779f90c868
Parents: 6a1f84e
Author: Arnaud Deprez <ar...@lampiris.be>
Authored: Thu Apr 21 22:13:03 2016 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Apr 22 07:44:45 2016 +0200

----------------------------------------------------------------------
 .../websocket/CamelWebSocketServlet.java        |  8 +--
 .../apache/camel/http/common/CamelServlet.java  | 53 +++++++-------
 .../camel/http/common/DefaultHttpBinding.java   | 62 ++++++++++------
 .../camel/http/common/HttpCommonComponent.java  |  1 +
 .../camel/http/common/HttpCommonEndpoint.java   | 16 +++--
 .../jetty/CamelContinuationServlet.java         | 23 +++---
 .../component/jetty/JettyHttpComponent.java     | 76 ++++++++++++++------
 .../jetty/ExplicitJettyAsyncRouteTest.java      |  2 +-
 ...pHttpMessageFormUrlEncodedFalseBodyTest.java |  6 +-
 .../component/jetty/HttpBridgeRouteTest.java    |  4 +-
 .../component/jetty/HttpsAsyncRouteTest.java    | 16 ++---
 .../camel/component/jetty/HttpsRouteTest.java   | 20 +++---
 .../component/servlet/ServletComponent.java     | 17 ++---
 .../component/servlet/ServletEndpoint.java      |  6 +-
 .../servlet/ServletAsyncArquillianTest.java     | 72 +++++++++++--------
 15 files changed, 227 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
index 2a84a73..9ddb21a 100644
--- a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
+++ b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
@@ -16,14 +16,14 @@
  */
 package org.apache.camel.component.atmosphere.websocket;
 
-import org.apache.camel.component.servlet.CamelHttpTransportServlet;
-import org.apache.camel.http.common.HttpConsumer;
-
+import java.io.IOException;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
+
+import org.apache.camel.component.servlet.CamelHttpTransportServlet;
+import org.apache.camel.http.common.HttpConsumer;
 
 /**
  * This servlet is used to add some websocket specific handling at the moment.

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
index 382a6a4..ed94745 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
@@ -16,6 +16,18 @@
  */
 package org.apache.camel.http.common;
 
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.RuntimeCamelException;
@@ -24,25 +36,12 @@ import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.servlet.AsyncContext;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
 /**
  * A servlet to use as a Camel route as entry.
  */
 public class CamelServlet extends HttpServlet {
-    private static final long serialVersionUID = -7061982839117697829L;
     public static final String ASYNC_PARAM = "async";
+    private static final long serialVersionUID = -7061982839117697829L;
     protected final Logger log = LoggerFactory.getLogger(getClass());
     
     /**
@@ -50,7 +49,7 @@ public class CamelServlet extends HttpServlet {
      *  sure that it is already set via the init method
      */
     private String servletName;
-    private boolean async = false;
+    private boolean async;
 
     private ServletResolveConsumerStrategy servletResolveConsumerStrategy = new HttpServletResolveConsumerStrategy();
     private final ConcurrentMap<String, HttpConsumer> consumers = new ConcurrentHashMap<String, HttpConsumer>();
@@ -59,9 +58,9 @@ public class CamelServlet extends HttpServlet {
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
         this.servletName = config.getServletName();
-        this.async = Optional.ofNullable(config.getInitParameter(ASYNC_PARAM))
-            .map(ObjectHelper::toBoolean)
-            .orElse(Boolean.FALSE);
+
+        final String asyncParam = config.getInitParameter(ASYNC_PARAM);
+        this.async = asyncParam == null ? false : ObjectHelper.toBoolean(asyncParam);
         log.trace("servlet '{}' initialized with: async={}", new Object[]{servletName, async});
     }
 
@@ -71,13 +70,12 @@ public class CamelServlet extends HttpServlet {
             final AsyncContext context = req.startAsync();
             //run async
             context.start(() -> doServiceAsync(context));
-        }
-        else {
+        } else {
             doService(req, resp);
         }
     }
 
-	/**
+    /**
      * This is used to handle request asynchronously
      * @param context the {@link AsyncContext}
      */
@@ -86,25 +84,22 @@ public class CamelServlet extends HttpServlet {
         final HttpServletResponse response = (HttpServletResponse) context.getResponse();
         try {
             doService(request, response);
-        }
-        //An error shouldn't occur as we should handle most of error in doService
-        catch (Exception e) {
+        } catch (Exception e) {
+            //An error shouldn't occur as we should handle most of error in doService
             log.error("Error processing request", e);
             try {
                 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            }
-            catch (Exception e1) {
+            } catch (Exception e1) {
                 log.debug("Cannot send reply to client!", e1);
             }
             //Need to wrap it in RuntimeException as it occurs in a Runnable
             throw new RuntimeCamelException(e);
-        }
-        finally {
+        } finally {
             context.complete();
         }
     }
 
-	/**
+    /**
      * This is the logical implementation to handle request with {@link CamelServlet}
      * This is where most exceptions should be handled
      *

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
index 1f190fe..828d90c 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
@@ -16,7 +16,34 @@
  */
 package org.apache.camel.http.common;
 
-import org.apache.camel.*;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import javax.activation.DataHandler;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.StreamCache;
 import org.apache.camel.converter.stream.CachedOutputStream;
 import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.util.GZIPHelper;
@@ -26,15 +53,6 @@ import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.activation.DataHandler;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.*;
-import java.net.URLDecoder;
-import java.text.SimpleDateFormat;
-import java.util.*;
-
 /**
  * Binding between {@link HttpMessage} and {@link HttpServletResponse}.
  * <p/>
@@ -92,11 +110,11 @@ public class DefaultHttpBinding implements HttpBinding {
             readHeaders(request, message);
         }
         if (mapHttpMessageFormUrlEncodedBody) {
-        	try {
-				readFormUrlEncodedBody(request, message);
-			} catch (UnsupportedEncodingException e) {
-	            throw new RuntimeCamelException("Cannot read Form URL encoded body due " + e.getMessage(), e);
-			}
+            try {
+                readFormUrlEncodedBody(request, message);
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeCamelException("Cannot read Form URL encoded body due " + e.getMessage(), e);
+            }
         }
 
         // populate the headers from the request
@@ -212,9 +230,9 @@ public class DefaultHttpBinding implements HttpBinding {
         }
     }
 
-	protected void readFormUrlEncodedBody(HttpServletRequest request, HttpMessage message) throws UnsupportedEncodingException {
+    protected void readFormUrlEncodedBody(HttpServletRequest request, HttpMessage message) throws UnsupportedEncodingException {
         LOG.trace("readFormUrlEncodedBody {}", request);
-		// should we extract key=value pairs from form bodies (application/x-www-form-urlencoded)
+        // should we extract key=value pairs from form bodies (application/x-www-form-urlencoded)
         // and map those to Camel headers
         if (mapHttpMessageBody && mapHttpMessageHeaders) {
             LOG.trace("HTTP method {} with Content-Type {}", request.getMethod(), request.getContentType());
@@ -260,16 +278,16 @@ public class DefaultHttpBinding implements HttpBinding {
                 }
             }
         }
-	}
+    }
 
     private String getRawPath(HttpServletRequest request) {
         String uri = request.getRequestURI();
-		/**
+        /**
          * In async case, it seems that request.getContextPath() can return null
          * @see https://dev.eclipse.org/mhonarc/lists/jetty-users/msg04669.html
          */
-        String contextPath = Optional.ofNullable(request.getContextPath()).orElse("");
-        String servletPath = Optional.ofNullable(request.getServletPath()).orElse("");
+        String contextPath = request.getContextPath() == null ? "" : request.getContextPath();
+        String servletPath = request.getServletPath() == null ? "" : request.getServletPath();
         return uri.substring(contextPath.length() + servletPath.length());
     }
 
@@ -619,7 +637,7 @@ public class DefaultHttpBinding implements HttpBinding {
         this.mapHttpMessageFormUrlEncodedBody = mapHttpMessageFormUrlEncodedBody;
     }
 
-	protected static SimpleDateFormat getHttpDateFormat() {
+    protected static SimpleDateFormat getHttpDateFormat() {
         SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
         dateFormat.setTimeZone(TIME_ZONE_GMT);
         return dateFormat;

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
index a99472e..189c269 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
@@ -86,4 +86,5 @@ public abstract class HttpCommonComponent extends HeaderFilterStrategyComponent
     public void setAllowJavaSerializedObject(boolean allowJavaSerializedObject) {
         this.allowJavaSerializedObject = allowJavaSerializedObject;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
index 9007322..99f03ea 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
@@ -16,12 +16,16 @@
  */
 package org.apache.camel.http.common;
 
-import org.apache.camel.impl.DefaultEndpoint;
-import org.apache.camel.spi.*;
-
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.HeaderFilterStrategyAware;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+
 public abstract class HttpCommonEndpoint extends DefaultEndpoint implements HeaderFilterStrategyAware {
 
     // Note: all options must be documented with description in annotations so extended components can access the documentation
@@ -43,9 +47,9 @@ public abstract class HttpCommonEndpoint extends DefaultEndpoint implements Head
                     + " You may also set the option throwExceptionOnFailure to be false to let the HttpProducer send all the fault response back.")
     boolean bridgeEndpoint;
     @UriParam(label = "producer",
-            description = "If the option is true, HttpProducer will set the Host header to the value contained in the current exchange Host header, " +
-                    "useful in reverse proxy applications where you want the Host header received by the downstream server to reflect the URL called by the upstream client, " +
-                    "this allows applications which use the Host header to generate accurate URL's for a proxied service")
+            description = "If the option is true, HttpProducer will set the Host header to the value contained in the current exchange Host header, "
+                + "useful in reverse proxy applications where you want the Host header received by the downstream server to reflect the URL called by the upstream client, "
+                + "this allows applications which use the Host header to generate accurate URL's for a proxied service")
     boolean preserveHostHeader;
     @UriParam(label = "consumer",
             description = "Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found.")

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
index d9abfe2..f1299f4 100644
--- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
+++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
@@ -16,24 +16,29 @@
  */
 package org.apache.camel.component.jetty;
 
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
-import org.apache.camel.http.common.*;
+import org.apache.camel.http.common.CamelServlet;
+import org.apache.camel.http.common.HttpCommonEndpoint;
+import org.apache.camel.http.common.HttpConstants;
+import org.apache.camel.http.common.HttpConsumer;
+import org.apache.camel.http.common.HttpHelper;
+import org.apache.camel.http.common.HttpMessage;
 import org.apache.camel.impl.DefaultExchange;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.eclipse.jetty.continuation.Continuation;
 import org.eclipse.jetty.continuation.ContinuationSupport;
 
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
 /**
  * Servlet which leverage <a href="http://wiki.eclipse.org/Jetty/Feature/Continuations">Jetty Continuations</a>.
  *

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
index 828514b..7b3e7bf 100644
--- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
+++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
@@ -16,16 +16,61 @@
  */
 package org.apache.camel.component.jetty;
 
-import org.apache.camel.*;
-import org.apache.camel.http.common.*;
-import org.apache.camel.spi.*;
-import org.apache.camel.util.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import javax.management.MBeanServer;
+import javax.servlet.Filter;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Consumer;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.http.common.CamelServlet;
+import org.apache.camel.http.common.HttpBinding;
+import org.apache.camel.http.common.HttpCommonComponent;
+import org.apache.camel.http.common.HttpCommonEndpoint;
+import org.apache.camel.http.common.HttpConfiguration;
+import org.apache.camel.http.common.HttpConsumer;
+import org.apache.camel.http.common.HttpRestServletResolveConsumerStrategy;
+import org.apache.camel.http.common.UrlRewrite;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.ManagementAgent;
+import org.apache.camel.spi.ManagementStrategy;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.RestApiConsumerFactory;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.RestConsumerFactory;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.HostUtils;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
+import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.apache.camel.util.jsse.SSLContextParameters;
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.jmx.MBeanContainer;
-import org.eclipse.jetty.server.*;
+import org.eclipse.jetty.server.AbstractConnector;
+import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 import org.eclipse.jetty.server.handler.ErrorHandler;
 import org.eclipse.jetty.server.handler.HandlerCollection;
@@ -43,21 +88,6 @@ import org.eclipse.jetty.util.thread.ThreadPool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.management.MBeanServer;
-import javax.servlet.Filter;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-import java.io.IOException;
-import java.io.Writer;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.util.*;
-
 /**
  * An HttpComponent which starts an embedded Jetty for to handle consuming from
  * the http endpoints.
@@ -152,7 +182,7 @@ public abstract class JettyHttpComponent extends HttpCommonComponent implements
         Integer httpClientMinThreads = getAndRemoveParameter(parameters, "httpClientMinThreads", Integer.class, this.httpClientMinThreads);
         Integer httpClientMaxThreads = getAndRemoveParameter(parameters, "httpClientMaxThreads", Integer.class, this.httpClientMaxThreads);
         HttpClient httpClient = resolveAndRemoveReferenceParameter(parameters, "httpClient", HttpClient.class);
-        Optional<Boolean> async = Optional.ofNullable(getAndRemoveParameter(parameters, "async", Boolean.class));
+        Boolean async = getAndRemoveParameter(parameters, "async", Boolean.class);
 
         // extract httpClient. parameters
         Map<String, Object> httpClientParameters = IntrospectionSupport.extractProperties(parameters, "httpClient.");
@@ -174,7 +204,9 @@ public abstract class JettyHttpComponent extends HttpCommonComponent implements
         endpointUri = new URI(scheme + ":" + endpointUri);
 
         JettyHttpEndpoint endpoint = createEndpoint(endpointUri, httpUri);
-        async.ifPresent(endpoint::setAsync);
+        if (async != null) {
+            endpoint.setAsync(async);
+        }
 
         if (headerFilterStrategy != null) {
             endpoint.setHeaderFilterStrategy(headerFilterStrategy);

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java
index 63fba47..8b36461 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java
@@ -16,12 +16,12 @@
  */
 package org.apache.camel.component.jetty;
 
+import javax.servlet.http.HttpServletRequest;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.Test;
 
-import javax.servlet.http.HttpServletRequest;
 
 /**
  * Unit test for wiki demonstration.

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBindingMapHttpMessageFormUrlEncodedFalseBodyTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBindingMapHttpMessageFormUrlEncodedFalseBodyTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBindingMapHttpMessageFormUrlEncodedFalseBodyTest.java
index 0a99d9b..8f3df8d 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBindingMapHttpMessageFormUrlEncodedFalseBodyTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBindingMapHttpMessageFormUrlEncodedFalseBodyTest.java
@@ -29,9 +29,9 @@ public class HttpBindingMapHttpMessageFormUrlEncodedFalseBodyTest extends BaseJe
     
     @Test
     public void testSendToJetty() throws Exception {
-    	Map<String,Object> map = new HashMap<String,Object>();
-    	map.put("content-type", "application/x-www-form-urlencoded");
-    	map.put(Exchange.HTTP_METHOD, HttpMethods.POST);
+        Map<String, Object> map = new HashMap<>();
+        map.put("content-type", "application/x-www-form-urlencoded");
+        map.put(Exchange.HTTP_METHOD, HttpMethods.POST);
         template.requestBodyAndHeaders("http://localhost:{{port}}/myapp/myservice?query1=a&query2=b", "b1=x&b2=y", map);
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
index edfbd3a..6b9cf2a 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
@@ -16,14 +16,14 @@
  */
 package org.apache.camel.component.jetty;
 
+import java.io.ByteArrayInputStream;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.Test;
 
-import java.io.ByteArrayInputStream;
-
 public class HttpBridgeRouteTest extends BaseJettyTest {
 
     protected int port1;

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java
index 6e3041b..a9e986e 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java
@@ -16,6 +16,14 @@
  */
 package org.apache.camel.component.jetty;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
@@ -27,14 +35,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.SocketException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
 
 public class HttpsAsyncRouteTest extends HttpsRouteTest {
 

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
index 9a3e04b..3403897 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
@@ -16,6 +16,16 @@
  */
 package org.apache.camel.component.jetty;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
@@ -28,16 +38,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.SocketException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
 public class HttpsRouteTest extends BaseJettyTest {
 
     public static final String NULL_VALUE_MARKER = CamelTestSupport.class.getCanonicalName();

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
index 2a16ebf..161c275 100644
--- a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
+++ b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
@@ -16,6 +16,11 @@
  */
 package org.apache.camel.component.servlet;
 
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
@@ -32,12 +37,6 @@ import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.URISupport;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Optional;
-
 public class ServletComponent extends HttpCommonComponent implements RestConsumerFactory, RestApiConsumerFactory {
 
     private String servletName = "CamelServlet";
@@ -62,7 +61,7 @@ public class ServletComponent extends HttpCommonComponent implements RestConsume
         String servletName = getAndRemoveParameter(parameters, "servletName", String.class, getServletName());
         String httpMethodRestrict = getAndRemoveParameter(parameters, "httpMethodRestrict", String.class);
         HeaderFilterStrategy headerFilterStrategy = resolveAndRemoveReferenceParameter(parameters, "headerFilterStrategy", HeaderFilterStrategy.class);
-        Optional<Boolean> async = Optional.ofNullable(getAndRemoveParameter(parameters, "async", Boolean.class));
+        Boolean async = getAndRemoveParameter(parameters, "async", Boolean.class);
 
         if (lenientContextPath()) {
             // the uri must have a leading slash for the context-path matching to work with servlet, and it can be something people
@@ -82,7 +81,9 @@ public class ServletComponent extends HttpCommonComponent implements RestConsume
 
         ServletEndpoint endpoint = createServletEndpoint(uri, this, httpUri);
         endpoint.setServletName(servletName);
-        async.ifPresent(endpoint::setAsync);
+        if (async != null) {
+            endpoint.setAsync(async);
+        }
         if (headerFilterStrategy != null) {
             endpoint.setHeaderFilterStrategy(headerFilterStrategy);
         } else {

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
index a22ffdb..5beefc3 100644
--- a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
+++ b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.component.servlet;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
@@ -25,9 +28,6 @@ import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-
 /**
  * To use a HTTP Servlet as entry for Camel routes when running in a servlet container.
  */

http://git-wip-us.apache.org/repos/asf/camel/blob/e6da66a6/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java
index 8ce0d98..8d50058 100644
--- a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java
+++ b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java
@@ -1,5 +1,24 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.camel.component.servlet;
 
+import java.net.URL;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.container.test.api.RunAsClient;
 import org.jboss.arquillian.junit.Arquillian;
@@ -10,13 +29,10 @@ import org.jboss.shrinkwrap.api.spec.WebArchive;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.net.URL;
-import java.nio.file.Paths;
-import java.text.MessageFormat;
-
 import static com.jayway.restassured.RestAssured.given;
 import static org.hamcrest.CoreMatchers.equalTo;
 
+
 /**
  * @author arnaud.deprez
  * @since 18/04/16
@@ -24,29 +40,29 @@ import static org.hamcrest.CoreMatchers.equalTo;
 @RunWith(Arquillian.class)
 public class ServletAsyncArquillianTest {
 
-	@Deployment
-	public static Archive<?> createTestArchive() {
-		// this is a WAR project so use WebArchive
-		return ShrinkWrap.create(WebArchive.class)
-			// add the web.xml
-			.setWebXML(Paths.get("src/test/resources/org/apache/camel/component/servlet/web-spring-async.xml").toFile());
-	}
+    @Deployment
+    public static Archive<?> createTestArchive() {
+        // this is a WAR project so use WebArchive
+        return ShrinkWrap.create(WebArchive.class)
+            // add the web.xml
+            .setWebXML(Paths.get("src/test/resources/org/apache/camel/component/servlet/web-spring-async.xml").toFile());
+    }
 
-	/**
-	 *
-	 * @param url the URL is the URL to the web application that was deployed
-	 * @throws Exception
-	 */
-	@Test
-	@RunAsClient
-	public void testHello(@ArquillianResource URL url) throws Exception {
-		final String name = "Arnaud";
-		given().
-			baseUri(url.toString()).
-			queryParam("name", name).
-		when().
-			get("/services/hello").
-		then().
-			body(equalTo(MessageFormat.format("Hello {0} how are you?", name)));
-	}
+    /**
+     *
+     * @param url the URL is the URL to the web application that was deployed
+     * @throws Exception
+     */
+    @Test
+    @RunAsClient
+    public void testHello(@ArquillianResource URL url) throws Exception {
+        final String name = "Arnaud";
+        given().
+            baseUri(url.toString()).
+            queryParam("name", name).
+        when().
+            get("/services/hello").
+        then().
+            body(equalTo(MessageFormat.format("Hello {0} how are you?", name)));
+    }
 }


[2/2] camel git commit: CAMEL-6707: add async for servlet

Posted by da...@apache.org.
CAMEL-6707: add async for servlet


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/6a1f84e0
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/6a1f84e0
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/6a1f84e0

Branch: refs/heads/master
Commit: 6a1f84e0bcddb68fcc075613a72b919709f9be3c
Parents: 2bd185e
Author: Arnaud Deprez <ar...@lampiris.be>
Authored: Wed Apr 13 23:38:00 2016 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Apr 22 07:44:45 2016 +0200

----------------------------------------------------------------------
 .../websocket/CamelWebSocketServlet.java        |  10 +-
 .../apache/camel/http/common/CamelServlet.java  |  89 +++++++--
 .../camel/http/common/DefaultHttpBinding.java   |  46 ++---
 .../camel/http/common/HttpCommonComponent.java  |   1 -
 .../camel/http/common/HttpCommonEndpoint.java   |  27 ++-
 components/camel-http/src/main/docs/http.adoc   |   2 +
 .../jetty/CamelContinuationServlet.java         |  27 ++-
 .../component/jetty/JettyHttpComponent.java     |  74 +++----
 .../jetty/ExplicitJettyAsyncRouteTest.java      |  66 +++++++
 .../jetty/HttpBridgeAsyncRouteTest.java         |  48 +++++
 .../component/jetty/HttpBridgeRouteTest.java    |   8 +-
 .../component/jetty/HttpsAsyncRouteTest.java    | 196 +++++++++++++++++++
 .../camel/component/jetty/HttpsRouteTest.java   |  22 +--
 components/camel-servlet/pom.xml                |  76 +++++++
 .../component/servlet/ServletComponent.java     |  13 +-
 .../component/servlet/ServletEndpoint.java      |   6 +-
 .../servlet/ServletAsyncArquillianTest.java     |  52 +++++
 .../component/servlet/web-spring-async.xml      |  56 ++++++
 18 files changed, 674 insertions(+), 145 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
index 6c9be21..2a84a73 100644
--- a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
+++ b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/CamelWebSocketServlet.java
@@ -16,14 +16,14 @@
  */
 package org.apache.camel.component.atmosphere.websocket;
 
-import java.io.IOException;
+import org.apache.camel.component.servlet.CamelHttpTransportServlet;
+import org.apache.camel.http.common.HttpConsumer;
+
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
-import org.apache.camel.component.servlet.CamelHttpTransportServlet;
-import org.apache.camel.http.common.HttpConsumer;
+import java.io.IOException;
 
 /**
  * This servlet is used to add some websocket specific handling at the moment.
@@ -50,7 +50,7 @@ public class CamelWebSocketServlet extends CamelHttpTransportServlet {
     }
 
     @Override
-    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+    protected void doService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         log.trace("Service: {}", request);
 
         // Is there a consumer registered for the request.

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
index cd872c6..382a6a4 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
@@ -16,28 +16,33 @@
  */
 package org.apache.camel.http.common;
 
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 /**
  * A servlet to use as a Camel route as entry.
  */
 public class CamelServlet extends HttpServlet {
     private static final long serialVersionUID = -7061982839117697829L;
+    public static final String ASYNC_PARAM = "async";
     protected final Logger log = LoggerFactory.getLogger(getClass());
     
     /**
@@ -45,6 +50,7 @@ public class CamelServlet extends HttpServlet {
      *  sure that it is already set via the init method
      */
     private String servletName;
+    private boolean async = false;
 
     private ServletResolveConsumerStrategy servletResolveConsumerStrategy = new HttpServletResolveConsumerStrategy();
     private final ConcurrentMap<String, HttpConsumer> consumers = new ConcurrentHashMap<String, HttpConsumer>();
@@ -53,10 +59,61 @@ public class CamelServlet extends HttpServlet {
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
         this.servletName = config.getServletName();
+        this.async = Optional.ofNullable(config.getInitParameter(ASYNC_PARAM))
+            .map(ObjectHelper::toBoolean)
+            .orElse(Boolean.FALSE);
+        log.trace("servlet '{}' initialized with: async={}", new Object[]{servletName, async});
     }
 
     @Override
-    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+    protected final void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        if (isAsync()) {
+            final AsyncContext context = req.startAsync();
+            //run async
+            context.start(() -> doServiceAsync(context));
+        }
+        else {
+            doService(req, resp);
+        }
+    }
+
+	/**
+     * This is used to handle request asynchronously
+     * @param context the {@link AsyncContext}
+     */
+    protected void doServiceAsync(AsyncContext context) {
+        final HttpServletRequest request = (HttpServletRequest) context.getRequest();
+        final HttpServletResponse response = (HttpServletResponse) context.getResponse();
+        try {
+            doService(request, response);
+        }
+        //An error shouldn't occur as we should handle most of error in doService
+        catch (Exception e) {
+            log.error("Error processing request", e);
+            try {
+                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            }
+            catch (Exception e1) {
+                log.debug("Cannot send reply to client!", e1);
+            }
+            //Need to wrap it in RuntimeException as it occurs in a Runnable
+            throw new RuntimeCamelException(e);
+        }
+        finally {
+            context.complete();
+        }
+    }
+
+	/**
+     * This is the logical implementation to handle request with {@link CamelServlet}
+     * This is where most exceptions should be handled
+     *
+     * @param request the {@link HttpServletRequest}
+     * @param response the {@link HttpServletResponse}
+     * @throws ServletException
+     * @throws IOException
+     */
+    protected void doService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         log.trace("Service: {}", request);
 
         // Is there a consumer registered for the request.
@@ -202,6 +259,14 @@ public class CamelServlet extends HttpServlet {
         this.servletResolveConsumerStrategy = servletResolveConsumerStrategy;
     }
 
+    public boolean isAsync() {
+        return async;
+    }
+
+    public void setAsync(boolean async) {
+        this.async = async;
+    }
+
     public Map<String, HttpConsumer> getConsumers() {
         return Collections.unmodifiableMap(consumers);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
index da361ea..1f190fe 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/DefaultHttpBinding.java
@@ -16,34 +16,7 @@
  */
 package org.apache.camel.http.common;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-import javax.activation.DataHandler;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.camel.Endpoint;
-import org.apache.camel.Exchange;
-import org.apache.camel.InvalidPayloadException;
-import org.apache.camel.Message;
-import org.apache.camel.RuntimeCamelException;
-import org.apache.camel.StreamCache;
+import org.apache.camel.*;
 import org.apache.camel.converter.stream.CachedOutputStream;
 import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.util.GZIPHelper;
@@ -53,6 +26,15 @@ import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.activation.DataHandler;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLDecoder;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
 /**
  * Binding between {@link HttpMessage} and {@link HttpServletResponse}.
  * <p/>
@@ -282,8 +264,12 @@ public class DefaultHttpBinding implements HttpBinding {
 
     private String getRawPath(HttpServletRequest request) {
         String uri = request.getRequestURI();
-        String contextPath = request.getContextPath();
-        String servletPath = request.getServletPath();
+		/**
+         * In async case, it seems that request.getContextPath() can return null
+         * @see https://dev.eclipse.org/mhonarc/lists/jetty-users/msg04669.html
+         */
+        String contextPath = Optional.ofNullable(request.getContextPath()).orElse("");
+        String servletPath = Optional.ofNullable(request.getServletPath()).orElse("");
         return uri.substring(contextPath.length() + servletPath.length());
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
index 189c269..a99472e 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonComponent.java
@@ -86,5 +86,4 @@ public abstract class HttpCommonComponent extends HeaderFilterStrategyComponent
     public void setAllowJavaSerializedObject(boolean allowJavaSerializedObject) {
         this.allowJavaSerializedObject = allowJavaSerializedObject;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
index c6679bf..9007322 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java
@@ -16,16 +16,12 @@
  */
 package org.apache.camel.http.common;
 
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.*;
+
 import java.net.URI;
 import java.net.URISyntaxException;
 
-import org.apache.camel.impl.DefaultEndpoint;
-import org.apache.camel.spi.HeaderFilterStrategy;
-import org.apache.camel.spi.HeaderFilterStrategyAware;
-import org.apache.camel.spi.Metadata;
-import org.apache.camel.spi.UriParam;
-import org.apache.camel.spi.UriPath;
-
 public abstract class HttpCommonEndpoint extends DefaultEndpoint implements HeaderFilterStrategyAware {
 
     // Note: all options must be documented with description in annotations so extended components can access the documentation
@@ -124,6 +120,9 @@ public abstract class HttpCommonEndpoint extends DefaultEndpoint implements Head
             description = "Refers to a custom org.apache.camel.component.http.UrlRewrite which allows you to rewrite urls when you bridge/proxy endpoints."
                     + " See more details at http://camel.apache.org/urlrewrite.html")
     private UrlRewrite urlRewrite;
+    @UriParam(label = "consumer", defaultValue = "false",
+            description = "Configure the consumer to work in async mode")
+    private boolean async;
 
     public HttpCommonEndpoint() {
     }
@@ -506,9 +505,21 @@ public abstract class HttpCommonEndpoint extends DefaultEndpoint implements Head
     }
 
     /**
-     * If this option is true then IN exchange Form Encoded body will be mapped to HTTP 
+     * If this option is true then IN exchange Form Encoded body will be mapped to HTTP
      */
     public void setMapHttpMessageFormUrlEncodedBody(boolean mapHttpMessageFormUrlEncodedBody) {
         this.mapHttpMessageFormUrlEncodedBody = mapHttpMessageFormUrlEncodedBody;
     }
+
+    public boolean isAsync() {
+        return async;
+    }
+
+    /**
+     * If this option is true, the consumer will work in async mode
+     * @param async
+     */
+    public void setAsync(boolean async) {
+        this.async = async;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-http/src/main/docs/http.adoc
----------------------------------------------------------------------
diff --git a/components/camel-http/src/main/docs/http.adoc b/components/camel-http/src/main/docs/http.adoc
index 677037e..24e1d4c 100644
--- a/components/camel-http/src/main/docs/http.adoc
+++ b/components/camel-http/src/main/docs/http.adoc
@@ -137,6 +137,7 @@ The HTTP component supports 6 options which are listed below.
 
 
 
+
 // endpoint options: START
 The HTTP component supports 25 endpoint options which are listed below:
 
@@ -173,6 +174,7 @@ The HTTP component supports 25 endpoint options which are listed below:
 
 
 
+
 [[HTTP-MessageHeaders]]
 Message Headers
 ^^^^^^^^^^^^^^^

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
index 9e77b29..d9abfe2 100644
--- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
+++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
@@ -16,29 +16,24 @@
  */
 package org.apache.camel.component.jetty;
 
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
-import org.apache.camel.http.common.CamelServlet;
-import org.apache.camel.http.common.HttpCommonEndpoint;
-import org.apache.camel.http.common.HttpConstants;
-import org.apache.camel.http.common.HttpConsumer;
-import org.apache.camel.http.common.HttpHelper;
-import org.apache.camel.http.common.HttpMessage;
+import org.apache.camel.http.common.*;
 import org.apache.camel.impl.DefaultExchange;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.eclipse.jetty.continuation.Continuation;
 import org.eclipse.jetty.continuation.ContinuationSupport;
 
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 /**
  * Servlet which leverage <a href="http://wiki.eclipse.org/Jetty/Feature/Continuations">Jetty Continuations</a>.
  *
@@ -56,7 +51,7 @@ public class CamelContinuationServlet extends CamelServlet {
     private final Map<String, String> expiredExchanges = new ConcurrentHashMap<String, String>();
 
     @Override
-    protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
+    protected void doService(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
         log.trace("Service: {}", request);
 
         // is there a consumer registered for the request.
@@ -89,7 +84,7 @@ public class CamelContinuationServlet extends CamelServlet {
             log.trace("Start request with continuation timeout of {}", continuationTimeout != null ? continuationTimeout : "jetty default");
         } else {
             log.trace("Usage of continuation is disabled, either by component or endpoint configuration, fallback to normal servlet processing instead");
-            super.service(request, response);
+            super.doService(request, response);
             return;
         }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
index b826e0d..828514b 100644
--- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
+++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
@@ -16,61 +16,16 @@
  */
 package org.apache.camel.component.jetty;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.Writer;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import javax.management.MBeanServer;
-import javax.servlet.Filter;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.Consumer;
-import org.apache.camel.Endpoint;
-import org.apache.camel.Processor;
-import org.apache.camel.RuntimeCamelException;
-import org.apache.camel.http.common.CamelServlet;
-import org.apache.camel.http.common.HttpBinding;
-import org.apache.camel.http.common.HttpCommonComponent;
-import org.apache.camel.http.common.HttpCommonEndpoint;
-import org.apache.camel.http.common.HttpConfiguration;
-import org.apache.camel.http.common.HttpConsumer;
-import org.apache.camel.http.common.HttpRestServletResolveConsumerStrategy;
-import org.apache.camel.http.common.UrlRewrite;
-import org.apache.camel.spi.HeaderFilterStrategy;
-import org.apache.camel.spi.ManagementAgent;
-import org.apache.camel.spi.ManagementStrategy;
-import org.apache.camel.spi.Metadata;
-import org.apache.camel.spi.RestApiConsumerFactory;
-import org.apache.camel.spi.RestConfiguration;
-import org.apache.camel.spi.RestConsumerFactory;
-import org.apache.camel.util.FileUtil;
-import org.apache.camel.util.HostUtils;
-import org.apache.camel.util.IntrospectionSupport;
-import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.URISupport;
-import org.apache.camel.util.UnsafeUriCharactersEncoder;
+import org.apache.camel.*;
+import org.apache.camel.http.common.*;
+import org.apache.camel.spi.*;
+import org.apache.camel.util.*;
 import org.apache.camel.util.jsse.SSLContextParameters;
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.jmx.MBeanContainer;
-import org.eclipse.jetty.server.AbstractConnector;
-import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.*;
 import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Response;
-import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 import org.eclipse.jetty.server.handler.ErrorHandler;
 import org.eclipse.jetty.server.handler.HandlerCollection;
@@ -88,6 +43,21 @@ import org.eclipse.jetty.util.thread.ThreadPool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.management.MBeanServer;
+import javax.servlet.Filter;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.util.*;
+
 /**
  * An HttpComponent which starts an embedded Jetty for to handle consuming from
  * the http endpoints.
@@ -182,6 +152,7 @@ public abstract class JettyHttpComponent extends HttpCommonComponent implements
         Integer httpClientMinThreads = getAndRemoveParameter(parameters, "httpClientMinThreads", Integer.class, this.httpClientMinThreads);
         Integer httpClientMaxThreads = getAndRemoveParameter(parameters, "httpClientMaxThreads", Integer.class, this.httpClientMaxThreads);
         HttpClient httpClient = resolveAndRemoveReferenceParameter(parameters, "httpClient", HttpClient.class);
+        Optional<Boolean> async = Optional.ofNullable(getAndRemoveParameter(parameters, "async", Boolean.class));
 
         // extract httpClient. parameters
         Map<String, Object> httpClientParameters = IntrospectionSupport.extractProperties(parameters, "httpClient.");
@@ -203,6 +174,7 @@ public abstract class JettyHttpComponent extends HttpCommonComponent implements
         endpointUri = new URI(scheme + ":" + endpointUri);
 
         JettyHttpEndpoint endpoint = createEndpoint(endpointUri, httpUri);
+        async.ifPresent(endpoint::setAsync);
 
         if (headerFilterStrategy != null) {
             endpoint.setHeaderFilterStrategy(headerFilterStrategy);
@@ -1122,6 +1094,8 @@ public abstract class JettyHttpComponent extends HttpCommonComponent implements
         CamelServlet camelServlet = new CamelContinuationServlet();
         ServletHolder holder = new ServletHolder();
         holder.setServlet(camelServlet);
+        holder.setAsyncSupported(true);
+        holder.setInitParameter(CamelServlet.ASYNC_PARAM, Boolean.toString(endpoint.isAsync()));
         context.addServlet(holder, "/*");
 
         // use rest enabled resolver in case we use rest

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java
new file mode 100644
index 0000000..63fba47
--- /dev/null
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/ExplicitJettyAsyncRouteTest.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jetty;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Unit test for wiki demonstration.
+ */
+public class ExplicitJettyAsyncRouteTest extends BaseJettyTest {
+
+    @Test
+    public void testSendToJetty() throws Exception {
+        Object response = template.requestBody("http://localhost:{{port}}/myapp/myservice", "bookid=123");
+        // convert the response to a String
+        String body = context.getTypeConverter().convertTo(String.class, response);
+        assertEquals("<html><body>Book 123 is Camel in Action</body></html>", body);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                //async and continuation is not compatible!
+                from("jetty:http://localhost:{{port}}/myapp/myservice?async=true&useContinuation=false").process(new MyBookService());
+            }
+        };
+    }
+
+    public class MyBookService implements Processor {
+        public void process(Exchange exchange) throws Exception {
+            // just get the body as a string
+            String body = exchange.getIn().getBody(String.class);
+
+            // we have access to the HttpServletRequest here and we can grab it if we need it
+            HttpServletRequest req = exchange.getIn().getBody(HttpServletRequest.class);
+            assertNotNull(req);
+
+            // for unit testing
+            assertEquals("bookid=123", body);
+
+            // send a html response
+            exchange.getOut().setBody("<html><body>Book 123 is Camel in Action</body></html>");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeAsyncRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeAsyncRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeAsyncRouteTest.java
new file mode 100644
index 0000000..4bd24cb
--- /dev/null
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeAsyncRouteTest.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jetty;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+
+public class HttpBridgeAsyncRouteTest extends HttpBridgeRouteTest {
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                port1 = getPort();
+                port2 = getNextPort();
+
+                errorHandler(noErrorHandler());
+
+                Processor serviceProc = new Processor() {
+                    public void process(Exchange exchange) throws Exception {
+                        // get the request URL and copy it to the request body
+                        String uri = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
+                        exchange.getOut().setBody(uri);
+                    }
+                };
+                from("jetty:http://localhost:" + port2 + "/test/hello?async=true&useContinuation=false")
+                    .to("http://localhost:" + port1 + "?throwExceptionOnFailure=false&bridgeEndpoint=true");
+                
+                from("jetty://http://localhost:" + port1 + "?matchOnUriPrefix=true&async=true&useContinuation=false").process(serviceProc);
+            }
+        };
+    }    
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
index 5303e6a..edfbd3a 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpBridgeRouteTest.java
@@ -16,18 +16,18 @@
  */
 package org.apache.camel.component.jetty;
 
-import java.io.ByteArrayInputStream;
-
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.Test;
 
+import java.io.ByteArrayInputStream;
+
 public class HttpBridgeRouteTest extends BaseJettyTest {
 
-    private int port1;
-    private int port2;
+    protected int port1;
+    protected int port2;
 
     @Test
     public void testHttpClient() throws Exception {

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java
new file mode 100644
index 0000000..6e3041b
--- /dev/null
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsAsyncRouteTest.java
@@ -0,0 +1,196 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jetty;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+public class HttpsAsyncRouteTest extends HttpsRouteTest {
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        port1 = getNextPort();
+        port2 = getNextPort(port1 + 1);
+        
+        super.setUp();
+        // ensure jsse clients can validate the self signed dummy localhost cert, 
+        // use the server keystore as the trust store for these tests
+        URL trustStoreUrl = this.getClass().getClassLoader().getResource("jsse/localhost.ks");
+        setSystemProp("javax.net.ssl.trustStore", trustStoreUrl.toURI().getPath());
+    }
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        restoreSystemProperties();
+        super.tearDown();
+    }
+
+    protected void setSystemProp(String key, String value) {
+        String originalValue = System.setProperty(key, value);
+        originalValues.put(key, originalValue != null ? originalValue : NULL_VALUE_MARKER);
+    }
+
+    protected void restoreSystemProperties() {
+        for (Object key : originalValues.keySet()) {
+            Object value = originalValues.get(key);
+            if (NULL_VALUE_MARKER.equals(value)) {
+                System.getProperties().remove(key);    
+            } else {
+                System.setProperty((String)key, (String)value);
+            }
+        }
+    }
+
+    @Test
+    public void testEndpoint() throws Exception {
+        // these tests does not run well on Windows
+        if (isPlatform("windows")) {
+            return;
+        }
+
+        MockEndpoint mockEndpointA = resolveMandatoryEndpoint("mock:a", MockEndpoint.class);
+        mockEndpointA.expectedBodiesReceived(expectedBody);
+        MockEndpoint mockEndpointB = resolveMandatoryEndpoint("mock:b", MockEndpoint.class);
+        mockEndpointB.expectedBodiesReceived(expectedBody);
+
+        invokeHttpEndpoint();
+
+        mockEndpointA.assertIsSatisfied();
+        mockEndpointB.assertIsSatisfied();
+        List<Exchange> list = mockEndpointA.getReceivedExchanges();
+        Exchange exchange = list.get(0);
+        assertNotNull("exchange", exchange);
+
+        Message in = exchange.getIn();
+        assertNotNull("in", in);
+
+        Map<String, Object> headers = in.getHeaders();
+
+        log.info("Headers: " + headers);
+
+        assertTrue("Should be more than one header but was: " + headers, headers.size() > 0);
+    }
+    
+    @Test
+    public void testEndpointWithoutHttps() throws Exception {
+        // these tests does not run well on Windows
+        if (isPlatform("windows")) {
+            return;
+        }
+
+        MockEndpoint mockEndpoint = resolveMandatoryEndpoint("mock:a", MockEndpoint.class);
+        try {
+            template.sendBodyAndHeader("http://localhost:" + port1 + "/test", expectedBody, "Content-Type", "application/xml");
+            fail("expect exception on access to https endpoint via http");
+        } catch (RuntimeCamelException expected) {
+        }
+        assertTrue("mock endpoint was not called", mockEndpoint.getExchanges().isEmpty());
+    }
+
+    @Test
+    public void testHelloEndpoint() throws Exception {
+        // these tests does not run well on Windows
+        if (isPlatform("windows")) {
+            return;
+        }
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        InputStream is = new URL("https://localhost:" + port1 + "/hello").openStream();
+        int c;
+        while ((c = is.read()) >= 0) {
+            os.write(c);
+        }
+
+        String data = new String(os.toByteArray());
+        assertEquals("<b>Hello World</b>", data);
+    }
+    
+    @Test
+    public void testHelloEndpointWithoutHttps() throws Exception {
+        // these tests does not run well on Windows
+        if (isPlatform("windows")) {
+            return;
+        }
+
+        try {
+            new URL("http://localhost:" + port1 + "/hello").openStream();
+            fail("expected SocketException on use ot http");
+        } catch (SocketException expected) {
+        }
+    }
+    
+    protected void invokeHttpEndpoint() throws IOException {
+        template.sendBodyAndHeader(getHttpProducerScheme() + "localhost:" + port1 + "/test", expectedBody, "Content-Type", "application/xml");
+        template.sendBodyAndHeader(getHttpProducerScheme() + "localhost:" + port2 + "/test", expectedBody, "Content-Type", "application/xml");
+    }
+    
+    protected void configureSslContextFactory(SslContextFactory sslContextFactory) {
+        sslContextFactory.setKeyManagerPassword(pwd);
+        sslContextFactory.setKeyStorePassword(pwd);
+        URL keyStoreUrl = this.getClass().getClassLoader().getResource("jsse/localhost.ks");
+        try {
+            sslContextFactory.setKeyStorePath(keyStoreUrl.toURI().getPath());
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+        sslContextFactory.setTrustStoreType("JKS");
+    }
+    
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws URISyntaxException {
+                JettyHttpComponent componentJetty = (JettyHttpComponent) context.getComponent("jetty");
+                componentJetty.setSslPassword(pwd);
+                componentJetty.setSslKeyPassword(pwd);
+                URL keyStoreUrl = this.getClass().getClassLoader().getResource("jsse/localhost.ks");
+                componentJetty.setKeystore(keyStoreUrl.toURI().getPath());
+                
+                from("jetty:https://localhost:" + port1 + "/test?async=true&useContinuation=false").to("mock:a");
+
+                Processor proc = new Processor() {
+                    public void process(Exchange exchange) throws Exception {
+                        exchange.getOut().setBody("<b>Hello World</b>");
+                    }
+                };
+                from("jetty:https://localhost:" + port1 + "/hello?async=true&useContinuation=false").process(proc);
+                
+                from("jetty:https://localhost:" + port2 + "/test?async=true&useContinuation=false").to("mock:b");
+            }
+        };
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
index 56cf84b..9a3e04b 100644
--- a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/HttpsRouteTest.java
@@ -16,16 +16,6 @@
  */
 package org.apache.camel.component.jetty;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.SocketException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
@@ -38,9 +28,19 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
 public class HttpsRouteTest extends BaseJettyTest {
 
-    private static final String NULL_VALUE_MARKER = CamelTestSupport.class.getCanonicalName();
+    public static final String NULL_VALUE_MARKER = CamelTestSupport.class.getCanonicalName();
 
     protected String expectedBody = "<hello>world!</hello>";
     protected String pwd = "changeit";

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-servlet/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-servlet/pom.xml b/components/camel-servlet/pom.xml
index f1f84f1..56c1050 100644
--- a/components/camel-servlet/pom.xml
+++ b/components/camel-servlet/pom.xml
@@ -30,6 +30,7 @@
   <description>Camel servlet transport support</description>
 
   <properties>
+    <tomcat.version>8.5.0</tomcat.version>
     <camel.osgi.import.before.defaults>
       javax.servlet.*;version="${servlet-version-range}"
     </camel.osgi.import.before.defaults>
@@ -37,6 +38,18 @@
     <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=servlet</camel.osgi.export.service>
   </properties>
 
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.jboss.arquillian</groupId>
+        <artifactId>arquillian-bom</artifactId>
+        <version>${arquillian-version}</version>
+        <scope>import</scope>
+        <type>pom</type>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
   <dependencies>
 
     <dependency>
@@ -113,6 +126,69 @@
       <artifactId>camel-jaxb</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.jayway.restassured</groupId>
+      <artifactId>rest-assured</artifactId>
+      <version>${rest-assured-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.arquillian.junit</groupId>
+      <artifactId>arquillian-junit-container</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <!--jetty-->
+    <!--https://github.com/GoogleCloudPlatform/appengine-java-vm-runtime/issues/23-->
+    <!--Still not fixed in 9.3.8.v20160314 and 9.3.9.M1, produce 404 NOT FOUND or a 500 if we remove the async-supported flag :-(-->
+    <!--<dependency>
+      <groupId>org.jboss.arquillian.container</groupId>
+      <artifactId>arquillian-jetty-embedded-9</artifactId>
+      <version>1.0.0.CR3</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-webapp</artifactId>
+      <version>${jetty9-version}</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-deploy</artifactId>
+      <version>${jetty9-version}</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-annotations</artifactId>
+      <version>${jetty9-version}</version>
+      <scope>runtime</scope>
+    </dependency>-->
+    <!--tomcat-->
+    <dependency>
+      <groupId>org.jboss.arquillian.container</groupId>
+      <artifactId>arquillian-tomcat-embedded-8</artifactId>
+      <version>1.0.0.CR7</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat.embed</groupId>
+      <artifactId>tomcat-embed-core</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat.embed</groupId>
+      <artifactId>tomcat-embed-jasper</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat.embed</groupId>
+      <artifactId>tomcat-embed-logging-juli</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>runtime</scope>
+    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
index 34f5039..2a16ebf 100644
--- a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
+++ b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
@@ -16,11 +16,6 @@
  */
 package org.apache.camel.component.servlet;
 
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
 import org.apache.camel.CamelContext;
 import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
@@ -37,6 +32,12 @@ import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.URISupport;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
 public class ServletComponent extends HttpCommonComponent implements RestConsumerFactory, RestApiConsumerFactory {
 
     private String servletName = "CamelServlet";
@@ -61,6 +62,7 @@ public class ServletComponent extends HttpCommonComponent implements RestConsume
         String servletName = getAndRemoveParameter(parameters, "servletName", String.class, getServletName());
         String httpMethodRestrict = getAndRemoveParameter(parameters, "httpMethodRestrict", String.class);
         HeaderFilterStrategy headerFilterStrategy = resolveAndRemoveReferenceParameter(parameters, "headerFilterStrategy", HeaderFilterStrategy.class);
+        Optional<Boolean> async = Optional.ofNullable(getAndRemoveParameter(parameters, "async", Boolean.class));
 
         if (lenientContextPath()) {
             // the uri must have a leading slash for the context-path matching to work with servlet, and it can be something people
@@ -80,6 +82,7 @@ public class ServletComponent extends HttpCommonComponent implements RestConsume
 
         ServletEndpoint endpoint = createServletEndpoint(uri, this, httpUri);
         endpoint.setServletName(servletName);
+        async.ifPresent(endpoint::setAsync);
         if (headerFilterStrategy != null) {
             endpoint.setHeaderFilterStrategy(headerFilterStrategy);
         } else {

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
index 5beefc3..a22ffdb 100644
--- a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
+++ b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletEndpoint.java
@@ -16,9 +16,6 @@
  */
 package org.apache.camel.component.servlet;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
@@ -28,6 +25,9 @@ import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
 /**
  * To use a HTTP Servlet as entry for Camel routes when running in a servlet container.
  */

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java
new file mode 100644
index 0000000..8ce0d98
--- /dev/null
+++ b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/ServletAsyncArquillianTest.java
@@ -0,0 +1,52 @@
+package org.apache.camel.component.servlet;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.URL;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+
+import static com.jayway.restassured.RestAssured.given;
+import static org.hamcrest.CoreMatchers.equalTo;
+
+/**
+ * @author arnaud.deprez
+ * @since 18/04/16
+ */
+@RunWith(Arquillian.class)
+public class ServletAsyncArquillianTest {
+
+	@Deployment
+	public static Archive<?> createTestArchive() {
+		// this is a WAR project so use WebArchive
+		return ShrinkWrap.create(WebArchive.class)
+			// add the web.xml
+			.setWebXML(Paths.get("src/test/resources/org/apache/camel/component/servlet/web-spring-async.xml").toFile());
+	}
+
+	/**
+	 *
+	 * @param url the URL is the URL to the web application that was deployed
+	 * @throws Exception
+	 */
+	@Test
+	@RunAsClient
+	public void testHello(@ArquillianResource URL url) throws Exception {
+		final String name = "Arnaud";
+		given().
+			baseUri(url.toString()).
+			queryParam("name", name).
+		when().
+			get("/services/hello").
+		then().
+			body(equalTo(MessageFormat.format("Hello {0} how are you?", name)));
+	}
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/6a1f84e0/components/camel-servlet/src/test/resources/org/apache/camel/component/servlet/web-spring-async.xml
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/test/resources/org/apache/camel/component/servlet/web-spring-async.xml b/components/camel-servlet/src/test/resources/org/apache/camel/component/servlet/web-spring-async.xml
new file mode 100644
index 0000000..8e9accd
--- /dev/null
+++ b/components/camel-servlet/src/test/resources/org/apache/camel/component/servlet/web-spring-async.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+    
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+ 
+  http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<!-- START SNIPPET: web -->    
+<web-app>
+  <!-- tell Spring where it should load the XML file -->
+  <context-param>
+    <param-name>contextConfigLocation</param-name>
+    <param-value>classpath:org/apache/camel/component/servlet/example-camelContext.xml</param-value>
+  </context-param>
+
+  <!-- spring context listener which loads the XML file -->
+  <listener>
+    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+  </listener>
+
+  <servlet>
+    <servlet-name>CamelServlet</servlet-name>
+    <display-name>Camel Http Transport Servlet</display-name>
+    <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
+    <init-param>
+      <param-name>async</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+    <async-supported>true</async-supported>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>CamelServlet</servlet-name>
+    <url-pattern>/services/*</url-pattern>
+  </servlet-mapping>
+
+</web-app>
+<!-- END SNIPPET: web -->
\ No newline at end of file