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 <arnaud.dep...@lampiris.be> Authored: Wed Apr 13 23:38:00 2016 +0200 Committer: Claus Ibsen <davscl...@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