CAMEL-10392: HTTP session handling in Camel routes Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e607dc3f Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e607dc3f Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e607dc3f
Branch: refs/heads/master Commit: e607dc3f116a4983306fa517300e1f3123945f79 Parents: 2c7c11a Author: Stephan Siano <stephan.si...@sap.com> Authored: Fri Oct 14 11:32:06 2016 +0200 Committer: Stephan Siano <stephan.si...@sap.com> Committed: Thu Oct 20 08:48:36 2016 +0200 ---------------------------------------------------------------------- .../main/java/org/apache/camel/Exchange.java | 1 + components/camel-ahc/pom.xml | 4 + .../camel-ahc/src/main/docs/ahc-component.adoc | 3 +- .../apache/camel/component/ahc/AhcEndpoint.java | 14 ++ .../camel/component/ahc/DefaultAhcBinding.java | 38 ++++- .../component/ahc/AhcProducerSessionTest.java | 111 +++++++++++++++ components/camel-cxf/pom.xml | 4 + .../camel-cxf/src/main/docs/cxf-component.adoc | 3 +- .../src/main/docs/cxfrs-component.adoc | 3 +- .../camel/component/cxf/CxfClientCallback.java | 32 ++++- .../apache/camel/component/cxf/CxfEndpoint.java | 33 +++++ .../apache/camel/component/cxf/CxfProducer.java | 39 ++++- .../component/cxf/jaxrs/CxfRsEndpoint.java | 12 ++ .../component/cxf/jaxrs/CxfRsProducer.java | 47 +++++- .../component/cxf/CxfProducerSessionTest.java | 142 +++++++++++++++++++ .../apache/camel/component/cxf/EchoService.java | 24 ++++ .../component/cxf/EchoServiceSessionImpl.java | 43 ++++++ .../cxf/jaxrs/CxfRsProducerSessionTest.java | 116 +++++++++++++++ .../cxf/jaxrs/testbean/EchoService.java | 41 ++++++ .../cxf/jaxrs/CxfRsSpringProducerSession.xml | 90 ++++++++++++ .../camel/http/common/HttpCommonEndpoint.java | 14 ++ .../http/common/cookie/BaseCookieHandler.java | 53 +++++++ .../camel/http/common/cookie/CookieHandler.java | 67 +++++++++ .../common/cookie/ExchangeCookieHandler.java | 43 ++++++ .../common/cookie/InstanceCookieHandler.java | 39 +++++ .../src/main/docs/http-component.adoc | 3 +- .../camel/component/http/HttpProducer.java | 38 ++++- .../component/http/HttpProducerSessionTest.java | 117 +++++++++++++++ .../http/handler/SessionReflectionHandler.java | 47 ++++++ components/camel-http4/pom.xml | 6 + .../src/main/docs/http4-component.adoc | 5 +- .../camel/component/http4/HttpEndpoint.java | 9 ++ .../camel/component/http4/HttpProducer.java | 30 +++- .../http4/HttpProducerSessionTest.java | 117 +++++++++++++++ .../http4/handler/SessionReflectionHandler.java | 47 ++++++ .../component/jetty/JettyHttpEndpoint.java | 14 ++ .../component/jetty/JettyHttpProducer.java | 12 +- .../src/main/docs/jetty-component.adoc | 3 +- .../JettyHttpProducerSessionTest.java | 120 ++++++++++++++++ components/camel-netty4-http/pom.xml | 11 +- .../src/main/docs/netty4-http-component.adoc | 3 +- .../netty4/http/NettyHttpEndpoint.java | 14 ++ .../netty4/http/NettyHttpProducer.java | 13 +- .../http/handlers/HttpClientChannelHandler.java | 16 ++- .../http/NettyHttpProducerSessionTest.java | 111 +++++++++++++++ components/camel-restlet/pom.xml | 4 + .../src/main/docs/restlet-component.adoc | 3 +- .../component/restlet/RestletEndpoint.java | 14 ++ .../component/restlet/RestletProducer.java | 50 +++++++ .../restlet/RestletProducerSessionTest.java | 107 ++++++++++++++ components/camel-undertow/pom.xml | 4 + .../src/main/docs/undertow-component.adoc | 3 +- .../component/undertow/UndertowEndpoint.java | 14 ++ .../component/undertow/UndertowProducer.java | 32 +++++ .../UndertowHttpProducerSessionTest.java | 120 ++++++++++++++++ 55 files changed, 2074 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/camel-core/src/main/java/org/apache/camel/Exchange.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/Exchange.java b/camel-core/src/main/java/org/apache/camel/Exchange.java index 0a00d18..b23da1a 100644 --- a/camel-core/src/main/java/org/apache/camel/Exchange.java +++ b/camel-core/src/main/java/org/apache/camel/Exchange.java @@ -100,6 +100,7 @@ public interface Exchange { String CONTENT_ENCODING = "Content-Encoding"; String CONTENT_LENGTH = "Content-Length"; String CONTENT_TYPE = "Content-Type"; + String COOKIE_HANDLER = "CamelCookieHandler"; String CORRELATION_ID = "CamelCorrelationId"; String DATASET_INDEX = "CamelDataSetIndex"; http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-ahc/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-ahc/pom.xml b/components/camel-ahc/pom.xml index 7c423c9..c1d98da 100644 --- a/components/camel-ahc/pom.xml +++ b/components/camel-ahc/pom.xml @@ -41,6 +41,10 @@ <artifactId>camel-core</artifactId> </dependency> <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-http-common</artifactId> + </dependency> + <dependency> <groupId>org.asynchttpclient</groupId> <artifactId>async-http-client</artifactId> <version>${ahc-version}</version> http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-ahc/src/main/docs/ahc-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-ahc/src/main/docs/ahc-component.adoc b/components/camel-ahc/src/main/docs/ahc-component.adoc index f897c48..e058b88 100644 --- a/components/camel-ahc/src/main/docs/ahc-component.adoc +++ b/components/camel-ahc/src/main/docs/ahc-component.adoc @@ -50,7 +50,7 @@ AhcEndpoint Options // endpoint options: START -The AHC component supports 12 endpoint options which are listed below: +The AHC component supports 13 endpoint options which are listed below: {% raw %} [width="100%",cols="2,1,1m,1m,5",options="header"] @@ -61,6 +61,7 @@ The AHC component supports 12 endpoint options which are listed below: | bridgeEndpoint | producer | false | boolean | If the option is true then the Exchange.HTTP_URI header is ignored and use the endpoint's URI for request. You may also set the throwExceptionOnFailure to be false to let the AhcProducer send all the fault response back. | bufferSize | producer | 4096 | int | The initial in-memory buffer size used when transferring data between Camel and AHC Client. | connectionClose | producer | false | boolean | Define if the Connection Close header has to be added to HTTP Request. This parameter is false by default +| cookieHandler | producer | | CookieHandler | Configure a cookie handler to maintain a HTTP session | headerFilterStrategy | producer | | HeaderFilterStrategy | To use a custom HeaderFilterStrategy to filter header to and from Camel message. | throwExceptionOnFailure | producer | true | boolean | Option to disable throwing the AhcOperationFailedException in case of failed responses from the remote server. This allows you to get all responses regardless of the HTTP status code. | transferException | producer | false | boolean | If enabled and an Exchange failed processing on the consumer side and if the caused Exception was send back serialized in the response as a application/x-java-serialized-object content type (for example using Jetty or Servlet Camel components). On the producer side the exception will be deserialized and thrown as is instead of the AhcOperationFailedException. The caused exception is required to be serialized. This is by default turned off. If you enable this then be aware that Java will deserialize the incoming data from the request to Java and that can be a potential security risk. http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/AhcEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/AhcEndpoint.java b/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/AhcEndpoint.java index 0afc438..e56a7c5 100644 --- a/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/AhcEndpoint.java +++ b/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/AhcEndpoint.java @@ -27,6 +27,7 @@ import org.apache.camel.AsyncEndpoint; import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.http.common.cookie.CookieHandler; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; @@ -70,6 +71,8 @@ public class AhcEndpoint extends DefaultEndpoint implements AsyncEndpoint, Heade private Map<String, Object> clientConfigOptions; @UriParam(label = "producer", defaultValue = "false") private boolean connectionClose; + @UriParam(label = "producer") + private CookieHandler cookieHandler; public AhcEndpoint(String endpointUri, AhcComponent component, URI httpUri) { super(endpointUri, component); @@ -248,6 +251,17 @@ public class AhcEndpoint extends DefaultEndpoint implements AsyncEndpoint, Heade this.connectionClose = connectionClose; } + public CookieHandler getCookieHandler() { + return cookieHandler; + } + + /** + * Configure a cookie handler to maintain a HTTP session + */ + public void setCookieHandler(CookieHandler cookieHandler) { + this.cookieHandler = cookieHandler; + } + @Override protected void doStart() throws Exception { super.doStart(); http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/DefaultAhcBinding.java ---------------------------------------------------------------------- diff --git a/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/DefaultAhcBinding.java b/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/DefaultAhcBinding.java index c1346b2..dae132b 100644 --- a/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/DefaultAhcBinding.java +++ b/components/camel-ahc/src/main/java/org/apache/camel/component/ahc/DefaultAhcBinding.java @@ -25,6 +25,8 @@ import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.URI; import java.nio.charset.Charset; +import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -65,10 +67,11 @@ public class DefaultAhcBinding implements AhcBinding { } RequestBuilder builder = new RequestBuilder(); + URI uri; try { // creating the url to use takes 2-steps String url = AhcHelper.createURL(exchange, endpoint); - URI uri = AhcHelper.createURI(exchange, url, endpoint); + uri = AhcHelper.createURI(exchange, url, endpoint); // get the url from the uri url = uri.toASCIIString(); @@ -82,6 +85,7 @@ public class DefaultAhcBinding implements AhcBinding { builder.setMethod(method); populateHeaders(builder, endpoint, exchange); + populateCookieHeaders(builder, endpoint, exchange, uri); populateBody(builder, endpoint, exchange); return builder.build(); @@ -118,6 +122,25 @@ public class DefaultAhcBinding implements AhcBinding { } } + private void populateCookieHeaders(RequestBuilder builder, AhcEndpoint endpoint, Exchange exchange, URI uri) throws CamelExchangeException { + if (endpoint.getCookieHandler() != null) { + try { + Map<String, List<String>> cookieHeaders = endpoint.getCookieHandler().loadCookies(exchange, uri); + for (Map.Entry<String, List<String>> entry : cookieHeaders.entrySet()) { + String key = entry.getKey(); + if (entry.getValue().size() > 0) { + // use the default toString of a ArrayList to create in the form [xxx, yyy] + // if multi valued, for a single value, then just output the value as is + String s = entry.getValue().size() > 1 ? entry.getValue().toString() : entry.getValue().get(0); + builder.addHeader(key, s); + } + } + } catch (IOException e) { + throw new CamelExchangeException("Error loading cookies", exchange, e); + } + } + } + protected void populateBody(RequestBuilder builder, AhcEndpoint endpoint, Exchange exchange) throws CamelExchangeException { Message in = exchange.getIn(); if (in.getBody() == null) { @@ -211,11 +234,24 @@ public class DefaultAhcBinding implements AhcBinding { @Override public void onHeadersReceived(AhcEndpoint endpoint, Exchange exchange, HttpResponseHeaders headers) throws Exception { List<Entry<String, String>> l = headers.getHeaders().entries(); + Map<String, List<String>> m = new HashMap<String, List<String>>(); for (Entry<String, String> entry : headers.getHeaders().entries()) { String key = entry.getKey(); String value = entry.getValue(); + m.put(key, Collections.singletonList(value)); exchange.getOut().getHeaders().put(key, value); } + // handle cookies + if (endpoint.getCookieHandler() != null) { + try { + // creating the url to use takes 2-steps + String url = AhcHelper.createURL(exchange, endpoint); + URI uri = AhcHelper.createURI(exchange, url, endpoint); + endpoint.getCookieHandler().storeCookies(exchange, uri, m); + } catch (Exception e) { + throw new CamelExchangeException("Error storing cookies", exchange, e); + } + } } @Override http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-ahc/src/test/java/org/apache/camel/component/ahc/AhcProducerSessionTest.java ---------------------------------------------------------------------- diff --git a/components/camel-ahc/src/test/java/org/apache/camel/component/ahc/AhcProducerSessionTest.java b/components/camel-ahc/src/test/java/org/apache/camel/component/ahc/AhcProducerSessionTest.java new file mode 100644 index 0000000..ca9bebe --- /dev/null +++ b/components/camel-ahc/src/test/java/org/apache/camel/component/ahc/AhcProducerSessionTest.java @@ -0,0 +1,111 @@ +/** + * 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.ahc; + +import javax.servlet.http.HttpSession; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.http.common.HttpMessage; +import org.apache.camel.http.common.cookie.ExchangeCookieHandler; +import org.apache.camel.http.common.cookie.InstanceCookieHandler; +import org.apache.camel.impl.JndiRegistry; +import org.junit.Test; + +public class AhcProducerSessionTest extends BaseAhcTest { + + @Test + public void testProducerNoSession() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived("New New World", "New New World"); + template.sendBody("direct:start", "World"); + template.sendBody("direct:start", "World"); + assertMockEndpointsSatisfied(); + } + + @Test + public void testProducerInstanceSession() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived("Old New World", "Old Old World"); + template.sendBody("direct:instance", "World"); + template.sendBody("direct:instance", "World"); + assertMockEndpointsSatisfied(); + } + + @Test + public void testProducerExchangeSession() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived("Old New World", "Old New World"); + template.sendBody("direct:exchange", "World"); + template.sendBody("direct:exchange", "World"); + assertMockEndpointsSatisfied(); + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry jndiRegistry = super.createRegistry(); + jndiRegistry.bind("instanceCookieHandler", new InstanceCookieHandler()); + jndiRegistry.bind("exchangeCookieHandler", new ExchangeCookieHandler()); + return jndiRegistry; + } + + private String getTestServerEndpointSessionUrl() { + // session handling will not work for localhost + return getProtocol() + "://127.0.0.1:" + getPort() + "/session"; + } + + private String getTestServerEndpointSessionUri() { + return "jetty:" + getTestServerEndpointSessionUrl() + "?sessionSupport=true"; + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("ahc:" + getTestServerEndpointSessionUrl()) + .to("ahc:" + getTestServerEndpointSessionUrl()) + .to("mock:result"); + + from("direct:instance") + .to("ahc:" + getTestServerEndpointSessionUrl() + "?cookieHandler=#instanceCookieHandler") + .to("ahc:" + getTestServerEndpointSessionUrl() + "?cookieHandler=#instanceCookieHandler") + .to("mock:result"); + + from("direct:exchange") + .to("ahc:" + getTestServerEndpointSessionUrl() + "?cookieHandler=#exchangeCookieHandler") + .to("ahc:" + getTestServerEndpointSessionUrl() + "?cookieHandler=#exchangeCookieHandler") + .to("mock:result"); + + from(getTestServerEndpointSessionUri()) + .process(new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + HttpMessage message = exchange.getIn(HttpMessage.class); + HttpSession session = message.getRequest().getSession(); + String body = message.getBody(String.class); + if ("bar".equals(session.getAttribute("foo"))) { + message.setBody("Old " + body); + } else { + session.setAttribute("foo", "bar"); + message.setBody("New " + body); + } + } + }); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-cxf/pom.xml b/components/camel-cxf/pom.xml index be08f29..5cd9cc4 100644 --- a/components/camel-cxf/pom.xml +++ b/components/camel-cxf/pom.xml @@ -96,6 +96,10 @@ <groupId>org.apache.camel</groupId> <artifactId>camel-cxf-transport</artifactId> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-http-common</artifactId> + </dependency> <dependency> <groupId>org.apache.cxf</groupId> http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/main/docs/cxf-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/docs/cxf-component.adoc b/components/camel-cxf/src/main/docs/cxf-component.adoc index 4184b90..a7d42d9 100644 --- a/components/camel-cxf/src/main/docs/cxf-component.adoc +++ b/components/camel-cxf/src/main/docs/cxf-component.adoc @@ -143,7 +143,7 @@ The CXF component supports 2 options which are listed below. // endpoint options: START -The CXF component supports 35 endpoint options which are listed below: +The CXF component supports 36 endpoint options which are listed below: {% raw %} [width="100%",cols="2,1,1m,1m,5",options="header"] @@ -156,6 +156,7 @@ The CXF component supports 35 endpoint options which are listed below: | bridgeErrorHandler | consumer | false | boolean | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN/ERROR level and ignored. | exceptionHandler | consumer (advanced) | | ExceptionHandler | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN/ERROR level and ignored. | exchangePattern | consumer (advanced) | | ExchangePattern | Sets the exchange pattern when the consumer creates an exchange. +| cookieHandler | producer | | CookieHandler | Configure a cookie handler to maintain a HTTP session | defaultOperationName | producer | | String | This option will set the default operationName that will be used by the CxfProducer which invokes the remote service. | defaultOperationNamespace | producer | | String | This option will set the default operationNamespace that will be used by the CxfProducer which invokes the remote service. | hostnameVerifier | producer | | HostnameVerifier | The hostname verifier to be used. Use the notation to reference a HostnameVerifier from the registry. http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/main/docs/cxfrs-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/docs/cxfrs-component.adoc b/components/camel-cxf/src/main/docs/cxfrs-component.adoc index b1b7ee8..3836666 100644 --- a/components/camel-cxf/src/main/docs/cxfrs-component.adoc +++ b/components/camel-cxf/src/main/docs/cxfrs-component.adoc @@ -81,7 +81,7 @@ The CXF-RS component supports 1 options which are listed below. // endpoint options: START -The CXF-RS component supports 30 endpoint options which are listed below: +The CXF-RS component supports 31 endpoint options which are listed below: {% raw %} [width="100%",cols="2,1,1m,1m,5",options="header"] @@ -102,6 +102,7 @@ The CXF-RS component supports 30 endpoint options which are listed below: | publishedEndpointUrl | consumer | | String | This option can override the endpointUrl that published from the WADL which can be accessed with resource address url plus _wadl | exceptionHandler | consumer (advanced) | | ExceptionHandler | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN/ERROR level and ignored. | exchangePattern | consumer (advanced) | | ExchangePattern | Sets the exchange pattern when the consumer creates an exchange. +| cookieHandler | producer | | CookieHandler | Configure a cookie handler to maintain a HTTP session | hostnameVerifier | producer | | HostnameVerifier | The hostname verifier to be used. Use the notation to reference a HostnameVerifier from the registry. | sslContextParameters | producer | | SSLContextParameters | The Camel SSL setting reference. Use the notation to reference the SSL Context. | throwExceptionOnFailure | producer | true | boolean | This option tells the CxfRsProducer to inspect return codes and will generate an Exception if the return code is larger than 207. http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfClientCallback.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfClientCallback.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfClientCallback.java index bcef9cf..b2810c5 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfClientCallback.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfClientCallback.java @@ -16,12 +16,16 @@ */ package org.apache.camel.component.cxf; +import java.io.IOException; +import java.util.List; import java.util.Map; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; import org.apache.cxf.endpoint.ClientCallback; import org.apache.cxf.endpoint.ConduitSelector; +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.message.Message; import org.apache.cxf.service.model.BindingOperationInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,31 +37,40 @@ public class CxfClientCallback extends ClientCallback { private final Exchange camelExchange; private final org.apache.cxf.message.Exchange cxfExchange; private final BindingOperationInfo boi; - private final CxfBinding binding; + private final CxfEndpoint endpoint; public CxfClientCallback(AsyncCallback callback, Exchange camelExchange, org.apache.cxf.message.Exchange cxfExchange, BindingOperationInfo boi, - CxfBinding binding) { + CxfEndpoint endpoint) { this.camelAsyncCallback = callback; this.camelExchange = camelExchange; this.cxfExchange = cxfExchange; this.boi = boi; - this.binding = binding; + this.endpoint = endpoint; } public void handleResponse(Map<String, Object> ctx, Object[] res) { try { super.handleResponse(ctx, res); } finally { + // add cookies to the cookie store + if (endpoint.getCookieHandler() != null) { + try { + Map<String, List<String>> cxfHeaders = CastUtils.cast((Map<?, ?>)cxfExchange.getInMessage().get(Message.PROTOCOL_HEADERS)); + endpoint.getCookieHandler().storeCookies(camelExchange, endpoint.getRequestUri(camelExchange), cxfHeaders); + } catch (IOException e) { + LOG.error("Cannot store cookies", e); + } + } // bind the CXF response to Camel exchange and // call camel callback // for one way messages callback is already called in // process method of org.apache.camel.component.cxf.CxfProducer if (!boi.getOperationInfo().isOneWay()) { - binding.populateExchangeFromCxfResponse(camelExchange, cxfExchange, ctx); + endpoint.getCxfBinding().populateExchangeFromCxfResponse(camelExchange, cxfExchange, ctx); camelAsyncCallback.done(false); } if (LOG.isDebugEnabled()) { @@ -84,12 +97,21 @@ public class CxfClientCallback extends ClientCallback { camelExchange.setException(ex); } } finally { + // add cookies to the cookie store + if (endpoint.getCookieHandler() != null) { + try { + Map<String, List<String>> cxfHeaders = CastUtils.cast((Map<?, ?>)cxfExchange.getInMessage().get(Message.PROTOCOL_HEADERS)); + endpoint.getCookieHandler().storeCookies(camelExchange, endpoint.getRequestUri(camelExchange), cxfHeaders); + } catch (IOException e) { + LOG.error("Cannot store cookies", e); + } + } // copy the context information and // call camel callback // for one way messages callback is already called in // process method of org.apache.camel.component.cxf.CxfProducer if (!boi.getOperationInfo().isOneWay()) { - binding.populateExchangeFromCxfResponse(camelExchange, cxfExchange, ctx); + endpoint.getCxfBinding().populateExchangeFromCxfResponse(camelExchange, cxfExchange, ctx); camelAsyncCallback.done(false); } if (LOG.isDebugEnabled()) { http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfEndpoint.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfEndpoint.java index 11edd4e..2311560 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfEndpoint.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfEndpoint.java @@ -18,6 +18,8 @@ package org.apache.camel.component.cxf; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -49,6 +51,7 @@ import org.apache.camel.AsyncEndpoint; import org.apache.camel.CamelContext; import org.apache.camel.CamelException; import org.apache.camel.Consumer; +import org.apache.camel.Exchange; import org.apache.camel.ExchangePattern; import org.apache.camel.Processor; import org.apache.camel.Producer; @@ -59,6 +62,7 @@ import org.apache.camel.component.cxf.common.message.CxfConstants; import org.apache.camel.component.cxf.feature.CXFMessageDataFormatFeature; import org.apache.camel.component.cxf.feature.PayLoadDataFormatFeature; import org.apache.camel.component.cxf.feature.RAWDataFormatFeature; +import org.apache.camel.http.common.cookie.CookieHandler; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.impl.SynchronousDelegateProducer; import org.apache.camel.spi.HeaderFilterStrategy; @@ -201,6 +205,8 @@ public class CxfEndpoint extends DefaultEndpoint implements AsyncEndpoint, Heade private String password; @UriParam(label = "advanced", prefix = "properties.", multiValue = true) private Map<String, Object> properties; + @UriParam(label = "producer") + private CookieHandler cookieHandler; public CxfEndpoint() { setExchangePattern(ExchangePattern.InOut); @@ -1066,6 +1072,17 @@ public class CxfEndpoint extends DefaultEndpoint implements AsyncEndpoint, Heade } } + public CookieHandler getCookieHandler() { + return cookieHandler; + } + + /** + * Configure a cookie handler to maintain a HTTP session + */ + public void setCookieHandler(CookieHandler cookieHandler) { + this.cookieHandler = cookieHandler; + } + @Override protected void doStart() throws Exception { if (headerFilterStrategy == null) { @@ -1437,4 +1454,20 @@ public class CxfEndpoint extends DefaultEndpoint implements AsyncEndpoint, Heade public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { this.hostnameVerifier = hostnameVerifier; } + + /** + * get the request uri for a given exchange. + */ + URI getRequestUri(Exchange camelExchange) { + String uriString = camelExchange.getIn().getHeader(Exchange.DESTINATION_OVERRIDE_URL, String.class); + if (uriString == null) { + uriString = getAddress(); + } + try { + return new URI(uriString); + } catch (URISyntaxException e) { + LOG.error("cannot determine request URI", e); + return null; + } + } } http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfProducer.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfProducer.java index c92abff..91b9ddb 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfProducer.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/CxfProducer.java @@ -16,12 +16,14 @@ */ package org.apache.camel.component.cxf; +import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.TreeMap; import javax.xml.namespace.QName; import javax.xml.ws.Holder; @@ -38,6 +40,7 @@ import org.apache.camel.util.ServiceHelper; import org.apache.cxf.Bus; import org.apache.cxf.binding.soap.model.SoapHeaderInfo; import org.apache.cxf.endpoint.Client; +import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.jaxws.context.WrappedMessageContext; import org.apache.cxf.message.ExchangeImpl; import org.apache.cxf.message.Message; @@ -125,8 +128,7 @@ public class CxfProducer extends DefaultProducer implements AsyncProcessor { invocationContext.put(Client.RESPONSE_CONTEXT, responseContext); invocationContext.put(Client.REQUEST_CONTEXT, prepareRequest(camelExchange, cxfExchange)); - CxfClientCallback cxfClientCallback = new CxfClientCallback(callback, camelExchange, cxfExchange, boi, - endpoint.getCxfBinding()); + CxfClientCallback cxfClientCallback = new CxfClientCallback(callback, camelExchange, cxfExchange, boi, endpoint); // send the CXF async request client.invoke(cxfClientCallback, boi, getParams(endpoint, camelExchange), invocationContext, cxfExchange); @@ -171,6 +173,15 @@ public class CxfProducer extends DefaultProducer implements AsyncProcessor { } catch (Exception exception) { camelExchange.setException(exception); } finally { + // add cookies to the cookie store + if (endpoint.getCookieHandler() != null) { + try { + Map<String, List<String>> cxfHeaders = CastUtils.cast((Map<?, ?>)cxfExchange.getInMessage().get(Message.PROTOCOL_HEADERS)); + endpoint.getCookieHandler().storeCookies(camelExchange, endpoint.getRequestUri(camelExchange), cxfHeaders); + } catch (IOException e) { + LOG.error("Cannot store cookies", e); + } + } // bind the CXF response to Camel exchange if (!boi.getOperationInfo().isOneWay()) { endpoint.getCxfBinding().populateExchangeFromCxfResponse(camelExchange, cxfExchange, @@ -208,7 +219,27 @@ public class CxfProducer extends DefaultProducer implements AsyncProcessor { // bind the request CXF exchange endpoint.getCxfBinding().populateCxfRequestFromExchange(cxfExchange, camelExchange, requestContext); - + + // add appropriate cookies from the cookie store to the protocol headers + if (endpoint.getCookieHandler() != null) { + try { + Map<String, List<String>> transportHeaders = CastUtils.cast((Map<?, ?>)requestContext.get(Message.PROTOCOL_HEADERS)); + boolean added; + if (transportHeaders == null) { + transportHeaders = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER); + added = true; + } else { + added = false; + } + transportHeaders.putAll(endpoint.getCookieHandler().loadCookies(camelExchange, endpoint.getRequestUri(camelExchange))); + if (added && transportHeaders.size() > 0) { + requestContext.put(Message.PROTOCOL_HEADERS, transportHeaders); + } + } catch (IOException e) { + LOG.warn("Cannot load cookies", e); + } + } + // Remove protocol headers from scopes. Otherwise, response headers can be // overwritten by request headers when SOAPHandlerInterceptor tries to create // a wrapped message context by the copyScoped() method. @@ -216,7 +247,7 @@ public class CxfProducer extends DefaultProducer implements AsyncProcessor { return requestContext.getWrappedMap(); } - + private BindingOperationInfo prepareBindingOperation(Exchange camelExchange, org.apache.cxf.message.Exchange cxfExchange) { // get binding operation info BindingOperationInfo boi = getBindingOperationInfo(camelExchange); http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java index 097c442..3435d20 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsEndpoint.java @@ -32,6 +32,7 @@ import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.Service; import org.apache.camel.component.cxf.NullFaultListener; +import org.apache.camel.http.common.cookie.CookieHandler; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; @@ -126,6 +127,8 @@ public class CxfRsEndpoint extends DefaultEndpoint implements HeaderFilterStrate private boolean propagateContexts; @UriParam(label = "advanced") private CxfRsEndpointConfigurer cxfRsEndpointConfigurer; + @UriParam(label = "producer") + private CookieHandler cookieHandler; public CxfRsEndpoint() { } @@ -799,5 +802,14 @@ public class CxfRsEndpoint extends DefaultEndpoint implements HeaderFilterStrate this.cxfRsEndpointConfigurer = configurer; } + public CookieHandler getCookieHandler() { + return cookieHandler; + } + /** + * Configure a cookie handler to maintain a HTTP session + */ + public void setCookieHandler(CookieHandler cookieHandler) { + this.cookieHandler = cookieHandler; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducer.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducer.java index afe20b4b..8ff54c3 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducer.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducer.java @@ -16,10 +16,13 @@ */ package org.apache.camel.component.cxf.jaxrs; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.net.CookieStore; +import java.net.HttpCookie; import java.net.URLDecoder; import java.util.Collection; import java.util.HashMap; @@ -27,6 +30,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import org.apache.camel.CamelExchangeException; @@ -35,6 +39,7 @@ import org.apache.camel.Message; import org.apache.camel.component.cxf.CxfEndpointUtils; import org.apache.camel.component.cxf.CxfOperationException; import org.apache.camel.component.cxf.common.message.CxfConstants; +import org.apache.camel.http.common.cookie.CookieHandler; import org.apache.camel.impl.DefaultProducer; import org.apache.camel.util.IOHelper; import org.apache.camel.util.LRUSoftCache; @@ -204,7 +209,11 @@ public class CxfRsProducer extends DefaultProducer { setupClientMatrix(client, exchange); setupClientQueryAndHeaders(client, exchange); - + + // handle cookies + CookieHandler cookieHandler = ((CxfRsEndpoint)getEndpoint()).getCookieHandler(); + loadCookies(exchange, client, cookieHandler); + // invoke the client Object response = null; if (responseClass == null || Response.class.equals(responseClass)) { @@ -224,6 +233,8 @@ public class CxfRsProducer extends DefaultProducer { } } int statesCode = client.getResponse().getStatus(); + // handle cookies + saveCookies(exchange, client, cookieHandler); //Throw exception on a response > 207 //http://en.wikipedia.org/wiki/List_of_HTTP_status_codes if (throwException) { @@ -249,6 +260,33 @@ public class CxfRsProducer extends DefaultProducer { } } + private void saveCookies(Exchange exchange, Client client, CookieHandler cookieHandler) { + if (cookieHandler != null) { + CookieStore cookieStore = cookieHandler.getCookieStore(exchange); + for (NewCookie newCookie: client.getResponse().getCookies().values()) { + HttpCookie cookie = new HttpCookie(newCookie.getName(), newCookie.getValue()); + cookie.setComment(newCookie.getComment()); + cookie.setDomain(newCookie.getDomain()); + cookie.setHttpOnly(newCookie.isHttpOnly()); + cookie.setMaxAge(newCookie.getMaxAge()); + cookie.setPath(newCookie.getPath()); + cookie.setSecure(newCookie.isSecure()); + cookie.setVersion(newCookie.getVersion()); + cookieStore.add(client.getCurrentURI(), cookie); + } + } + } + + private void loadCookies(Exchange exchange, Client client, CookieHandler cookieHandler) throws IOException { + if (cookieHandler != null) { + for (Map.Entry<String, List<String>> cookie : cookieHandler.loadCookies(exchange, client.getCurrentURI()).entrySet()) { + if (cookie.getValue().size() > 0) { + client.header(cookie.getKey(), cookie.getValue()); + } + } + } + } + protected void invokeProxyClient(Exchange exchange) throws Exception { Message inMessage = exchange.getIn(); Object[] varValues = inMessage.getHeader(CxfConstants.CAMEL_CXF_RS_VAR_VALUES, Object[].class); @@ -280,10 +318,17 @@ public class CxfRsProducer extends DefaultProducer { } // get the method Method method = findRightMethod(sfb.getResourceClasses(), methodName, getParameterTypes(parameters)); + + // handle cookies + CookieHandler cookieHandler = ((CxfRsEndpoint)getEndpoint()).getCookieHandler(); + loadCookies(exchange, target, cookieHandler); + // Will send out the message to // Need to deal with the sub resource class Object response = method.invoke(target, parameters); int statesCode = target.getResponse().getStatus(); + // handle cookies + saveCookies(exchange, target, cookieHandler); if (throwException) { if (response instanceof Response) { Integer respCode = ((Response) response).getStatus(); http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerSessionTest.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerSessionTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerSessionTest.java new file mode 100644 index 0000000..86ecd2f --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfProducerSessionTest.java @@ -0,0 +1,142 @@ +/** + * 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.cxf; + +import java.util.Collections; +import java.util.Map; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.http.common.cookie.ExchangeCookieHandler; +import org.apache.camel.http.common.cookie.InstanceCookieHandler; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.cxf.Bus; +import org.apache.cxf.BusFactory; +import org.apache.cxf.jaxws.JaxWsServerFactoryBean; +import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean; +import org.apache.cxf.transport.http_jetty.JettyHTTPServerEngineFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CxfProducerSessionTest extends CamelTestSupport { + private static final int PORT = CXFTestSupport.getPort1(); + private static final String SIMPLE_SERVER_ADDRESS = "http://127.0.0.1:" + PORT + "/CxfProducerSessionTest/test"; + private static final String REQUEST_MESSAGE_EXPRESSION = "<ns1:echo xmlns:ns1=\"http://cxf.component.camel.apache.org/\"><arg0>${in.body}</arg0></ns1:echo>"; + private static final Map<String, String> NAMESPACES = Collections.singletonMap("ns1", "http://cxf.component.camel.apache.org/"); + private static final String PARAMETER_XPATH = "/ns1:echoResponse/return/text()"; + + private String url = "cxf://" + SIMPLE_SERVER_ADDRESS + "?serviceClass=org.apache.camel.component.cxf.EchoService&dataFormat=PAYLOAD&synchronous=true"; + + @Override + public boolean isCreateCamelContextPerClass() { + return true; + } + + @BeforeClass + public static void startServer() throws Exception { + // start a simple front service + JaxWsServiceFactoryBean svrFBean = new JaxWsServiceFactoryBean(); + svrFBean.setServiceClass(EchoService.class); + JaxWsServerFactoryBean svrBean = new JaxWsServerFactoryBean(svrFBean); + svrBean.setAddress(SIMPLE_SERVER_ADDRESS); + svrBean.setServiceClass(EchoService.class); + svrBean.setServiceBean(new EchoServiceSessionImpl()); + // make the Jetty server support sessions + Bus bus = BusFactory.newInstance().createBus(); + JettyHTTPServerEngineFactory jettyFactory = bus.getExtension(JettyHTTPServerEngineFactory.class); + jettyFactory.createJettyHTTPServerEngine(PORT, "http").setSessionSupport(true); + svrBean.setBus(bus); + svrBean.create(); + } + + @AfterClass + public static void destroyServer() { + // If we don't destroy this the session support will spill over to other + // tests and they will fail + JettyHTTPServerEngineFactory.destroyForPort(PORT); + } + + @Test + public void testNoSession() throws Exception { + getMockEndpoint("mock:result").expectedMessageCount(2); + String response = template.requestBody("direct:start", "World", String.class); + assertEquals("New New World", response); + response = template.requestBody("direct:start", "World", String.class); + assertEquals("New New World", response); + assertMockEndpointsSatisfied(); + } + + @Test + public void testExchangeSession() throws Exception { + getMockEndpoint("mock:result").expectedMessageCount(2); + String response = template.requestBody("direct:exchange", "World", String.class); + assertEquals("Old New World", response); + response = template.requestBody("direct:exchange", "World", String.class); + assertEquals("Old New World", response); + assertMockEndpointsSatisfied(); + } + + @Test + public void testInstanceSession() throws Exception { + getMockEndpoint("mock:result").expectedMessageCount(2); + String response = template.requestBody("direct:instance", "World", String.class); + assertEquals("Old New World", response); + response = template.requestBody("direct:instance", "World", String.class); + assertEquals("Old Old World", response); + assertMockEndpointsSatisfied(); + } + + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start") + .setBody().simple(REQUEST_MESSAGE_EXPRESSION) + .to(url) + .setBody().xpath(PARAMETER_XPATH, String.class, NAMESPACES) + .setBody().simple(REQUEST_MESSAGE_EXPRESSION) + .to(url) + .setBody().xpath(PARAMETER_XPATH, String.class, NAMESPACES) + .to("mock:result"); + from("direct:instance") + .setBody().simple(REQUEST_MESSAGE_EXPRESSION) + .to(url + "&cookieHandler=#instanceCookieHandler") + .setBody().xpath(PARAMETER_XPATH, String.class, NAMESPACES) + .setBody().simple(REQUEST_MESSAGE_EXPRESSION) + .to(url + "&cookieHandler=#instanceCookieHandler") + .setBody().xpath(PARAMETER_XPATH, String.class, NAMESPACES) + .to("mock:result"); + from("direct:exchange") + .setBody().simple(REQUEST_MESSAGE_EXPRESSION) + .to(url + "&cookieHandler=#exchangeCookieHandler") + .setBody().xpath(PARAMETER_XPATH, String.class, NAMESPACES) + .setBody().simple(REQUEST_MESSAGE_EXPRESSION) + .to(url + "&cookieHandler=#exchangeCookieHandler") + .setBody().xpath(PARAMETER_XPATH, String.class, NAMESPACES) + .to("mock:result"); + } + }; + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry jndiRegistry = super.createRegistry(); + jndiRegistry.bind("instanceCookieHandler", new InstanceCookieHandler()); + jndiRegistry.bind("exchangeCookieHandler", new ExchangeCookieHandler()); + return jndiRegistry; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoService.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoService.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoService.java new file mode 100644 index 0000000..11c4196 --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoService.java @@ -0,0 +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.cxf; + +import javax.jws.WebService; + +@WebService +public interface EchoService { + String echo(String text) throws Exception; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoServiceSessionImpl.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoServiceSessionImpl.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoServiceSessionImpl.java new file mode 100644 index 0000000..c72355c --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/EchoServiceSessionImpl.java @@ -0,0 +1,43 @@ +/** + * 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.cxf; + +import javax.annotation.Resource; +import javax.servlet.http.HttpSession; +import javax.xml.ws.WebServiceContext; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.handler.MessageContext; + +public class EchoServiceSessionImpl implements EchoService { + + @Resource + private WebServiceContext context; + + public String echo(String text) { + // Find the HttpSession + MessageContext mc = context.getMessageContext(); + HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession(); + if (session == null) { + throw new WebServiceException("No HTTP Session found"); + } + if (session.getAttribute("foo") == null) { + session.setAttribute("foo", "bar"); + return "New " + text; + } + return "Old " + text; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducerSessionTest.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducerSessionTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducerSessionTest.java new file mode 100644 index 0000000..30efb7b --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsProducerSessionTest.java @@ -0,0 +1,116 @@ +/** + * 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.cxf.jaxrs; + +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.camel.component.cxf.CXFTestSupport; +import org.apache.camel.component.cxf.common.message.CxfConstants; +import org.apache.camel.test.spring.CamelSpringTestSupport; +import org.junit.Test; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class CxfRsProducerSessionTest extends CamelSpringTestSupport { + private static int port1 = CXFTestSupport.getPort1(); + private static int port2 = CXFTestSupport.getPort("CxfRsProducerSessionTest.jetty"); + + @Override + public boolean isCreateCamelContextPerClass() { + return true; + } + + public int getPort1() { + return port1; + } + + public int getPort2() { + return port2; + } + + @Override + protected AbstractXmlApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/camel/component/cxf/jaxrs/CxfRsSpringProducerSession.xml"); + } + + protected void setupDestinationURL(Message inMessage) { + // do nothing here + } + + @Test + public void testNoSessionProxy() { + String response = sendMessage("direct://proxy", "World", Boolean.FALSE).getOut().getBody(String.class); + assertEquals("New New World", response); + response = sendMessage("direct://proxy", "World", Boolean.FALSE).getOut().getBody(String.class); + assertEquals("New New World", response); + } + + @Test + public void testExchangeSessionProxy() { + String response = sendMessage("direct://proxyexchange", "World", Boolean.FALSE).getOut().getBody(String.class); + assertEquals("Old New World", response); + response = sendMessage("direct://proxyexchange", "World", Boolean.FALSE).getOut().getBody(String.class); + assertEquals("Old New World", response); + } + + @Test + public void testInstanceSession() { + String response = sendMessage("direct://proxyinstance", "World", Boolean.FALSE).getOut().getBody(String.class); + assertEquals("Old New World", response); + response = sendMessage("direct://proxyinstance", "World", Boolean.FALSE).getOut().getBody(String.class); + assertEquals("Old Old World", response); + // we do the instance tests for proxy and http in one test because order + // matters here + response = sendMessage("direct://httpinstance", "World", Boolean.TRUE).getOut().getBody(String.class); + assertEquals("Old Old World", response); + } + + @Test + public void testNoSessionHttp() { + String response = sendMessage("direct://http", "World", Boolean.TRUE).getOut().getBody(String.class); + assertEquals("New New World", response); + response = sendMessage("direct://http", "World", Boolean.TRUE).getOut().getBody(String.class); + assertEquals("New New World", response); + } + + @Test + public void testExchangeSessionHttp() { + String response = sendMessage("direct://httpexchange", "World", Boolean.TRUE).getOut().getBody(String.class); + assertEquals("Old New World", response); + response = sendMessage("direct://httpexchange", "World", Boolean.TRUE).getOut().getBody(String.class); + assertEquals("Old New World", response); + } + + private Exchange sendMessage(String endpoint, String body, Boolean httpApi) { + Exchange exchange = template.send(endpoint, new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.setPattern(ExchangePattern.InOut); + Message inMessage = exchange.getIn(); + inMessage.setHeader(CxfConstants.OPERATION_NAME, "echo"); + inMessage.setHeader(Exchange.HTTP_METHOD, "POST"); + inMessage.setHeader(Exchange.HTTP_PATH, "/echoservice/echo"); + inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, httpApi); + inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, String.class); + inMessage.setHeader(Exchange.ACCEPT_CONTENT_TYPE, "application/json"); + inMessage.setBody(body); + } + }); + return exchange; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/testbean/EchoService.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/testbean/EchoService.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/testbean/EchoService.java new file mode 100644 index 0000000..36bf2ac --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/jaxrs/testbean/EchoService.java @@ -0,0 +1,41 @@ +/** + * 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.cxf.jaxrs.testbean; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Cookie; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.NewCookie; +import javax.ws.rs.core.Response; + +@Path("/echoservice/") +public class EchoService { + @Context + private HttpHeaders headers; + + @POST + @Path("/echo/") + public Response echo(String string) { + Cookie fooCookie = headers.getCookies().get("foo"); + if (fooCookie != null && "bar".equals(fooCookie.getValue())) { + return Response.ok("Old " + string).build(); + } + return Response.ok("New " + string).cookie(new NewCookie("foo", "bar", "/", null, 1, null, -1, false)).build(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/jaxrs/CxfRsSpringProducerSession.xml ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/jaxrs/CxfRsSpringProducerSession.xml b/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/jaxrs/CxfRsSpringProducerSession.xml new file mode 100644 index 0000000..7837077 --- /dev/null +++ b/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/jaxrs/CxfRsSpringProducerSession.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:cxf="http://camel.apache.org/schema/cxf" + xmlns:jaxrs="http://cxf.apache.org/jaxrs" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd + http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd + http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd + "> + <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> + + <jaxrs:server id="restService" + address="http://127.0.0.1:${CXFTestSupport.port1}/CxfRsProducerSessionTest/" + staticSubresourceResolution="true"> + <jaxrs:serviceBeans> + <ref bean="echoService"/> + </jaxrs:serviceBeans> + </jaxrs:server> + + <bean id="echoService" class="org.apache.camel.component.cxf.jaxrs.testbean.EchoService" /> + + <cxf:rsClient id="rsClientProxy" address="http://127.0.0.1:${CXFTestSupport.port1}/CxfRsProducerSessionTest/" + serviceClass="org.apache.camel.component.cxf.jaxrs.testbean.EchoService" + loggingFeatureEnabled="true" /> + + <cxf:rsClient id="rsClientHttp" address="http://127.0.0.1:${CXFTestSupport.port1}/CxfRsProducerSessionTest/"/> + + <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> + <endpoint id="fromEndpoint" uri="jetty://http://127.0.0.1:${CxfRsProducerSessionTest.jetty}/CxfRsProducerSessionTest/echoservice"/> + <route> + <from uri="direct://proxy"/> + <to uri="cxfrs://bean://rsClientProxy"/> + <convertBodyTo type="java.lang.String"/> + <to uri="cxfrs://bean://rsClientProxy"/> + </route> + <route> + <from uri="direct://proxyinstance"/> + <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#instanceCookieHandler"/> + <convertBodyTo type="java.lang.String"/> + <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#instanceCookieHandler"/> + </route> + <route> + <from uri="direct://proxyexchange"/> + <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#exchangeCookieHandler"/> + <convertBodyTo type="java.lang.String"/> + <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#exchangeCookieHandler"/> + </route> + <route> + <from uri="direct://http"/> + <to uri="cxfrs://bean://rsClientHttp"/> + <convertBodyTo type="java.lang.String"/> + <to uri="cxfrs://bean://rsClientHttp"/> + </route> + <route> + <from uri="direct://httpinstance"/> + <to uri="cxfrs://bean://rsClientHttp?cookieHandler=#instanceCookieHandler"/> + <convertBodyTo type="java.lang.String"/> + <to uri="cxfrs://bean://rsClientHttp?cookieHandler=#instanceCookieHandler"/> + </route> + <route> + <from uri="direct://httpexchange"/> + <to uri="cxfrs://bean://rsClientHttp?cookieHandler=#exchangeCookieHandler"/> + <convertBodyTo type="java.lang.String"/> + <to uri="cxfrs://bean://rsClientHttp?cookieHandler=#exchangeCookieHandler"/> + </route> + </camelContext> + + <bean id="instanceCookieHandler" class="org.apache.camel.http.common.cookie.InstanceCookieHandler"/> + <bean id="exchangeCookieHandler" class="org.apache.camel.http.common.cookie.ExchangeCookieHandler"/> +</beans> http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/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 cb6e7ec..8890cca 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 @@ -19,6 +19,7 @@ package org.apache.camel.http.common; import java.net.URI; import java.net.URISyntaxException; +import org.apache.camel.http.common.cookie.CookieHandler; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.spi.HeaderFilterStrategyAware; @@ -129,6 +130,8 @@ public abstract class HttpCommonEndpoint extends DefaultEndpoint implements Head @UriParam(label = "consumer", defaultValue = "false", description = "Configure the consumer to work in async mode") private boolean async; + @UriParam(label = "producer", description = "Configure a cookie handler to maintain a HTTP session") + private CookieHandler cookieHandler; public HttpCommonEndpoint() { } @@ -539,4 +542,15 @@ public abstract class HttpCommonEndpoint extends DefaultEndpoint implements Head public void setAsync(boolean async) { this.async = async; } + + public CookieHandler getCookieHandler() { + return cookieHandler; + } + + /** + * Configure a cookie handler to maintain a HTTP session + */ + public void setCookieHandler(CookieHandler cookieHandler) { + this.cookieHandler = cookieHandler; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/BaseCookieHandler.java ---------------------------------------------------------------------- diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/BaseCookieHandler.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/BaseCookieHandler.java new file mode 100644 index 0000000..5040272 --- /dev/null +++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/BaseCookieHandler.java @@ -0,0 +1,53 @@ +/** + * 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.http.common.cookie; + +import java.io.IOException; +import java.net.CookieManager; +import java.net.CookieStore; +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.camel.Exchange; + +/** + * A basic implementation of a CamelCookie handler based on the JDK + * CookieManager. + */ +public abstract class BaseCookieHandler implements CookieHandler { + + @Override + public void storeCookies(Exchange exchange, URI uri, Map<String, List<String>> headerMap) throws IOException { + getCookieManager(exchange).put(uri, headerMap); + } + + @Override + public Map<String, List<String>> loadCookies(Exchange exchange, URI uri) throws IOException { + // the map is not used, so we do not need to fetch the headers from the + // exchange + return getCookieManager(exchange).get(uri, Collections.emptyMap()); + } + + @Override + public CookieStore getCookieStore(Exchange exchange) { + return getCookieManager(exchange).getCookieStore(); + } + + protected abstract CookieManager getCookieManager(Exchange exchange); +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/CookieHandler.java ---------------------------------------------------------------------- diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/CookieHandler.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/CookieHandler.java new file mode 100644 index 0000000..1f8829d --- /dev/null +++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/CookieHandler.java @@ -0,0 +1,67 @@ +/** + * 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.http.common.cookie; + +import java.io.IOException; +import java.net.CookieStore; +import java.net.URI; +import java.util.List; +import java.util.Map; + +import org.apache.camel.Exchange; + +/** + * The interface for cookie handling will allow components to handle cookies for + * HTTP requests. + * <p> + * Note: The usual cookie policies apply, so cookies will only be handled for + * fully qualified host names in the URI (not local host names like "myhost" or + * "localhost"). + */ +public interface CookieHandler { + + /** + * Store cookies for a HTTP response in the cookie handler + * + * @param exchange the exchange + * @param uri the URI of the called HTTP service + * @param headerMap a map containing the HTTP headers returned by the server + * @throws IOException if the cookies cannot be stored + */ + void storeCookies(Exchange exchange, URI uri, Map<String, List<String>> headerMap) throws IOException; + + /** + * Create cookie headers from the stored cookies appropriate for a given + * URI. + * + * @param exchange the exchange + * @param uri the URI of the called HTTP service + * @return a map containing the cookie headers that can be set to the HTTP + * request. Only cookies that are supposed to be sent to the URI in + * question are considered. + * @throws IOException if the cookies cannot be loaded + */ + Map<String, List<String>> loadCookies(Exchange exchange, URI uri) throws IOException; + + /** + * Get the CookieStore. This method can be used if the is using a CookieHandler by itself. + * + * @param exchange the exchange + * @return the CookieStore + */ + CookieStore getCookieStore(Exchange exchange); +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/ExchangeCookieHandler.java ---------------------------------------------------------------------- diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/ExchangeCookieHandler.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/ExchangeCookieHandler.java new file mode 100644 index 0000000..a661ead --- /dev/null +++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/ExchangeCookieHandler.java @@ -0,0 +1,43 @@ +/** + * 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.http.common.cookie; + +import java.net.CookieManager; + +import org.apache.camel.Exchange; + +/** + * This implementation of the + * {@link org.apache.camel.http.common.cookie.CookieHandler} interface keeps the + * cookies with the {@link org.apache.camel.Exchange}. As this implementation + * does not keep any state you can share it between different endpoints without + * limitation. + */ +public class ExchangeCookieHandler extends BaseCookieHandler { + + @Override + protected CookieManager getCookieManager(Exchange exchange) { + Object handlerObj = exchange.getProperty(Exchange.COOKIE_HANDLER); + if (handlerObj instanceof java.net.CookieManager) { + return (CookieManager)handlerObj; + } else { + CookieManager handler = new CookieManager(); + exchange.setProperty(Exchange.COOKIE_HANDLER, handler); + return handler; + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/InstanceCookieHandler.java ---------------------------------------------------------------------- diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/InstanceCookieHandler.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/InstanceCookieHandler.java new file mode 100644 index 0000000..30795be --- /dev/null +++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/cookie/InstanceCookieHandler.java @@ -0,0 +1,39 @@ +/** + * 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.http.common.cookie; + +import java.net.CookieManager; + +import org.apache.camel.Exchange; + +/** + * This implementation of the + * {@link org.apache.camel.http.common.cookie.CookieHandler} interface keeps the + * cookies with the instance of this object. If it is shared between endpoints + * the sessions will be shared as long as they are sent to the same domain. + */ +public class InstanceCookieHandler extends BaseCookieHandler { + private CookieManager cookieHandler; + + @Override + protected CookieManager getCookieManager(Exchange exchange) { + if (cookieHandler == null) { + cookieHandler = new CookieManager(); + } + return cookieHandler; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http/src/main/docs/http-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-http/src/main/docs/http-component.adoc b/components/camel-http/src/main/docs/http-component.adoc index 5a204d7..fe0e6a1 100644 --- a/components/camel-http/src/main/docs/http-component.adoc +++ b/components/camel-http/src/main/docs/http-component.adoc @@ -147,7 +147,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: +The HTTP component supports 26 endpoint options which are listed below: {% raw %} [width="100%",cols="2,1,1m,1m,5",options="header"] @@ -159,6 +159,7 @@ The HTTP component supports 25 endpoint options which are listed below: | bridgeEndpoint | producer | false | boolean | If the option is true HttpProducer will ignore the Exchange.HTTP_URI header and use the endpoint's URI for request. You may also set the option throwExceptionOnFailure to be false to let the HttpProducer send all the fault response back. | chunked | producer | true | boolean | If this option is false the Servlet will disable the HTTP streaming and set the content-length header on the response | connectionClose | producer | false | boolean | Specifies whether a Connection Close header must be added to HTTP Request. By default connectionClose is false. +| cookieHandler | producer | | CookieHandler | Configure a cookie handler to maintain a HTTP session | copyHeaders | producer | true | boolean | If this option is true then IN exchange headers will be copied to OUT exchange headers according to copy strategy. Setting this to false allows to only include the headers from the HTTP response (not propagating IN headers). | headerFilterStrategy | producer | | HeaderFilterStrategy | To use a custom HeaderFilterStrategy to filter header to and from Camel message. | httpBinding | producer | | HttpBinding | To use a custom HttpBinding to control the mapping between Camel message and HttpClient.