http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
----------------------------------------------------------------------
diff --git 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
index e855f92..8935278 100644
--- 
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
+++ 
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
@@ -23,11 +23,14 @@ import java.io.InputStream;
 import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.camel.CamelExchangeException;
 import org.apache.camel.Exchange;
@@ -51,6 +54,7 @@ import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.HttpVersion;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
 import org.apache.commons.httpclient.methods.FileRequestEntity;
@@ -140,6 +144,21 @@ public class HttpProducer extends DefaultProducer {
             }
         }
         
+        if (getEndpoint().getCookieHandler() != null) {
+            // disable the per endpoint cookie handling
+            method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
+            Map<String, List<String>> cookieHeaders = 
getEndpoint().getCookieHandler().loadCookies(exchange, new 
URI(method.getURI().getEscapedURI()));
+            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);
+                    method.addRequestHeader(key, s);
+                }
+            }
+        }
+
         if (getEndpoint().isConnectionClose()) {
             method.addRequestHeader("Connection", "close");
         }
@@ -175,7 +194,7 @@ public class HttpProducer extends DefaultProducer {
         return (HttpEndpoint) super.getEndpoint();
     }
 
-    protected void populateResponse(Exchange exchange, HttpMethod method, 
Message in, HeaderFilterStrategy strategy, int responseCode) throws 
IOException, ClassNotFoundException {
+    protected void populateResponse(Exchange exchange, HttpMethod method, 
Message in, HeaderFilterStrategy strategy, int responseCode) throws 
IOException, ClassNotFoundException, URISyntaxException {
         //We just make the out message is not create when extractResponseBody 
throws exception,
         Object response = extractResponseBody(method, exchange, 
getEndpoint().isIgnoreResponseBody());
         Message answer = exchange.getOut();
@@ -186,9 +205,11 @@ public class HttpProducer extends DefaultProducer {
 
         // propagate HTTP response headers
         Header[] headers = method.getResponseHeaders();
+        Map<String, List<String>> m = new HashMap<String, List<String>>();
         for (Header header : headers) {
             String name = header.getName();
             String value = header.getValue();
+            m.put(name, Collections.singletonList(value));
             if (name.toLowerCase().equals("content-type")) {
                 name = Exchange.CONTENT_TYPE;
                 exchange.setProperty(Exchange.CHARSET_NAME, 
IOHelper.getCharsetNameFromContentType(value));
@@ -200,7 +221,10 @@ public class HttpProducer extends DefaultProducer {
                 HttpHelper.appendHeader(answer.getHeaders(), name, extracted);
             }
         }
-
+        // handle cookies
+        if (getEndpoint().getCookieHandler() != null) {
+            getEndpoint().getCookieHandler().storeCookies(exchange, new 
URI(method.getURI().getEscapedURI()), m);
+        }
         // endpoint might be configured to copy headers from in to out
         // to avoid overriding existing headers with old values just
         // filter the http protocol headers
@@ -209,12 +233,20 @@ public class HttpProducer extends DefaultProducer {
         }
     }
 
-    protected Exception populateHttpOperationFailedException(Exchange 
exchange, HttpMethod method, int responseCode) throws IOException, 
ClassNotFoundException {
+    protected Exception populateHttpOperationFailedException(Exchange 
exchange, HttpMethod method, int responseCode) throws IOException, 
ClassNotFoundException, URISyntaxException {
         Exception answer;
 
         String uri = method.getURI().toString();
         String statusText = method.getStatusLine() != null ? 
method.getStatusLine().getReasonPhrase() : null;
         Map<String, String> headers = 
extractResponseHeaders(method.getResponseHeaders());
+        // handle cookies
+        if (getEndpoint().getCookieHandler() != null) {
+            Map<String, List<String>> m = new HashMap<String, List<String>>();
+            for (Entry<String, String> e : headers.entrySet()) {
+                m.put(e.getKey(), Collections.singletonList(e.getValue()));
+            }
+            getEndpoint().getCookieHandler().storeCookies(exchange, new 
URI(method.getURI().getEscapedURI()), m);
+        }
 
         Object responseBody = extractResponseBody(method, exchange, 
getEndpoint().isIgnoreResponseBody());
         if (transferException && responseBody != null && responseBody 
instanceof Exception) {

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerSessionTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerSessionTest.java
 
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerSessionTest.java
new file mode 100644
index 0000000..d33e792
--- /dev/null
+++ 
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerSessionTest.java
@@ -0,0 +1,117 @@
+/**
+ * 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.http;
+
+import java.net.InetSocketAddress;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.http.handler.SessionReflectionHandler;
+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.AvailablePortFinder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class HttpProducerSessionTest extends CamelTestSupport {
+    private static volatile int port;
+    private static Server localServer;
+
+    @BeforeClass
+    public static void initServer() throws Exception {
+        port = AvailablePortFinder.getNextAvailable(24000);
+        localServer = new Server(new InetSocketAddress("127.0.0.1", port));
+        ContextHandler contextHandler = new ContextHandler();
+        contextHandler.setContextPath("/session");
+        SessionHandler sessionHandler = new SessionHandler();
+        sessionHandler.setHandler(new SessionReflectionHandler());
+        contextHandler.setHandler(sessionHandler);
+        localServer.setHandler(contextHandler);
+        localServer.start();
+    }
+
+    @AfterClass
+    public static void shutdownServer() throws Exception {
+        localServer.stop();
+    }
+    
+    @Test
+    public void testNoSession() throws Exception {
+        // the camel-http component will handle cookies at endpoint level
+        getMockEndpoint("mock:result").expectedBodiesReceived("New New World", 
"Old Old World");
+        template.sendBody("direct:start", "World");
+        template.sendBody("direct:start", "World");
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testInstanceSession() 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 testExchangeSession() 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 "http://127.0.0.1:"; + port + "/session/";
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .to(getTestServerEndpointSessionUrl())
+                    .to(getTestServerEndpointSessionUrl())
+                    .to("mock:result");
+
+                from("direct:instance")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to("mock:result");
+
+                from("direct:exchange")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#exchangeCookieHandler")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#exchangeCookieHandler")
+                    .to("mock:result");
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http/src/test/java/org/apache/camel/component/http/handler/SessionReflectionHandler.java
----------------------------------------------------------------------
diff --git 
a/components/camel-http/src/test/java/org/apache/camel/component/http/handler/SessionReflectionHandler.java
 
b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/SessionReflectionHandler.java
new file mode 100644
index 0000000..63c13e3
--- /dev/null
+++ 
b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/SessionReflectionHandler.java
@@ -0,0 +1,47 @@
+/**
+ * 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.http.handler;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.camel.util.IOHelper;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+public class SessionReflectionHandler extends AbstractHandler {
+
+    @Override
+    public void handle(String target, Request baseRequest, HttpServletRequest 
request, HttpServletResponse response) throws IOException, ServletException {
+        HttpSession session = request.getSession();
+        OutputStream os = response.getOutputStream();
+        baseRequest.setHandled(true);
+        if (session.getAttribute("foo") == null) {
+            session.setAttribute("foo", "bar");
+            os.write("New ".getBytes());
+        } else {
+            os.write("Old ".getBytes());
+        }
+        IOHelper.copyAndCloseInput(request.getInputStream(), os);
+        response.setStatus(HttpServletResponse.SC_OK);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http4/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-http4/pom.xml b/components/camel-http4/pom.xml
index 8209bce..2c54bd0 100644
--- a/components/camel-http4/pom.xml
+++ b/components/camel-http4/pom.xml
@@ -95,6 +95,12 @@
       <classifier>tests</classifier>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>${jetty-version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http4/src/main/docs/http4-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-http4/src/main/docs/http4-component.adoc 
b/components/camel-http4/src/main/docs/http4-component.adoc
index f90dcdd..c45269d 100644
--- a/components/camel-http4/src/main/docs/http4-component.adoc
+++ b/components/camel-http4/src/main/docs/http4-component.adoc
@@ -92,7 +92,7 @@ The HTTP4 component supports 13 options which are listed 
below.
 
 
 // endpoint options: START
-The HTTP4 component supports 31 endpoint options which are listed below:
+The HTTP4 component supports 32 endpoint options which are listed below:
 
 {% raw %}
 [width="100%",cols="2,1,1m,1m,5",options="header"]
@@ -106,7 +106,8 @@ The HTTP4 component supports 31 endpoint options which are 
listed below:
 | 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
 | clearExpiredCookies | producer | true | boolean | Whether to clear expired 
cookies before sending the HTTP request. This ensures the cookies store does 
not keep growing by adding new cookies which is newer removed when they are 
expired.
 | connectionClose | producer | false | boolean | Specifies whether a 
Connection Close header must be added to HTTP Request. By default 
connectionClose is false.
-| cookieStore | producer |  | CookieStore | To use a custom 
org.apache.http.client.CookieStore. By default the 
org.apache.http.impl.client.BasicCookieStore is used which is an in-memory only 
cookie store. Notice if bridgeEndpoint=true then the cookie store is forced to 
be a noop cookie store as cookie shouldn't be stored as we are just bridging 
(eg acting as a proxy).
+| cookieHandler | producer |  | CookieHandler | Configure a cookie handler to 
maintain a HTTP session
+| cookieStore | producer |  | CookieStore | To use a custom 
org.apache.http.client.CookieStore. By default the 
org.apache.http.impl.client.BasicCookieStore is used which is an in-memory only 
cookie store. Notice if bridgeEndpoint=true then the cookie store is forced to 
be a noop cookie store as cookie shouldn't be stored as we are just bridging 
(eg acting as a proxy). If a cookieHandler is set then the cookie store is also 
forced to be a noop cookie store as cookie handling is then performed by the 
cookieHandler.
 | 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.

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpEndpoint.java
 
b/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpEndpoint.java
index 34161e6..01d1b7e 100644
--- 
a/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpEndpoint.java
+++ 
b/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpEndpoint.java
@@ -27,6 +27,7 @@ import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.http.common.HttpCommonEndpoint;
 import org.apache.camel.http.common.HttpHelper;
+import org.apache.camel.http.common.cookie.CookieHandler;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.util.IOHelper;
@@ -269,11 +270,19 @@ public class HttpEndpoint extends HttpCommonEndpoint {
      * By default the org.apache.http.impl.client.BasicCookieStore is used 
which is an in-memory only cookie store.
      * Notice if bridgeEndpoint=true then the cookie store is forced to be a 
noop cookie store as cookie
      * shouldn't be stored as we are just bridging (eg acting as a proxy).
+     * If a cookieHandler is set then the cookie store is also forced to be a 
noop cookie store as cookie handling is
+     * then performed by the cookieHandler.
      */
     public void setCookieStore(CookieStore cookieStore) {
         this.cookieStore = cookieStore;
     }
 
+    public void setCookieHandler(CookieHandler cookieHandler) {
+        super.setCookieHandler(cookieHandler);
+        // if we set an explicit cookie handler 
+        this.cookieStore = new NoopCookieStore();
+    }
+
     public boolean isAuthenticationPreemptive() {
         return authenticationPreemptive;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpProducer.java
----------------------------------------------------------------------
diff --git 
a/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpProducer.java
 
b/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpProducer.java
index dc60660..085d3d7 100644
--- 
a/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpProducer.java
+++ 
b/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpProducer.java
@@ -26,11 +26,13 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.camel.CamelExchangeException;
 import org.apache.camel.Exchange;
@@ -155,6 +157,19 @@ public class HttpProducer extends DefaultProducer {
             }
         }
 
+        if (getEndpoint().getCookieHandler() != null) {
+            Map<String, List<String>> cookieHeaders = 
getEndpoint().getCookieHandler().loadCookies(exchange, httpRequest.getURI());
+            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);
+                    httpRequest.addHeader(key, s);
+                }
+            }
+        }
+
         //In reverse proxy applications it can be desirable for the downstream 
service to see the original Host header
         //if this option is set, and the exchange Host header is not null, we 
will set it's current value on the httpRequest
         if (getEndpoint().isPreserveHostHeader()) {
@@ -236,9 +251,11 @@ public class HttpProducer extends DefaultProducer {
 
         // propagate HTTP response headers
         Header[] headers = httpResponse.getAllHeaders();
+        Map<String, List<String>> m = new HashMap<String, List<String>>();
         for (Header header : headers) {
             String name = header.getName();
             String value = header.getValue();
+            m.put(name, Collections.singletonList(value));
             if (name.toLowerCase().equals("content-type")) {
                 name = Exchange.CONTENT_TYPE;
                 exchange.setProperty(Exchange.CHARSET_NAME, 
IOHelper.getCharsetNameFromContentType(value));
@@ -249,7 +266,10 @@ public class HttpProducer extends DefaultProducer {
                 HttpHelper.appendHeader(answer.getHeaders(), name, extracted);
             }
         }
-
+        // handle cookies
+        if (getEndpoint().getCookieHandler() != null) {
+            getEndpoint().getCookieHandler().storeCookies(exchange, 
httpRequest.getURI(), m);
+        }
         // endpoint might be configured to copy headers from in to out
         // to avoid overriding existing headers with old values just
         // filter the http protocol headers
@@ -264,6 +284,14 @@ public class HttpProducer extends DefaultProducer {
         String uri = httpRequest.getURI().toString();
         String statusText = httpResponse.getStatusLine() != null ? 
httpResponse.getStatusLine().getReasonPhrase() : null;
         Map<String, String> headers = 
extractResponseHeaders(httpResponse.getAllHeaders());
+        // handle cookies
+        if (getEndpoint().getCookieHandler() != null) {
+            Map<String, List<String>> m = new HashMap<String, List<String>>();
+            for (Entry<String, String> e : headers.entrySet()) {
+                m.put(e.getKey(), Collections.singletonList(e.getValue()));
+            }
+            getEndpoint().getCookieHandler().storeCookies(exchange, 
httpRequest.getURI(), m);
+        }
 
         Object responseBody = extractResponseBody(httpRequest, httpResponse, 
exchange, getEndpoint().isIgnoreResponseBody());
         if (transferException && responseBody != null && responseBody 
instanceof Exception) {

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http4/src/test/java/org/apache/camel/component/http4/HttpProducerSessionTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-http4/src/test/java/org/apache/camel/component/http4/HttpProducerSessionTest.java
 
b/components/camel-http4/src/test/java/org/apache/camel/component/http4/HttpProducerSessionTest.java
new file mode 100644
index 0000000..0a81d41
--- /dev/null
+++ 
b/components/camel-http4/src/test/java/org/apache/camel/component/http4/HttpProducerSessionTest.java
@@ -0,0 +1,117 @@
+/**
+ * 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.http4;
+
+import java.net.InetSocketAddress;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.http4.handler.SessionReflectionHandler;
+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.AvailablePortFinder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class HttpProducerSessionTest extends CamelTestSupport {
+    private static volatile int port;
+    private static Server localServer;
+
+    @BeforeClass
+    public static void initServer() throws Exception {
+        port = AvailablePortFinder.getNextAvailable(24000);
+        localServer = new Server(new InetSocketAddress("127.0.0.1", port));
+        ContextHandler contextHandler = new ContextHandler();
+        contextHandler.setContextPath("/session");
+        SessionHandler sessionHandler = new SessionHandler();
+        sessionHandler.setHandler(new SessionReflectionHandler());
+        contextHandler.setHandler(sessionHandler);
+        localServer.setHandler(contextHandler);
+        localServer.start();
+    }
+
+    @AfterClass
+    public static void shutdownServer() throws Exception {
+        localServer.stop();
+    }
+
+    @Test
+    public void testNoSession() 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 testInstanceSession() 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 testExchangeSession() 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());
+        jndiRegistry.bind("noopCookieStore", new NoopCookieStore());
+        return jndiRegistry;
+    }
+
+    private String getTestServerEndpointSessionUrl() {
+        // session handling will not work for localhost
+        return "http4://127.0.0.1:" + port + "/session/";
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieStore=#noopCookieStore")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieStore=#noopCookieStore")
+                    .to("mock:result");
+
+                from("direct:instance")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to("mock:result");
+
+                from("direct:exchange")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#exchangeCookieHandler")
+                    .to(getTestServerEndpointSessionUrl() + 
"?cookieHandler=#exchangeCookieHandler")
+                    .to("mock:result");
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-http4/src/test/java/org/apache/camel/component/http4/handler/SessionReflectionHandler.java
----------------------------------------------------------------------
diff --git 
a/components/camel-http4/src/test/java/org/apache/camel/component/http4/handler/SessionReflectionHandler.java
 
b/components/camel-http4/src/test/java/org/apache/camel/component/http4/handler/SessionReflectionHandler.java
new file mode 100644
index 0000000..0358ce5
--- /dev/null
+++ 
b/components/camel-http4/src/test/java/org/apache/camel/component/http4/handler/SessionReflectionHandler.java
@@ -0,0 +1,47 @@
+/**
+ * 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.http4.handler;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.camel.util.IOHelper;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+public class SessionReflectionHandler extends AbstractHandler {
+
+    @Override
+    public void handle(String target, Request baseRequest, HttpServletRequest 
request, HttpServletResponse response) throws IOException, ServletException {
+        HttpSession session = request.getSession();
+        OutputStream os = response.getOutputStream();
+        baseRequest.setHandled(true);
+        if (session.getAttribute("foo") == null) {
+            session.setAttribute("foo", "bar");
+            os.write("New ".getBytes());
+        } else {
+            os.write("Old ".getBytes());
+        }
+        IOHelper.copyAndCloseInput(request.getInputStream(), os);
+        response.setStatus(HttpServletResponse.SC_OK);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java
 
b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java
index 8cfc32a..9d2a291 100644
--- 
a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java
+++ 
b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpEndpoint.java
@@ -29,6 +29,7 @@ import org.apache.camel.Producer;
 import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.http.common.HttpCommonEndpoint;
 import org.apache.camel.http.common.HttpConsumer;
+import org.apache.camel.http.common.cookie.CookieHandler;
 import org.apache.camel.impl.SynchronousDelegateProducer;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.util.IntrospectionSupport;
@@ -129,6 +130,8 @@ public abstract class JettyHttpEndpoint extends 
HttpCommonEndpoint {
             description = "To configure security using SSLContextParameters")
     @Deprecated
     private String sslContextParametersRef;
+    @UriParam(label = "producer", description = "Configure a cookie handler to 
maintain a HTTP session")
+    private CookieHandler cookieHandler;
 
     public JettyHttpEndpoint(JettyHttpComponent component, String uri, URI 
httpURL) throws URISyntaxException {
         super(uri, component, httpURL);
@@ -437,6 +440,17 @@ public abstract class JettyHttpEndpoint extends 
HttpCommonEndpoint {
         this.enableCORS = enableCORS;
     }
 
+    public CookieHandler getCookieHandler() {
+        return cookieHandler;
+    }
+
+    /**
+     * Configure a cookie handler to maintain a HTTP session
+     */
+    public void setCookieHandler(CookieHandler cookieHandler) {
+        this.cookieHandler = cookieHandler;
+    }
+
     public abstract JettyContentExchange createContentExchange();
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpProducer.java
----------------------------------------------------------------------
diff --git 
a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpProducer.java
 
b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpProducer.java
index e0595bc..e8a7f1b 100644
--- 
a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpProducer.java
+++ 
b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpProducer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.jetty;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.Serializable;
+import java.net.CookieStore;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -225,7 +226,7 @@ public class JettyHttpProducer extends DefaultAsyncProducer 
implements AsyncProc
                 }
             }
         }
-        
+
         if (getEndpoint().isConnectionClose()) {
             httpExchange.addRequestHeader("Connection", "close");
         }
@@ -244,6 +245,15 @@ public class JettyHttpProducer extends 
DefaultAsyncProducer implements AsyncProc
         if (LOG.isDebugEnabled()) {
             LOG.debug("Sending HTTP request to: {}", httpExchange.getUrl());
         }
+
+        if (getEndpoint().getCookieHandler() != null) {
+            // this will store the cookie in the cookie store
+            CookieStore cookieStore = 
getEndpoint().getCookieHandler().getCookieStore(exchange);
+            if (!client.getCookieStore().equals(cookieStore)) {
+                client.setCookieStore(cookieStore);
+            }
+        }
+
         httpExchange.send(client);
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-jetty9/src/main/docs/jetty-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/main/docs/jetty-component.adoc 
b/components/camel-jetty9/src/main/docs/jetty-component.adoc
index febf26e..9aae5a7 100644
--- a/components/camel-jetty9/src/main/docs/jetty-component.adoc
+++ b/components/camel-jetty9/src/main/docs/jetty-component.adoc
@@ -106,7 +106,7 @@ The Jetty 9 component supports 31 options which are listed 
below.
 
 
 // endpoint options: START
-The Jetty 9 component supports 53 endpoint options which are listed below:
+The Jetty 9 component supports 54 endpoint options which are listed below:
 
 {% raw %}
 [width="100%",cols="2,1,1m,1m,5",options="header"]
@@ -145,6 +145,7 @@ The Jetty 9 component supports 53 endpoint options which 
are listed below:
 | authMethodPriority | producer |  | String | Authentication method for proxy 
either as Basic Digest or NTLM.
 | 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.
 | 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).
 | httpClientMaxThreads | producer | 254 | Integer | To set a value for maximum 
number of threads in HttpClient thread pool. This setting override any setting 
configured on component level. Notice that both a min and max size must be 
configured. If not set it default to max 254 threads used in Jettys thread pool.
 | httpClientMinThreads | producer | 8 | Integer | To set a value for minimum 
number of threads in HttpClient thread pool. This setting override any setting 
configured on component level. Notice that both a min and max size must be 
configured. If not set it default to min 8 threads used in Jettys thread pool.

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/jettyproducer/JettyHttpProducerSessionTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/jettyproducer/JettyHttpProducerSessionTest.java
 
b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/jettyproducer/JettyHttpProducerSessionTest.java
new file mode 100644
index 0000000..5aa7a63
--- /dev/null
+++ 
b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/jettyproducer/JettyHttpProducerSessionTest.java
@@ -0,0 +1,120 @@
+/**
+ * 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.jettyproducer;
+
+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.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class JettyHttpProducerSessionTest extends CamelTestSupport {
+    private static volatile int port;
+
+    @BeforeClass
+    public static void initPort() throws Exception {
+        port = AvailablePortFinder.getNextAvailable(24000);
+    }
+
+    @Test
+    public void testNoSession() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("New New World", 
"Old Old World");
+        template.sendBody("direct:start", "World");
+        template.sendBody("direct:start", "World");
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testInstanceSession() 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 testExchangeSession() 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 "http://127.0.0.1:"; + port + "/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("jetty://" + getTestServerEndpointSessionUrl())
+                    .to("jetty://" + getTestServerEndpointSessionUrl())
+                    .to("mock:result");
+
+                from("direct:instance")
+                    .to("jetty://" + getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to("jetty://" + getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to("mock:result");
+
+                from("direct:exchange")
+                    .to("jetty://" + getTestServerEndpointSessionUrl() + 
"?cookieHandler=#exchangeCookieHandler")
+                    .to("jetty://" + 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-netty4-http/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/pom.xml 
b/components/camel-netty4-http/pom.xml
index 09e881b..87f46dc 100644
--- a/components/camel-netty4-http/pom.xml
+++ b/components/camel-netty4-http/pom.xml
@@ -41,7 +41,11 @@
       <artifactId>camel-netty4</artifactId>
     </dependency>
     <!-- we use netty-all as dependency which has HTTP included -->
- 
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-http-common</artifactId>
+    </dependency>
+
     <!-- testing -->
     <dependency>
       <groupId>com.jcraft</groupId>
@@ -80,6 +84,11 @@
       <artifactId>camel-swagger-java</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jetty9</artifactId>
+      <scope>test</scope>
+    </dependency>
 
     <!-- logging -->   
     <dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc
----------------------------------------------------------------------
diff --git 
a/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc 
b/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc
index 21d994a..f122836 100644
--- a/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc
+++ b/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc
@@ -109,7 +109,7 @@ The Netty4 HTTP component supports 6 options which are 
listed below.
 
 
 // endpoint options: START
-The Netty4 HTTP component supports 82 endpoint options which are listed below:
+The Netty4 HTTP component supports 83 endpoint options which are listed below:
 
 {% raw %}
 [width="100%",cols="2,1,1m,1m,5",options="header"]
@@ -151,6 +151,7 @@ The Netty4 HTTP component supports 82 endpoint options 
which are listed below:
 | workerCount | consumer (advanced) |  | int | When netty works on nio mode it 
uses default workerCount parameter from Netty which is cpu_core_threads2. User 
can use this operation to override the default workerCount from Netty
 | workerGroup | consumer (advanced) |  | EventLoopGroup | To use a explicit 
EventLoopGroup as the boss thread pool. For example to share a thread pool with 
multiple consumers. By default each consumer has their own boss pool with 1 
core thread.
 | connectTimeout | producer | 10000 | int | Time to wait for a socket 
connection to be available. Value is in millis.
+| cookieHandler | producer |  | CookieHandler | Configure a cookie handler to 
maintain a HTTP session
 | requestTimeout | producer |  | long | Allows to use a timeout for the Netty 
producer when calling a remote server. By default no timeout is in use. The 
value is in milli seconds so eg 30000 is 30 seconds. The requestTimeout is 
using Netty's ReadTimeoutHandler to trigger the timeout.
 | reuseChannel | producer | false | boolean | This option allows producers to 
reuse the same Netty Channel for the lifecycle of processing the Exchange. This 
is useable if you need to call a server multiple times in a Camel route and 
want to use the same network connection. When using this the channel is not 
returned to the connection pool until the Exchange is done; or disconnected if 
the disconnect option is set to true. The reused Channel is stored on the 
Exchange as an exchange property with the key link NettyConstantsNETTY_CHANNEL 
which allows you to obtain the channel during routing and use it as well.
 | throwExceptionOnFailure | producer | true | boolean | Option to disable 
throwing the HttpOperationFailedException in case of failed responses from the 
remote server. This allows you to get all responses regardless of the HTTP 
status code.

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpEndpoint.java
 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpEndpoint.java
index 43adfcf..28a1e23 100644
--- 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpEndpoint.java
+++ 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpEndpoint.java
@@ -29,6 +29,7 @@ import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.netty4.NettyConfiguration;
 import org.apache.camel.component.netty4.NettyEndpoint;
+import org.apache.camel.http.common.cookie.CookieHandler;
 import org.apache.camel.impl.SynchronousDelegateProducer;
 import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.spi.HeaderFilterStrategyAware;
@@ -67,6 +68,8 @@ public class NettyHttpEndpoint extends NettyEndpoint 
implements AsyncEndpoint, H
     private NettyHttpSecurityConfiguration securityConfiguration;
     @UriParam(label = "consumer,security", prefix = "securityConfiguration.", 
multiValue = true)
     private Map<String, Object> securityOptions; // to include in component 
docs
+    @UriParam(label = "producer")
+    private CookieHandler cookieHandler;
 
     public NettyHttpEndpoint(String endpointUri, NettyHttpComponent component, 
NettyConfiguration configuration) {
         super(endpointUri, component, configuration);
@@ -227,6 +230,17 @@ public class NettyHttpEndpoint extends NettyEndpoint 
implements AsyncEndpoint, H
         this.securityOptions = securityOptions;
     }
 
+    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-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpProducer.java
----------------------------------------------------------------------
diff --git 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpProducer.java
 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpProducer.java
index 8a6b540..31710e0 100644
--- 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpProducer.java
+++ 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpProducer.java
@@ -17,9 +17,10 @@
 package org.apache.camel.component.netty4.http;
 
 import java.net.URI;
+import java.util.List;
+import java.util.Map;
 
 import io.netty.handler.codec.http.FullHttpResponse;
-import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpRequest;
 import io.netty.handler.codec.http.HttpUtil;
 import io.netty.util.ReferenceCountUtil;
@@ -75,6 +76,16 @@ public class NettyHttpProducer extends NettyProducer {
             exchange.getIn().removeHeader("host");
         }
 
+        if (getEndpoint().getCookieHandler() != null) {
+            Map<String, List<String>> cookieHeaders = 
getEndpoint().getCookieHandler().loadCookies(exchange, new URI(actualUri));
+            for (Map.Entry<String, List<String>> entry : 
cookieHeaders.entrySet()) {
+                String key = entry.getKey();
+                if (entry.getValue().size() > 0) {
+                    request.headers().add(key, entry.getValue());
+                }
+            }
+        }
+
         // need to release the request when we are done
         exchange.addOnCompletion(new SynchronizationAdapter() {
             @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpClientChannelHandler.java
----------------------------------------------------------------------
diff --git 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpClientChannelHandler.java
 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpClientChannelHandler.java
index 04b0ad1..3f56e3d 100644
--- 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpClientChannelHandler.java
+++ 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpClientChannelHandler.java
@@ -16,9 +16,13 @@
  */
 package org.apache.camel.component.netty4.http.handlers;
 
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.http.FullHttpResponse;
-import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpUtil;
 
 import org.apache.camel.Exchange;
@@ -46,6 +50,16 @@ public class HttpClientChannelHandler extends 
ClientChannelHandler {
             // just want to make sure we close the channel if the keepAlive is 
not true
             
exchange.setProperty(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, true);
         }
+        // handle cookies
+        if (producer.getEndpoint().getCookieHandler() != null) {
+            String actualUri = exchange.getIn().getHeader(Exchange.HTTP_URL, 
String.class);
+            URI uri = new URI(actualUri);
+            Map<String, List<String>> m = new HashMap<String, List<String>>();
+            for (String name : response.headers().names()) {
+                m.put(name, response.headers().getAll(name));
+            }
+            producer.getEndpoint().getCookieHandler().storeCookies(exchange, 
uri, m);
+        }
         // use the binding
         return 
producer.getEndpoint().getNettyHttpBinding().toCamelMessage(response, exchange, 
producer.getConfiguration());
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpProducerSessionTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpProducerSessionTest.java
 
b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpProducerSessionTest.java
new file mode 100644
index 0000000..b5f55d1
--- /dev/null
+++ 
b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/NettyHttpProducerSessionTest.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.netty4.http;
+
+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 NettyHttpProducerSessionTest extends BaseNettyTest {
+
+    @Test
+    public void testNoSession() 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 testInstanceSession() 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 testExchangeSession() 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 "http://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("netty4-http:" + getTestServerEndpointSessionUrl())
+                    .to("netty4-http:" + getTestServerEndpointSessionUrl())
+                    .to("mock:result");
+
+                from("direct:instance")
+                    .to("netty4-http:" + getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to("netty4-http:" + getTestServerEndpointSessionUrl() + 
"?cookieHandler=#instanceCookieHandler")
+                    .to("mock:result");
+
+                from("direct:exchange")
+                    .to("netty4-http:" + getTestServerEndpointSessionUrl() + 
"?cookieHandler=#exchangeCookieHandler")
+                    .to("netty4-http:" + 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-restlet/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-restlet/pom.xml b/components/camel-restlet/pom.xml
index 9cb2b72..8555deb 100644
--- a/components/camel-restlet/pom.xml
+++ b/components/camel-restlet/pom.xml
@@ -51,6 +51,10 @@
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-http-common</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>org.restlet.jee</groupId>

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-restlet/src/main/docs/restlet-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-restlet/src/main/docs/restlet-component.adoc 
b/components/camel-restlet/src/main/docs/restlet-component.adoc
index b47b775..779addf 100644
--- a/components/camel-restlet/src/main/docs/restlet-component.adoc
+++ b/components/camel-restlet/src/main/docs/restlet-component.adoc
@@ -102,7 +102,7 @@ The Restlet component supports 20 options which are listed 
below.
 
 
 // endpoint options: START
-The Restlet component supports 21 endpoint options which are listed below:
+The Restlet component supports 22 endpoint options which are listed below:
 
 {% raw %}
 [width="100%",cols="2,1,1m,1m,5",options="header"]
@@ -119,6 +119,7 @@ The Restlet component supports 21 endpoint options which 
are listed below:
 | 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.
 | connectTimeout | producer | 30000 | int | The Client will give up connection 
if the connection is timeout 0 for unlimited wait.
+| cookieHandler | producer |  | CookieHandler | Configure a cookie handler to 
maintain a HTTP session
 | socketTimeout | producer | 30000 | int | The Client socket receive timeout 0 
for unlimited wait.
 | throwExceptionOnFailure | producer | true | boolean | Whether to throw 
exception on a producer failure. If this option is false then the http status 
code is set as a message header which can be checked if it has an error value.
 | autoCloseStream | producer (advanced) | false | boolean | Whether to auto 
close the stream representation as response from calling a REST service using 
the restlet producer. If the response is streaming and the option 
streamRepresentation is enabled then you may want to auto close the InputStream 
from the streaming response to ensure the input stream is closed when the Camel 
Exchange is done being routed. However if you need to read the stream outside a 
Camel route you may need to not auto close the stream.

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletEndpoint.java
 
b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletEndpoint.java
index ec2871b..be23c6c 100644
--- 
a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletEndpoint.java
+++ 
b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletEndpoint.java
@@ -27,6 +27,7 @@ import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;
 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;
@@ -84,6 +85,8 @@ public class RestletEndpoint extends DefaultEndpoint 
implements AsyncEndpoint, H
     private boolean streamRepresentation;
     @UriParam(label = "producer,advanced")
     private boolean autoCloseStream;
+    @UriParam(label = "producer")
+    private CookieHandler cookieHandler;
 
     public RestletEndpoint(RestletComponent component, String remaining) 
throws Exception {
         super(remaining, component);
@@ -343,6 +346,17 @@ public class RestletEndpoint extends DefaultEndpoint 
implements AsyncEndpoint, H
         this.autoCloseStream = autoCloseStream;
     }
 
+    public CookieHandler getCookieHandler() {
+        return cookieHandler;
+    }
+
+    /**
+     * Configure a cookie handler to maintain a HTTP session
+     */
+    public void setCookieHandler(CookieHandler cookieHandler) {
+        this.cookieHandler = cookieHandler;
+    }
+
     // Update the endpointUri with the restlet method information
     protected void updateEndpointUri() {
         String endpointUri = getEndpointUri();

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletProducer.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletProducer.java
 
b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletProducer.java
index 97116fb..8b107bb 100644
--- 
a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletProducer.java
+++ 
b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletProducer.java
@@ -16,7 +16,12 @@
  */
 package org.apache.camel.component.restlet;
 
+import java.io.IOException;
+import java.net.CookieStore;
+import java.net.HttpCookie;
+import java.net.URI;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -30,6 +35,9 @@ import org.restlet.Context;
 import org.restlet.Request;
 import org.restlet.Response;
 import org.restlet.Uniform;
+import org.restlet.data.Cookie;
+import org.restlet.data.CookieSetting;
+import org.restlet.util.Series;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,14 +88,17 @@ public class RestletProducer extends DefaultAsyncProducer {
         final RestletBinding binding = endpoint.getRestletBinding();
         Request request;
         String resourceUri = buildUri(endpoint, exchange);
+        URI uri = new URI(resourceUri);
         request = new Request(endpoint.getRestletMethod(), resourceUri);
         binding.populateRestletRequestFromExchange(request, exchange);
+        loadCookies(exchange, uri, request);
 
         LOG.debug("Sending request synchronously: {} for exchangeId: {}", 
request, exchange.getExchangeId());
         Response response = client.handle(request);
         LOG.debug("Received response synchronously: {} for exchangeId: {}", 
response, exchange.getExchangeId());
         if (response != null) {
             Integer respCode = response.getStatus().getCode();
+            storeCookies(exchange, uri, response);
             if (respCode > 207 && throwException) {
                 
exchange.setException(populateRestletProducerException(exchange, response, 
respCode));
             } else {
@@ -96,6 +107,40 @@ public class RestletProducer extends DefaultAsyncProducer {
         }
     }
 
+    private void storeCookies(Exchange exchange, URI uri, Response response) {
+        RestletEndpoint endpoint = (RestletEndpoint) getEndpoint();
+        if (endpoint.getCookieHandler() != null) {
+            Series<CookieSetting> cookieSettings = 
response.getCookieSettings();
+            CookieStore cookieJar = 
endpoint.getCookieHandler().getCookieStore(exchange);
+            for (CookieSetting s:cookieSettings) {
+                HttpCookie cookie = new HttpCookie(s.getName(), s.getValue());
+                cookie.setComment(s.getComment());
+                cookie.setDomain(s.getDomain());
+                cookie.setMaxAge(s.getMaxAge());
+                cookie.setPath(s.getPath());
+                cookie.setSecure(s.isSecure());
+                cookie.setVersion(s.getVersion());
+                cookieJar.add(uri, cookie);
+            }
+        }
+    }
+
+    private void loadCookies(Exchange exchange, URI uri, Request request) 
throws IOException {
+        RestletEndpoint endpoint = (RestletEndpoint) getEndpoint();
+        if (endpoint.getCookieHandler() != null) {
+            Series<Cookie> cookies = request.getCookies();
+            Map<String, List<String>> cookieHeaders = 
endpoint.getCookieHandler().loadCookies(exchange, uri);
+            // parse the cookies
+            for (String cookieHeader : cookieHeaders.keySet()) {
+                for (String cookieStr : cookieHeaders.get(cookieHeader)) {
+                    for (HttpCookie cookie : HttpCookie.parse(cookieStr)) {
+                        cookies.add(new Cookie(cookie.getVersion(), 
cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getDomain()));
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public boolean process(final Exchange exchange, final AsyncCallback 
callback) {
         RestletEndpoint endpoint = (RestletEndpoint) getEndpoint();
@@ -117,8 +162,10 @@ public class RestletProducer extends DefaultAsyncProducer {
         Request request;
         try {
             String resourceUri = buildUri(endpoint, exchange);
+            URI uri = new URI(resourceUri);
             request = new Request(endpoint.getRestletMethod(), resourceUri);
             binding.populateRestletRequestFromExchange(request, exchange);
+            loadCookies(exchange, uri, request);
         } catch (Throwable e) {
             // break out in case of exception
             exchange.setException(e);
@@ -134,7 +181,10 @@ public class RestletProducer extends DefaultAsyncProducer {
                 LOG.debug("Received response asynchronously: {} for 
exchangeId: {}", response, exchange.getExchangeId());
                 try {
                     if (response != null) {
+                        String resourceUri = buildUri(endpoint, exchange);
+                        URI uri = new URI(resourceUri);
                         Integer respCode = response.getStatus().getCode();
+                        storeCookies(exchange, uri, response);
                         if (respCode > 207 && throwException) {
                             
exchange.setException(populateRestletProducerException(exchange, response, 
respCode));
                         } else {

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestletProducerSessionTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestletProducerSessionTest.java
 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestletProducerSessionTest.java
new file mode 100644
index 0000000..abd123d
--- /dev/null
+++ 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestletProducerSessionTest.java
@@ -0,0 +1,107 @@
+/**
+ * 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.restlet;
+
+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 RestletProducerSessionTest extends RestletTestSupport {
+    private String url = "restlet:http://127.0.0.1:"; + portNum + 
"/session?restletMethod=POST";
+
+    @Test
+    public void testProducerNoSession() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("{New New 
World}", "{New New World}");
+        template.sendBodyAndHeader("direct:start", "{World}", 
Exchange.CONTENT_TYPE, "application/json");
+        template.sendBodyAndHeader("direct:start", "{World}", 
Exchange.CONTENT_TYPE, "application/json");
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testProducerInstanceSession() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("{Old New 
World}", "{Old Old World}");
+        template.sendBodyAndHeader("direct:instance", "{World}", 
Exchange.CONTENT_TYPE, "application/json");
+        template.sendBodyAndHeader("direct:instance", "{World}", 
Exchange.CONTENT_TYPE, "application/json");
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testProducerExchangeSession() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("{Old New 
World}", "{Old New World}");
+        template.sendBodyAndHeader("direct:exchange", "{World}", 
Exchange.CONTENT_TYPE, "application/json");
+        template.sendBodyAndHeader("direct:exchange", "{World}", 
Exchange.CONTENT_TYPE, "application/json");
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndiRegistry = super.createRegistry();
+        jndiRegistry.bind("instanceCookieHandler", new 
InstanceCookieHandler());
+        jndiRegistry.bind("exchangeCookieHandler", new 
ExchangeCookieHandler());
+        return jndiRegistry;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .to(url)
+                    .to(url)
+                    .to("mock:result");
+
+                from("direct:instance")
+                    .to(url + "&cookieHandler=#instanceCookieHandler")
+                    .to(url + "&cookieHandler=#instanceCookieHandler")
+                    .to("mock:result");
+
+                from("direct:exchange")
+                    .to(url + "&cookieHandler=#exchangeCookieHandler")
+                    .to(url + "&cookieHandler=#exchangeCookieHandler")
+                    .to("mock:result");
+
+                from("jetty://http://127.0.0.1:"; + portNum + 
"/session?sessionSupport=true")
+                    .process(new Processor() {
+                        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 (body.length() > 2) {
+                                body = body.substring(1, body.length() - 1);
+                            }
+                            if ("bar".equals(session.getAttribute("foo"))) {
+                                body = "{Old " + body + "}";
+                            } else {
+                                session.setAttribute("foo", "bar");
+                                body = "{New " + body + "}";
+                            }
+                            exchange.getOut().setBody(body);
+                            exchange.getOut().setHeader(Exchange.CONTENT_TYPE, 
"application/json");
+                        }
+                    });
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-undertow/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-undertow/pom.xml 
b/components/camel-undertow/pom.xml
index 4f930f3..05d81e3 100644
--- a/components/camel-undertow/pom.xml
+++ b/components/camel-undertow/pom.xml
@@ -40,6 +40,10 @@
       <artifactId>camel-core</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-http-common</artifactId>
+    </dependency>
+    <dependency>
       <groupId>io.undertow</groupId>
       <artifactId>undertow-core</artifactId>
       <version>${undertow-version}</version>

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-undertow/src/main/docs/undertow-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/docs/undertow-component.adoc 
b/components/camel-undertow/src/main/docs/undertow-component.adoc
index 490052f..2422104 100644
--- a/components/camel-undertow/src/main/docs/undertow-component.adoc
+++ b/components/camel-undertow/src/main/docs/undertow-component.adoc
@@ -65,7 +65,7 @@ The Undertow component supports 2 options which are listed 
below.
 
 
 // endpoint options: START
-The Undertow component supports 17 endpoint options which are listed below:
+The Undertow component supports 18 endpoint options which are listed below:
 
 {% raw %}
 [width="100%",cols="2,1,1m,1m,5",options="header"]
@@ -78,6 +78,7 @@ The Undertow component supports 17 endpoint options which are 
listed below:
 | optionsEnabled | consumer | false | boolean | Specifies whether to enable 
HTTP OPTIONS for this Servlet consumer. By default OPTIONS is turned off.
 | 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
 | keepAlive | producer | true | Boolean | Setting to ensure socket is not 
closed due to inactivity
 | options | producer |  | Map | Sets additional channel options. The options 
that can be used are defined in org.xnio.Options. To configure from endpoint 
uri then prefix each option with option. such as 
option.close-abort=true&option.send-buffer=8192
 | reuseAddresses | producer | true | Boolean | Setting to facilitate socket 
multiplexing

http://git-wip-us.apache.org/repos/asf/camel/blob/e607dc3f/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java
index 9a36978..9ad7ed2 100644
--- 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java
@@ -30,6 +30,7 @@ import org.apache.camel.Message;
 import org.apache.camel.PollingConsumer;
 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;
@@ -83,6 +84,8 @@ public class UndertowEndpoint extends DefaultEndpoint 
implements AsyncEndpoint,
     @UriParam(label = "consumer",
             description = "Specifies whether to enable HTTP OPTIONS for this 
Servlet consumer. By default OPTIONS is turned off.")
     private boolean optionsEnabled;
+    @UriParam(label = "producer")
+    private CookieHandler cookieHandler;
 
     public UndertowEndpoint(String uri, UndertowComponent component) throws 
URISyntaxException {
         super(uri, component);
@@ -289,6 +292,17 @@ public class UndertowEndpoint extends DefaultEndpoint 
implements AsyncEndpoint,
         this.optionsEnabled = optionsEnabled;
     }
 
+    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-undertow/src/main/java/org/apache/camel/component/undertow/UndertowProducer.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowProducer.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowProducer.java
index cbdcba6..7cabc4f 100644
--- 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowProducer.java
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowProducer.java
@@ -18,7 +18,12 @@ package org.apache.camel.component.undertow;
 
 import java.io.IOException;
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
 
 import io.undertow.client.ClientCallback;
 import io.undertow.client.ClientConnection;
@@ -26,6 +31,7 @@ import io.undertow.client.ClientExchange;
 import io.undertow.client.ClientRequest;
 import io.undertow.client.UndertowClient;
 import io.undertow.server.DefaultByteBufferPool;
+import io.undertow.util.HeaderMap;
 import io.undertow.util.Headers;
 import io.undertow.util.HttpString;
 import io.undertow.util.Protocols;
@@ -100,6 +106,13 @@ public class UndertowProducer extends DefaultAsyncProducer 
{
                 request.getRequestHeaders().put(Headers.CONTENT_LENGTH, 
bodyAsByte.array().length);
             }
 
+            if (getEndpoint().getCookieHandler() != null) {
+                Map<String, List<String>> cookieHeaders = 
getEndpoint().getCookieHandler().loadCookies(exchange, uri);
+                for (Map.Entry<String, List<String>> entry : 
cookieHeaders.entrySet()) {
+                    request.getRequestHeaders().putAll(new 
HttpString(entry.getKey()), entry.getValue());
+                }
+            }
+
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Executing http {} method: {}", method, url);
             }
@@ -166,6 +179,7 @@ public class UndertowProducer extends DefaultAsyncProducer {
                 public void completed(ClientExchange clientExchange) {
                     LOG.trace("completed: {}", clientExchange);
                     try {
+                        storeCookies(clientExchange);
                         Message message = 
endpoint.getUndertowHttpBinding().toCamelMessage(clientExchange, camelExchange);
                         if (ExchangeHelper.isOutCapable(camelExchange)) {
                             camelExchange.setOut(message);
@@ -217,6 +231,24 @@ public class UndertowProducer extends DefaultAsyncProducer 
{
             // make sure to call callback
             callback.done(false);
         }
+
+        private void storeCookies(ClientExchange clientExchange) throws 
URISyntaxException, IOException {
+            if (endpoint.getCookieHandler() != null) {
+                // creating the url to use takes 2-steps
+                String url = UndertowHelper.createURL(camelExchange, 
getEndpoint());
+                URI uri = UndertowHelper.createURI(camelExchange, url, 
getEndpoint());
+                HeaderMap headerMap = 
clientExchange.getResponse().getResponseHeaders();
+                Map<String, List<String>> m = new HashMap<String, 
List<String>>();
+                for (HttpString headerName : headerMap.getHeaderNames()) {
+                    List<String> headerValue = new LinkedList<String>();
+                    for (int i = 0; i < headerMap.count(headerName); i++) {
+                        headerValue.add(headerMap.get(headerName, i));
+                    }
+                    m.put(headerName.toString(), headerValue);
+                }
+                endpoint.getCookieHandler().storeCookies(camelExchange, uri, 
m);
+            }
+        }
     }
 
 }

Reply via email to