camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ningji...@apache.org
Subject [8/9] git commit: CAMEL-7782 Added camel-netty4-http component
Date Fri, 05 Sep 2014 13:13:26 GMT
CAMEL-7782 Added camel-netty4-http component


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

Branch: refs/heads/master
Commit: db88eeda8e7c40b00b9f9ff015ed0b54e6922ea9
Parents: 8c5529f
Author: Willem Jiang <willem.jiang@gmail.com>
Authored: Fri Sep 5 20:55:54 2014 +0800
Committer: Willem Jiang <willem.jiang@gmail.com>
Committed: Fri Sep 5 20:55:54 2014 +0800

----------------------------------------------------------------------
 .../apache/camel/impl/DefaultCamelContext.java  |   2 +
 components/camel-netty4-http/pom.xml            |  86 +++
 .../netty4/http/ContextPathMatcher.java         |  55 ++
 .../netty4/http/DefaultContextPathMatcher.java  |  88 +++
 .../netty4/http/DefaultNettyHttpBinding.java    | 550 +++++++++++++++++++
 .../http/DefaultNettySharedHttpServer.java      | 132 +++++
 .../netty4/http/HttpClientPipelineFactory.java  | 165 ++++++
 .../component/netty4/http/HttpPrincipal.java    |  52 ++
 .../netty4/http/HttpServerBootstrapFactory.java | 104 ++++
 .../http/HttpServerConsumerChannelFactory.java  |  63 +++
 .../netty4/http/HttpServerPipelineFactory.java  | 172 ++++++
 .../http/HttpServerSharedPipelineFactory.java   | 159 ++++++
 .../netty4/http/JAASSecurityAuthenticator.java  |  72 +++
 .../http/NettyChannelBufferStreamCache.java     |  99 ++++
 .../component/netty4/http/NettyHttpBinding.java | 119 ++++
 .../netty4/http/NettyHttpComponent.java         | 303 ++++++++++
 .../netty4/http/NettyHttpConfiguration.java     | 166 ++++++
 .../netty4/http/NettyHttpConstants.java         |  31 ++
 .../netty4/http/NettyHttpConsumer.java          |  75 +++
 .../netty4/http/NettyHttpConverter.java         | 118 ++++
 .../netty4/http/NettyHttpEndpoint.java          | 198 +++++++
 .../http/NettyHttpHeaderFilterStrategy.java     |  53 ++
 .../component/netty4/http/NettyHttpHelper.java  | 243 ++++++++
 .../component/netty4/http/NettyHttpMessage.java |  51 ++
 .../http/NettyHttpOperationFailedException.java |  77 +++
 .../netty4/http/NettyHttpProducer.java          | 120 ++++
 .../http/NettyHttpSecurityConfiguration.java    | 115 ++++
 .../netty4/http/NettySharedHttpServer.java      |  74 +++
 ...ySharedHttpServerBootstrapConfiguration.java |  50 ++
 .../netty4/http/RestContextPathMatcher.java     | 102 ++++
 .../netty4/http/RestNettyHttpBinding.java       |  92 ++++
 .../netty4/http/SecurityAuthenticator.java      |  76 +++
 .../http/SecurityAuthenticatorSupport.java      | 127 +++++
 .../netty4/http/SecurityConstraint.java         |  31 ++
 .../netty4/http/SecurityConstraintMapping.java  | 133 +++++
 .../http/handlers/HttpClientChannelHandler.java |  46 ++
 .../http/handlers/HttpServerChannelHandler.java | 316 +++++++++++
 .../HttpServerMultiplexChannelHandler.java      | 235 ++++++++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 +++++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../services/org/apache/camel/TypeConverter     |  18 +
 .../org/apache/camel/component/netty4-http      |  17 +
 .../component/netty4/http/BaseNettyTest.java    |  95 ++++
 .../netty4/http/ManagedNettyEndpointTest.java   |  81 +++
 .../component/netty4/http/MyLoginModule.java    | 102 ++++
 .../component/netty4/http/MyRolePrincipal.java  |  33 ++
 .../netty4/http/NettyHttp500ErrorTest.java      |  66 +++
 ...yHttp500ErrorThrowExceptionOnServerTest.java |  67 +++
 ...ttpAccessHttpRequestAndResponseBeanTest.java |  74 +++
 .../NettyHttpAccessHttpRequestBeanTest.java     |  54 ++
 .../http/NettyHttpAccessHttpRequestTest.java    |  59 ++
 .../NettyHttpBasicAuthConstraintMapperTest.java |  96 ++++
 ...asicAuthCustomSecurityAuthenticatorTest.java | 105 ++++
 .../netty4/http/NettyHttpBasicAuthTest.java     | 104 ++++
 ...ndingPreservePostFormUrlEncodedBodyTest.java |  68 +++
 .../http/NettyHttpBridgeEncodedPathTest.java    |  66 +++
 ...NettyHttpBridgeRouteUsingHttpClientTest.java |  92 ++++
 .../http/NettyHttpCharacterEncodingTest.java    |  63 +++
 .../netty4/http/NettyHttpClientChunkedTest.java |  46 ++
 .../http/NettyHttpClientExpectContinueTest.java |  58 ++
 ...ponentConfigurationAndDocumentationTest.java |  57 ++
 .../netty4/http/NettyHttpContentTypeTest.java   |  87 +++
 ...ettyHttpConvertPayloadToInputStreamTest.java |  62 +++
 ...dpointUriCustomHeaderFilterStrategyTest.java |  70 +++
 .../NettyHttpEndpointUriEncodingIssueTest.java  |  57 ++
 ...ntUriEncodingIssueUrlDecodeDisabledTest.java |  49 ++
 .../http/NettyHttpFilterCamelHeadersTest.java   |  76 +++
 .../NettyHttpGetWithInvalidMessageTest.java     | 106 ++++
 ...ttyHttpGetWithParamAsExchangeHeaderTest.java | 127 +++++
 .../netty4/http/NettyHttpGetWithParamTest.java  |  78 +++
 .../netty4/http/NettyHttpHandle404Test.java     |  92 ++++
 .../netty4/http/NettyHttpHeaderCaseTest.java    |  73 +++
 ...ettyHttpHeaderFilterStrategyRemovalTest.java |  78 +++
 .../http/NettyHttpHeaderFilterStrategyTest.java | 106 ++++
 .../netty4/http/NettyHttpHeadersTest.java       |  54 ++
 .../http/NettyHttpMapHeadersFalseTest.java      |  70 +++
 .../http/NettyHttpMethodRestrictTest.java       |  74 +++
 .../http/NettyHttpOnExceptionHandledTest.java   |  56 ++
 ...tpProducerBridgePathWithSpacesAtEndTest.java |  54 ++
 .../http/NettyHttpProducerBridgeTest.java       |  50 ++
 .../http/NettyHttpProducerConcurrentTest.java   |  87 +++
 .../http/NettyHttpProducerKeepAliveTest.java    |  64 +++
 .../http/NettyHttpProducerQueryParamTest.java   |  75 +++
 .../NettyHttpProducerSendEmptyHeaderTest.java   |  48 ++
 .../http/NettyHttpProducerSimpleGetTest.java    |  69 +++
 .../http/NettyHttpProducerSimpleTest.java       |  76 +++
 ...ttpProducerTwoParametersWithSameKeyTest.java | 100 ++++
 .../http/NettyHttpProducerWithHeaderTest.java   |  60 ++
 .../netty4/http/NettyHttpRawQueryTest.java      |  57 ++
 .../http/NettyHttpRedirectNoLocationTest.java   |  59 ++
 .../netty4/http/NettyHttpRedirectTest.java      |  56 ++
 .../http/NettyHttpRequestTimeoutTest.java       |  62 +++
 ...ReturnDataNotInputStreamConvertableTest.java |  53 ++
 .../netty4/http/NettyHttpReturnFaultTest.java   |  58 ++
 .../component/netty4/http/NettyHttpSSLTest.java | 109 ++++
 ...ettyHttpSameHostDifferentParametersTest.java |  52 ++
 ...HttpSimpleBasicAuthConstraintMapperTest.java |  90 +++
 .../http/NettyHttpSimpleBasicAuthTest.java      |  70 +++
 .../netty4/http/NettyHttpSimpleTest.java        |  46 ++
 .../http/NettyHttpSimpleUriParametersTest.java  |  46 ++
 .../NettyHttpStreamCacheFileResponseTest.java   |  75 +++
 .../http/NettyHttpSuspendResume503Test.java     |  74 +++
 .../netty4/http/NettyHttpSuspendResumeTest.java |  73 +++
 .../netty4/http/NettyHttpTraceDisabledTest.java |  62 +++
 .../http/NettyHttpTransferExceptionTest.java    |  52 ++
 ...HttpTwoRoutesBootstrapConfigurationTest.java |  93 ++++
 .../NettyHttpTwoRoutesMatchOnUriPrefixTest.java |  77 +++
 .../NettyHttpTwoRoutesStopOneRouteTest.java     |  77 +++
 .../netty4/http/NettyHttpTwoRoutesTest.java     |  54 ++
 ...outesValidateBootstrapConfigurationTest.java |  52 ++
 .../http/NettyHttpXMLXPathResponseTest.java     |  53 ++
 .../netty4/http/NettyHttpXMLXPathTest.java      |  53 ++
 .../http/NettyRecipientListHttpBaseTest.java    |  53 ++
 .../netty4/http/NettyRouteSimpleTest.java       |  51 ++
 .../netty4/http/NettySharedHttpServerTest.java  |  90 +++
 .../http/NettyUseRawHttpResponseTest.java       |  63 +++
 .../http/SecurityConstraintMappingTest.java     | 108 ++++
 .../http/SpringNettyHttpBasicAuthTest.java      | 118 ++++
 .../netty4/http/SpringNettyHttpSSLTest.java     |  79 +++
 .../component/netty4/http/rest/CountryPojo.java |  40 ++
 ...estNettyHttpBindingModeAutoWithJsonTest.java |  59 ++
 ...RestNettyHttpBindingModeAutoWithXmlTest.java |  59 ++
 .../rest/RestNettyHttpBindingModeJsonTest.java  |  76 +++
 .../rest/RestNettyHttpBindingModeXmlTest.java   |  77 +++
 .../RestNettyHttpContextPathMatchGetTest.java   |  68 +++
 .../netty4/http/rest/RestNettyHttpGetTest.java  |  56 ++
 .../http/rest/RestNettyHttpPojoInOutTest.java   |  53 ++
 .../rest/RestNettyHttpPostJsonJaxbPojoTest.java |  61 ++
 .../rest/RestNettyHttpPostJsonPojoListTest.java |  68 +++
 .../rest/RestNettyHttpPostJsonPojoTest.java     |  61 ++
 .../rest/RestNettyHttpPostXmlJaxbPojoTest.java  |  79 +++
 .../netty4/http/rest/RestPathMatchingTest.java  |  86 +++
 .../netty4/http/rest/UserJaxbPojo.java          |  48 ++
 .../component/netty4/http/rest/UserPojo.java    |  40 ++
 .../component/netty4/http/rest/UserService.java |  33 ++
 .../src/test/resources/jsse/localhost.ks        | Bin 0 -> 1265 bytes
 .../src/test/resources/log4j.properties         |  39 ++
 .../src/test/resources/myjaas.config            |   5 +
 .../http/SpringNettyHttpBasicAuthTest.xml       |  70 +++
 .../netty4/http/SpringNettyHttpSSLTest.xml      |  62 +++
 components/pom.xml                              |   1 +
 parent/pom.xml                                  |   5 +
 142 files changed, 11644 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index f825a25..7dd681d 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -1101,6 +1101,8 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
             return "atmosphere/websocket";
         } else if ("netty-http".equals(componentName)) {
             return "netty/http";
+        } else if ("netty4-http".equals(componentName)) {
+            return "netty4/http";
         }
         return componentName.replaceAll("-", "");
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/pom.xml b/components/camel-netty4-http/pom.xml
new file mode 100644
index 0000000..47e8269
--- /dev/null
+++ b/components/camel-netty4-http/pom.xml
@@ -0,0 +1,86 @@
+<?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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.camel</groupId>
+		<artifactId>components</artifactId>
+		<version>2.14-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>camel-netty4-http</artifactId>
+	<packaging>bundle</packaging>
+	<name>Camel :: Netty4 HTTP</name>
+	<description>Camel Netty4 HTTP support</description>
+
+	<properties>
+		<camel.osgi.export.pkg>
+			org.apache.camel.component.netty4.http.*
+		</camel.osgi.export.pkg>
+		<camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=netty4-http</camel.osgi.export.service>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.camel</groupId>
+            <artifactId>camel-netty4</artifactId>
+		</dependency>
+		<dependency>
+             <groupId>io.netty</groupId>
+             <artifactId>netty-codec-http</artifactId>
+             <version>${netty-version}</version>
+        </dependency>
+
+		<!-- testing -->
+		<dependency>
+			<groupId>org.apache.camel</groupId>
+			<artifactId>camel-test-spring</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.camel</groupId>
+			<artifactId>camel-http</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+    <!-- for testing rest-dsl -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jackson</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jaxb</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+		<!-- logging -->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+	</dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/ContextPathMatcher.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/ContextPathMatcher.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/ContextPathMatcher.java
new file mode 100644
index 0000000..1b58af8
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/ContextPathMatcher.java
@@ -0,0 +1,55 @@
+/**
+ * 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;
+
+/**
+ * A matcher used for selecting the correct {@link org.apache.camel.component.netty.http.handlers.HttpServerChannelHandler}
+ * to handle an incoming {@link io.netty.handler.codec.http.HttpRequest} when you use multiple routes on the same
+ * port.
+ * <p/>
+ * As when we do that, we need to multiplex and select the correct consumer route to process the HTTP request.
+ * To do that we need to match on the incoming HTTP request context-path from the request.
+ */
+public interface ContextPathMatcher {
+
+    /**
+     * Whether the target context-path matches a regular url.
+     *
+     * @param path  the context-path from the incoming HTTP request
+     * @return <tt>true</tt> to match, <tt>false</tt> if not.
+     */
+    boolean matches(String path);
+
+    /**
+     * Whether the target context-path matches a REST url.
+     *
+     * @param path  the context-path from the incoming HTTP request
+     * @param wildcard whether to match strict or by wildcards
+     * @return <tt>true</tt> to match, <tt>false</tt> if not.
+     */
+    boolean matchesRest(String path, boolean wildcard);
+
+    /**
+     * Matches the given request HTTP method with the configured HTTP method of the consumer
+     *
+     * @param method    the request HTTP method
+     * @param restrict  the consumer configured HTTP restrict method
+     * @return <tt>true</tt> if matched, <tt>false</tt> otherwise
+     */
+    boolean matchMethod(String method, String restrict);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultContextPathMatcher.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultContextPathMatcher.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultContextPathMatcher.java
new file mode 100644
index 0000000..f30cc66
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultContextPathMatcher.java
@@ -0,0 +1,88 @@
+/**
+ * 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 java.util.Locale;
+
+/**
+ * A default {@link ContextPathMatcher} which supports the <tt>matchOnUriPrefix</tt> option.
+ */
+public class DefaultContextPathMatcher implements ContextPathMatcher {
+
+    private final String path;
+    private final boolean matchOnUriPrefix;
+
+    public DefaultContextPathMatcher(String path, boolean matchOnUriPrefix) {
+        this.path = path.toLowerCase(Locale.US);
+        this.matchOnUriPrefix = matchOnUriPrefix;
+    }
+
+    @Override
+    public boolean matches(String path) {
+        path = path.toLowerCase(Locale.US);
+        if (!matchOnUriPrefix) {
+            // exact match
+            return path.equals(this.path);
+        } else {
+            // match on prefix, then we just need to match the start of the context-path
+            return path.startsWith(this.path);
+        }
+    }
+
+    @Override
+    public boolean matchesRest(String path, boolean wildcard) {
+        return false;
+    }
+
+    @Override
+    public boolean matchMethod(String method, String restrict) {
+        // always match as HttpServerChannelHandler will deal with HTTP method restrictions
+        return true;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        DefaultContextPathMatcher that = (DefaultContextPathMatcher) o;
+
+        if (matchOnUriPrefix != that.matchOnUriPrefix) {
+            return false;
+        }
+        if (!path.equals(that.path)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = path.hashCode();
+        result = 31 * result + (matchOnUriPrefix ? 1 : 0);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
new file mode 100644
index 0000000..42e4bec
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
@@ -0,0 +1,550 @@
+/**
+ * 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 java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.handler.codec.http.DefaultFullHttpRequest;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.DefaultHttpRequest;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpVersion;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.component.netty4.NettyConverter;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.util.ExchangeHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.MessageHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Default {@link NettyHttpBinding}.
+ */
+public class DefaultNettyHttpBinding implements NettyHttpBinding, Cloneable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultNettyHttpBinding.class);
+    private HeaderFilterStrategy headerFilterStrategy = new NettyHttpHeaderFilterStrategy();
+
+    public DefaultNettyHttpBinding() {
+    }
+
+    public DefaultNettyHttpBinding(HeaderFilterStrategy headerFilterStrategy) {
+        this.headerFilterStrategy = headerFilterStrategy;
+    }
+    
+    public DefaultNettyHttpBinding copy() {
+        try {
+            return (DefaultNettyHttpBinding)this.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+
+    @Override
+    public Message toCamelMessage(FullHttpRequest request, Exchange exchange, NettyHttpConfiguration configuration) throws Exception {
+        LOG.trace("toCamelMessage: {}", request);
+
+        NettyHttpMessage answer = new NettyHttpMessage(request, null);
+        answer.setExchange(exchange);
+        if (configuration.isMapHeaders()) {
+            populateCamelHeaders(request, answer.getHeaders(), exchange, configuration);
+        }
+
+        if (configuration.isDisableStreamCache()) {
+            // keep the body as is, and use type converters
+            answer.setBody(request.content());
+        } else {
+            // turn the body into stream cached
+            NettyChannelBufferStreamCache cache = new NettyChannelBufferStreamCache(request.content());
+            answer.setBody(cache);
+        }
+        return answer;
+    }
+
+    @Override
+    public void populateCamelHeaders(FullHttpRequest request, Map<String, Object> headers, Exchange exchange, NettyHttpConfiguration configuration) throws Exception {
+        LOG.trace("populateCamelHeaders: {}", request);
+
+        // NOTE: these headers is applied using the same logic as camel-http/camel-jetty to be consistent
+
+        headers.put(Exchange.HTTP_METHOD, request.getMethod().name());
+        // strip query parameters from the uri
+        String s = request.getUri();
+        if (s.contains("?")) {
+            s = ObjectHelper.before(s, "?");
+        }
+
+        // we want the full path for the url, as the client may provide the url in the HTTP headers as absolute or relative, eg
+        //   /foo
+        //   http://servername/foo
+        String http = configuration.isSsl() ? "https://" : "http://";
+        if (!s.startsWith(http)) {
+            if (configuration.getPort() != 80) {
+                s = http + configuration.getHost() + ":" + configuration.getPort() + s;
+            } else {
+                s = http + configuration.getHost() + s;
+            }
+        }
+
+        headers.put(Exchange.HTTP_URL, s);
+        // uri is without the host and port
+        URI uri = new URI(request.getUri());
+        // uri is path and query parameters
+        headers.put(Exchange.HTTP_URI, uri.getPath());
+        headers.put(Exchange.HTTP_QUERY, uri.getQuery());
+        headers.put(Exchange.HTTP_RAW_QUERY, uri.getRawQuery());
+
+        // strip the starting endpoint path so the path is relative to the endpoint uri
+        String path = uri.getPath();
+        if (configuration.getPath() != null && path.startsWith(configuration.getPath())) {
+            path = path.substring(configuration.getPath().length());
+        }
+        headers.put(Exchange.HTTP_PATH, path);
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("HTTP-Method {}", request.getMethod().name());
+            LOG.trace("HTTP-Uri {}", request.getUri());
+        }
+
+        for (String name : request.headers().names()) {
+            // mapping the content-type
+            if (name.toLowerCase(Locale.US).equals("content-type")) {
+                name = Exchange.CONTENT_TYPE;
+            }
+
+            if (name.toLowerCase(Locale.US).equals("authorization")) {
+                String value = request.headers().get(name);
+                // store a special header that this request was authenticated using HTTP Basic
+                if (value != null && value.trim().startsWith("Basic")) {
+                    if (headerFilterStrategy != null
+                            && !headerFilterStrategy.applyFilterToExternalHeaders(NettyHttpConstants.HTTP_AUTHENTICATION, "Basic", exchange)) {
+                        NettyHttpHelper.appendHeader(headers, NettyHttpConstants.HTTP_AUTHENTICATION, "Basic");
+                    }
+                }
+            }
+
+            // add the headers one by one, and use the header filter strategy
+            List<String> values = request.headers().getAll(name);
+            Iterator<?> it = ObjectHelper.createIterator(values);
+            while (it.hasNext()) {
+                Object extracted = it.next();
+                Object decoded = shouldUrlDecodeHeader(configuration, name, extracted, "UTF-8");
+                LOG.trace("HTTP-header: {}", extracted);
+                if (headerFilterStrategy != null
+                        && !headerFilterStrategy.applyFilterToExternalHeaders(name, decoded, exchange)) {
+                    NettyHttpHelper.appendHeader(headers, name, decoded);
+                }
+            }
+        }
+
+        // add uri parameters as headers to the Camel message
+        if (request.getUri().contains("?")) {
+            String query = ObjectHelper.after(request.getUri(), "?");
+            Map<String, Object> uriParameters = URISupport.parseQuery(query);
+
+            for (Map.Entry<String, Object> entry : uriParameters.entrySet()) {
+                String name = entry.getKey();
+                Object values = entry.getValue();
+                Iterator<?> it = ObjectHelper.createIterator(values);
+                while (it.hasNext()) {
+                    Object extracted = it.next();
+                    Object decoded = shouldUrlDecodeHeader(configuration, name, extracted, "UTF-8");
+                    LOG.trace("URI-Parameter: {}", extracted);
+                    if (headerFilterStrategy != null
+                            && !headerFilterStrategy.applyFilterToExternalHeaders(name, decoded, exchange)) {
+                        NettyHttpHelper.appendHeader(headers, name, decoded);
+                    }
+                }
+            }
+        }
+
+        // if body is application/x-www-form-urlencoded then extract the body as query string and append as headers
+        // if it is a bridgeEndpoint we need to skip this part of work
+        if (request.getMethod().name().equals("POST") && request.headers().get(Exchange.CONTENT_TYPE) != null
+                && request.headers().get(Exchange.CONTENT_TYPE).startsWith(NettyHttpConstants.CONTENT_TYPE_WWW_FORM_URLENCODED)
+                && !configuration.isBridgeEndpoint()) {
+
+            String charset = "UTF-8";
+
+            // Push POST form params into the headers to retain compatibility with DefaultHttpBinding
+            String body = request.content().toString(Charset.forName(charset));
+            if (ObjectHelper.isNotEmpty(body)) {
+                for (String param : body.split("&")) {
+                    String[] pair = param.split("=", 2);
+                    if (pair.length == 2) {
+                        String name = shouldUrlDecodeHeader(configuration, "", pair[0], charset);
+                        String value = shouldUrlDecodeHeader(configuration, name, pair[1], charset);
+                        if (headerFilterStrategy != null
+                                && !headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) {
+                            NettyHttpHelper.appendHeader(headers, name, value);
+                        }
+                    } else {
+                        throw new IllegalArgumentException("Invalid parameter, expected to be a pair but was " + param);
+                    }
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Decodes the header if needed to, or returns the header value as is.
+     *
+     * @param configuration  the configuration
+     * @param headerName     the header name
+     * @param value          the current header value
+     * @param charset        the charset to use for decoding
+     * @return  the decoded value (if decoded was needed) or a <tt>toString</tt> representation of the value.
+     * @throws UnsupportedEncodingException is thrown if error decoding.
+     */
+    protected String shouldUrlDecodeHeader(NettyHttpConfiguration configuration, String headerName, Object value, String charset) throws UnsupportedEncodingException {
+        // do not decode Content-Type
+        if (Exchange.CONTENT_TYPE.equals(headerName)) {
+            return value.toString();
+        } else if (configuration.isUrlDecodeHeaders()) {
+            return URLDecoder.decode(value.toString(), charset);
+        } else {
+            return value.toString();
+        }
+    }
+
+    @Override
+    public Message toCamelMessage(FullHttpResponse response, Exchange exchange, NettyHttpConfiguration configuration) throws Exception {
+        LOG.trace("toCamelMessage: {}", response);
+
+        NettyHttpMessage answer = new NettyHttpMessage(null, response);
+        answer.setExchange(exchange);
+        if (configuration.isMapHeaders()) {
+            populateCamelHeaders(response, answer.getHeaders(), exchange, configuration);
+        }
+
+        // keep the body as is, and use type converters
+        answer.setBody(response.content());
+        return answer;
+    }
+
+    @Override
+    public void populateCamelHeaders(FullHttpResponse response, Map<String, Object> headers, Exchange exchange, NettyHttpConfiguration configuration) throws Exception {
+        LOG.trace("populateCamelHeaders: {}", response);
+
+        headers.put(Exchange.HTTP_RESPONSE_CODE, response.getStatus().code());
+        headers.put(NettyHttpConstants.HTTP_RESPONSE_TEXT, response.getStatus().reasonPhrase());
+
+        for (String name : response.headers().names()) {
+            // mapping the content-type
+            if (name.toLowerCase().equals("content-type")) {
+                name = Exchange.CONTENT_TYPE;
+            }
+            // add the headers one by one, and use the header filter strategy
+            List<String> values = response.headers().getAll(name);
+            Iterator<?> it = ObjectHelper.createIterator(values);
+            while (it.hasNext()) {
+                Object extracted = it.next();
+                LOG.trace("HTTP-header: {}", extracted);
+                if (headerFilterStrategy != null
+                        && !headerFilterStrategy.applyFilterToExternalHeaders(name, extracted, exchange)) {
+                    NettyHttpHelper.appendHeader(headers, name, extracted);
+                }
+            }
+        }
+    }
+
+    @Override
+    public HttpResponse toNettyResponse(Message message, NettyHttpConfiguration configuration) throws Exception {
+        LOG.trace("toNettyResponse: {}", message);
+
+        // the message body may already be a Netty HTTP response
+        if (message.getBody() instanceof HttpResponse) {
+            return (HttpResponse) message.getBody();
+        }
+
+        Object body = message.getBody();
+        Exception cause = message.getExchange().getException();
+        // support bodies as native Netty
+        ByteBuf buffer;
+        // the response code is 200 for OK and 500 for failed
+        boolean failed = message.getExchange().isFailed();
+        int defaultCode = failed ? 500 : 200;
+
+        int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, defaultCode, int.class);
+        
+        LOG.trace("HTTP Status Code: {}", code);
+
+
+        // if there was an exception then use that as body
+        if (cause != null) {
+            if (configuration.isTransferException()) {
+                // we failed due an exception, and transfer it as java serialized object
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                ObjectOutputStream oos = new ObjectOutputStream(bos);
+                oos.writeObject(cause);
+                oos.flush();
+                IOHelper.close(oos, bos);
+
+                // the body should be the serialized java object of the exception
+                body = NettyConverter.toByteBuffer(bos.toByteArray());
+                // force content type to be serialized java object
+                message.setHeader(Exchange.CONTENT_TYPE, NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT);
+            } else {
+                // we failed due an exception so print it as plain text
+                StringWriter sw = new StringWriter();
+                PrintWriter pw = new PrintWriter(sw);
+                cause.printStackTrace(pw);
+
+                // the body should then be the stacktrace
+                body = NettyConverter.toByteBuffer(sw.toString().getBytes());
+                // force content type to be text/plain as that is what the stacktrace is
+                message.setHeader(Exchange.CONTENT_TYPE, "text/plain");
+            }
+
+            // and mark the exception as failure handled, as we handled it by returning it as the response
+            ExchangeHelper.setFailureHandled(message.getExchange());
+        }
+
+        if (body instanceof ByteBuf) {
+            buffer = (ByteBuf) body;
+        } else {
+            // try to convert to buffer first
+            buffer = message.getBody(ByteBuf.class);
+            if (buffer == null) {
+                // fallback to byte array as last resort
+                byte[] data = message.getBody(byte[].class);
+                if (data != null) {
+                    buffer = NettyConverter.toByteBuffer(data);
+                } else {
+                    // and if byte array fails then try String
+                    String str;
+                    if (body != null) {
+                        str = message.getMandatoryBody(String.class);
+                    } else {
+                        str = "";
+                    }
+                    buffer = NettyConverter.toByteBuffer(str.getBytes());
+                }
+            }
+        }
+        
+        HttpResponse response = null;
+        
+        if (buffer != null) {
+            response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(code), buffer);
+            // We just need to reset the readerIndex this time
+            if (buffer.readerIndex() == buffer.writerIndex()) {
+                buffer.setIndex(0, buffer.writerIndex());
+            }
+            // TODO How to enable the chunk transport 
+            int len = buffer.readableBytes();
+            // set content-length
+            response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, len);
+            LOG.trace("Content-Length: {}", len);
+        } else {
+            response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(code));
+        }
+        
+        TypeConverter tc = message.getExchange().getContext().getTypeConverter();
+
+        // append headers
+        // must use entrySet to ensure case of keys is preserved
+        for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            // use an iterator as there can be multiple values. (must not use a delimiter)
+            final Iterator<?> it = ObjectHelper.createIterator(value, null);
+            while (it.hasNext()) {
+                String headerValue = tc.convertTo(String.class, it.next());
+                if (headerValue != null && headerFilterStrategy != null
+                        && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, message.getExchange())) {
+                    LOG.trace("HTTP-Header: {}={}", key, headerValue);
+                    response.headers().add(key, headerValue);
+                }
+            }
+        }
+
+        // set the content type in the response.
+        String contentType = MessageHelper.getContentType(message);
+        if (contentType != null) {
+            // set content-type
+            response.headers().set(HttpHeaders.Names.CONTENT_TYPE, contentType);
+            LOG.trace("Content-Type: {}", contentType);
+        }
+
+        // configure connection to accordingly to keep alive configuration
+        // favor using the header from the message
+        String connection = message.getHeader(HttpHeaders.Names.CONNECTION, String.class);
+        if (connection == null) {
+            // fallback and use the keep alive from the configuration
+            if (configuration.isKeepAlive()) {
+                connection = HttpHeaders.Values.KEEP_ALIVE;
+            } else {
+                connection = HttpHeaders.Values.CLOSE;
+            }
+        }
+        response.headers().set(HttpHeaders.Names.CONNECTION, connection);
+        LOG.trace("Connection: {}", connection);
+
+        return response;
+    }
+
+    @Override
+    public HttpRequest toNettyRequest(Message message, String uri, NettyHttpConfiguration configuration) throws Exception {
+        LOG.trace("toNettyRequest: {}", message);
+
+        // the message body may already be a Netty HTTP response
+        if (message.getBody() instanceof HttpRequest) {
+            return (HttpRequest) message.getBody();
+        }
+
+        // just assume GET for now, we will later change that to the actual method to use
+        HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);
+        
+        Object body = message.getBody();
+        if (body != null) {
+            // support bodies as native Netty
+            ByteBuf buffer;
+            if (body instanceof ByteBuf) {
+                buffer = (ByteBuf) body;
+            } else {
+                // try to convert to buffer first
+                buffer = message.getBody(ByteBuf.class);
+                if (buffer == null) {
+                    // fallback to byte array as last resort
+                    byte[] data = message.getMandatoryBody(byte[].class);
+                    buffer = NettyConverter.toByteBuffer(data);
+                }
+            }
+            if (buffer != null) {
+                request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uri, buffer);
+                int len = buffer.readableBytes();
+                // set content-length
+                request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, len);
+                LOG.trace("Content-Length: {}", len);
+            } else {
+                // we do not support this kind of body
+                throw new NoTypeConversionAvailableException(body, ByteBuf.class);
+            }
+        }
+
+        // update HTTP method accordingly as we know if we have a body or not
+        HttpMethod method = NettyHttpHelper.createMethod(message, body != null);
+        request.setMethod(method);
+        
+        TypeConverter tc = message.getExchange().getContext().getTypeConverter();
+
+        // if we bridge endpoint then we need to skip matching headers with the HTTP_QUERY to avoid sending
+        // duplicated headers to the receiver, so use this skipRequestHeaders as the list of headers to skip
+        Map<String, Object> skipRequestHeaders = null;
+        if (configuration.isBridgeEndpoint()) {
+            String queryString = message.getHeader(Exchange.HTTP_QUERY, String.class);
+            if (queryString != null) {
+                skipRequestHeaders = URISupport.parseQuery(queryString);
+            }
+            // Need to remove the Host key as it should be not used
+            message.getHeaders().remove("host");
+        }
+
+        // append headers
+        // must use entrySet to ensure case of keys is preserved
+        for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+
+            // we should not add headers for the parameters in the uri if we bridge the endpoint
+            // as then we would duplicate headers on both the endpoint uri, and in HTTP headers as well
+            if (skipRequestHeaders != null && skipRequestHeaders.containsKey(key)) {
+                continue;
+            }
+
+            // use an iterator as there can be multiple values. (must not use a delimiter)
+            final Iterator<?> it = ObjectHelper.createIterator(value, null, true);
+            while (it.hasNext()) {
+                String headerValue = tc.convertTo(String.class, it.next());
+
+                if (headerValue != null && headerFilterStrategy != null
+                        && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, message.getExchange())) {
+                    LOG.trace("HTTP-Header: {}={}", key, headerValue);
+                    request.headers().add(key, headerValue);
+                }
+            }
+        }
+
+        // set the content type in the response.
+        String contentType = MessageHelper.getContentType(message);
+        if (contentType != null) {
+            // set content-type
+            request.headers().set(HttpHeaders.Names.CONTENT_TYPE, contentType);
+            LOG.trace("Content-Type: {}", contentType);
+        }
+
+        // must include HOST header as required by HTTP 1.1
+        // use URI as its faster than URL (no DNS lookup)
+        URI u = new URI(uri);
+        String host = u.getHost();
+        request.headers().set(HttpHeaders.Names.HOST, host);
+        LOG.trace("Host: {}", host);
+
+        // configure connection to accordingly to keep alive configuration
+        // favor using the header from the message
+        String connection = message.getHeader(HttpHeaders.Names.CONNECTION, String.class);
+        if (connection == null) {
+            // fallback and use the keep alive from the configuration
+            if (configuration.isKeepAlive()) {
+                connection = HttpHeaders.Values.KEEP_ALIVE;
+            } else {
+                connection = HttpHeaders.Values.CLOSE;
+            }
+        }
+        request.headers().set(HttpHeaders.Names.CONNECTION, connection);
+        LOG.trace("Connection: {}", connection);
+
+        return request;
+    }
+
+    @Override
+    public HeaderFilterStrategy getHeaderFilterStrategy() {
+        return headerFilterStrategy;
+    }
+
+    @Override
+    public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) {
+        this.headerFilterStrategy = headerFilterStrategy;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettySharedHttpServer.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettySharedHttpServer.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettySharedHttpServer.java
new file mode 100644
index 0000000..3ad1fb1
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettySharedHttpServer.java
@@ -0,0 +1,132 @@
+/**
+ * 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 java.util.concurrent.ThreadFactory;
+import java.util.regex.Matcher;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import org.apache.camel.component.netty4.NettyServerBootstrapFactory;
+import org.apache.camel.component.netty4.http.handlers.HttpServerMultiplexChannelHandler;
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.support.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
+import org.apache.camel.util.concurrent.CamelThreadFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A default {@link NettySharedHttpServer} to make sharing Netty server in Camel applications easier.
+ */
+public class DefaultNettySharedHttpServer extends ServiceSupport implements NettySharedHttpServer {
+
+    // TODO: option to enlist in JMX
+
+    public static final String DEFAULT_PATTERN = "Camel Thread ##counter# - #name#:#port#";
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultNettySharedHttpServer.class);
+
+    private NettySharedHttpServerBootstrapConfiguration configuration;
+    private HttpServerConsumerChannelFactory channelFactory;
+    private HttpServerBootstrapFactory bootstrapFactory;
+    private ClassResolver classResolver;
+    private boolean startServer = true;
+    private String threadPattern = DEFAULT_PATTERN;
+
+    public void setNettyServerBootstrapConfiguration(NettySharedHttpServerBootstrapConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    public void setClassResolver(ClassResolver classResolver) {
+        this.classResolver = classResolver;
+    }
+
+    public int getPort() {
+        return configuration != null ? configuration.getPort() : -1;
+    }
+
+    public HttpServerConsumerChannelFactory getConsumerChannelFactory() {
+        return channelFactory;
+    }
+
+    public NettyServerBootstrapFactory getServerBootstrapFactory() {
+        return bootstrapFactory;
+    }
+
+    public int getConsumersSize() {
+        if (channelFactory != null) {
+            return channelFactory.consumers();
+        } else {
+            return -1;
+        }
+    }
+
+    public void setStartServer(boolean startServer) {
+        this.startServer = startServer;
+    }
+
+    public void setThreadNamePattern(String pattern) {
+        this.threadPattern = pattern;
+    }
+
+    protected void doStart() throws Exception {
+        ObjectHelper.notNull(configuration, "setNettyServerBootstrapConfiguration() must be called with a NettyServerBootstrapConfiguration instance", this);
+
+        // port must be set
+        if (configuration.getPort() <= 0) {
+            throw new IllegalArgumentException("Port must be configured on NettySharedHttpServerBootstrapConfiguration " + configuration);
+        }
+        // hostname must be set
+        if (ObjectHelper.isEmpty(configuration.getHost())) {
+            throw new IllegalArgumentException("Host must be configured on NettySharedHttpServerBootstrapConfiguration " + configuration);
+        }
+
+        LOG.debug("NettySharedHttpServer using configuration: {}", configuration);
+
+        // force using tcp as the underlying transport
+        configuration.setProtocol("tcp");
+
+        channelFactory = new HttpServerMultiplexChannelHandler();
+        channelFactory.init(configuration.getPort());
+
+        ChannelInitializer<Channel> pipelineFactory = new HttpServerSharedPipelineFactory(configuration, channelFactory, classResolver);
+
+        // thread factory and pattern
+        String port = Matcher.quoteReplacement("" + configuration.getPort());
+        String pattern = threadPattern;
+        pattern = pattern.replaceFirst("#port#", port);
+        ThreadFactory tf = new CamelThreadFactory(pattern, "NettySharedHttpServer", true);
+
+        // create bootstrap factory and disable compatible check as its shared among the consumers
+        bootstrapFactory = new HttpServerBootstrapFactory(channelFactory, false);
+        bootstrapFactory.init(tf, configuration, pipelineFactory);
+
+        ServiceHelper.startServices(channelFactory);
+
+        if (startServer) {
+            LOG.info("Starting NettySharedHttpServer on {}:{}", configuration.getHost(), configuration.getPort());
+            ServiceHelper.startServices(bootstrapFactory);
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        LOG.info("Stopping NettySharedHttpServer on {}:{}", configuration.getHost(), configuration.getPort());
+        ServiceHelper.stopServices(bootstrapFactory, channelFactory);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpClientPipelineFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpClientPipelineFactory.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpClientPipelineFactory.java
new file mode 100644
index 0000000..cb6610c
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpClientPipelineFactory.java
@@ -0,0 +1,165 @@
+/**
+ * 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 java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.timeout.ReadTimeoutHandler;
+import org.apache.camel.component.netty4.ClientPipelineFactory;
+import org.apache.camel.component.netty4.NettyConfiguration;
+import org.apache.camel.component.netty4.NettyProducer;
+import org.apache.camel.component.netty4.http.handlers.HttpClientChannelHandler;
+import org.apache.camel.component.netty4.ssl.SSLEngineFactory;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link org.apache.camel.component.netty.ClientPipelineFactory} for the Netty HTTP client.
+ */
+public class HttpClientPipelineFactory extends ClientPipelineFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpClientPipelineFactory.class);
+    protected NettyHttpConfiguration configuration;
+    private NettyHttpProducer producer;
+    private SSLContext sslContext;
+
+    public HttpClientPipelineFactory() {
+        // default constructor needed
+    }
+
+    public HttpClientPipelineFactory(NettyHttpProducer nettyProducer) {
+        this.producer = nettyProducer;
+        try {
+            this.sslContext = createSSLContext(producer);
+        } catch (Exception e) {
+            throw ObjectHelper.wrapRuntimeCamelException(e);
+        }
+
+        if (sslContext != null) {
+            LOG.info("Created SslContext {}", sslContext);
+        }
+        configuration = nettyProducer.getConfiguration();
+    }
+
+    @Override
+    public ClientPipelineFactory createPipelineFactory(NettyProducer nettyProducer) {
+        return new HttpClientPipelineFactory((NettyHttpProducer) nettyProducer);
+    }
+
+    @Override
+    protected void initChannel(Channel ch) throws Exception {
+        // create a new pipeline
+        ChannelPipeline pipeline = ch.pipeline();
+
+        SslHandler sslHandler = configureClientSSLOnDemand();
+        if (sslHandler != null) {
+            //TODO must close on SSL exception
+            //sslHandler.setCloseOnSSLException(true);
+            LOG.debug("Client SSL handler configured and added as an interceptor against the ChannelPipeline: {}", sslHandler);
+            pipeline.addLast("ssl", sslHandler);
+        }
+
+        pipeline.addLast("http", new HttpClientCodec());
+        pipeline.addLast("aggregator", new HttpObjectAggregator(configuration.getChunkedMaxContentLength()));
+
+        if (producer.getConfiguration().getRequestTimeout() > 0) {
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Using request timeout {} millis", producer.getConfiguration().getRequestTimeout());
+            }
+            ChannelHandler timeout = new ReadTimeoutHandler(producer.getConfiguration().getRequestTimeout(), TimeUnit.MILLISECONDS);
+            pipeline.addLast("timeout", timeout);
+        }
+
+        // handler to route Camel messages
+        pipeline.addLast("handler", new HttpClientChannelHandler(producer));
+
+        
+    }
+
+    private SSLContext createSSLContext(NettyProducer producer) throws Exception {
+        NettyConfiguration configuration = producer.getConfiguration();
+
+        if (!configuration.isSsl()) {
+            return null;
+        }
+
+        SSLContext answer;
+
+        // create ssl context once
+        if (configuration.getSslContextParameters() != null) {
+            answer = configuration.getSslContextParameters().createSSLContext();
+        } else {
+            if (configuration.getKeyStoreFile() == null && configuration.getKeyStoreResource() == null) {
+                LOG.debug("keystorefile is null");
+            }
+            if (configuration.getTrustStoreFile() == null && configuration.getTrustStoreResource() == null) {
+                LOG.debug("truststorefile is null");
+            }
+            if (configuration.getPassphrase().toCharArray() == null) {
+                LOG.debug("passphrase is null");
+            }
+
+            SSLEngineFactory sslEngineFactory;
+            if (configuration.getKeyStoreFile() != null || configuration.getTrustStoreFile() != null) {
+                sslEngineFactory = new SSLEngineFactory();
+                answer = sslEngineFactory.createSSLContext(producer.getContext().getClassResolver(),
+                        configuration.getKeyStoreFormat(),
+                        configuration.getSecurityProvider(),
+                        "file:" + configuration.getKeyStoreFile().getPath(),
+                        "file:" + configuration.getTrustStoreFile().getPath(),
+                        configuration.getPassphrase().toCharArray());
+            } else {
+                sslEngineFactory = new SSLEngineFactory();
+                answer = sslEngineFactory.createSSLContext(producer.getContext().getClassResolver(),
+                        configuration.getKeyStoreFormat(),
+                        configuration.getSecurityProvider(),
+                        configuration.getKeyStoreResource(),
+                        configuration.getTrustStoreResource(),
+                        configuration.getPassphrase().toCharArray());
+            }
+        }
+
+        return answer;
+    }
+
+    private SslHandler configureClientSSLOnDemand() throws Exception {
+        if (!producer.getConfiguration().isSsl()) {
+            return null;
+        }
+
+        if (producer.getConfiguration().getSslHandler() != null) {
+            return producer.getConfiguration().getSslHandler();
+        } else if (sslContext != null) {
+            SSLEngine engine = sslContext.createSSLEngine();
+            engine.setUseClientMode(true);
+            return new SslHandler(engine);
+        }
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpPrincipal.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpPrincipal.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpPrincipal.java
new file mode 100644
index 0000000..5e10ed9
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpPrincipal.java
@@ -0,0 +1,52 @@
+/**
+ * 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 java.security.Principal;
+
+/**
+ * Http {@link Principal}.
+ */
+public final class HttpPrincipal implements Principal {
+
+    private final String username;
+    private final String password;
+
+    public HttpPrincipal(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+    @Override
+    public String getName() {
+        return username;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public String toString() {
+        // do not display the password
+        return "HttpPrincipal[" + username + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerBootstrapFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerBootstrapFactory.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerBootstrapFactory.java
new file mode 100644
index 0000000..be4c9e1
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerBootstrapFactory.java
@@ -0,0 +1,104 @@
+/**
+ * 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 io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.netty4.NettyConsumer;
+import org.apache.camel.component.netty4.NettyServerBootstrapConfiguration;
+import org.apache.camel.component.netty4.SingleTCPNettyServerBootstrapFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HttpServerBootstrapFactory extends SingleTCPNettyServerBootstrapFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpServerBootstrapFactory.class);
+    private final HttpServerConsumerChannelFactory channelFactory;
+    private int port;
+    private NettyServerBootstrapConfiguration bootstrapConfiguration;
+    private boolean compatibleCheck;
+
+    public HttpServerBootstrapFactory(HttpServerConsumerChannelFactory channelFactory) {
+        this(channelFactory, true);
+    }
+
+    public HttpServerBootstrapFactory(HttpServerConsumerChannelFactory channelFactory, boolean compatibleCheck) {
+        this.channelFactory = channelFactory;
+        this.compatibleCheck = compatibleCheck;
+    }
+
+    @Override
+    public void init(CamelContext camelContext, NettyServerBootstrapConfiguration configuration, ChannelInitializer<Channel> pipelineFactory) {
+        super.init(camelContext, configuration, pipelineFactory);
+        this.port = configuration.getPort();
+        this.bootstrapConfiguration = configuration;
+
+        LOG.info("BootstrapFactory on port {} is using bootstrap configuration: [{}]", port, bootstrapConfiguration.toStringBootstrapConfiguration());
+    }
+
+    public void addConsumer(NettyConsumer consumer) {
+        if (compatibleCheck) {
+            // when adding additional consumers on the same port (eg to reuse port for multiple routes etc) then the Netty server bootstrap
+            // configuration must match, as its the 1st consumer that calls the init method, which configuration is used for the Netty server bootstrap
+            // we do this to avoid mis configuration, so people configure SSL and plain configuration on the same port etc.
+
+            // first it may be the same instance, so only check for compatibility of different instance
+            if (bootstrapConfiguration != consumer.getConfiguration() && !bootstrapConfiguration.compatible(consumer.getConfiguration())) {
+                throw new IllegalArgumentException("Bootstrap configuration must be identical when adding additional consumer: " + consumer.getEndpoint() + " on same port: " + port
+                    + ".\n  Existing " + bootstrapConfiguration.toStringBootstrapConfiguration() + "\n       New " + consumer.getConfiguration().toStringBootstrapConfiguration());
+            }
+        }
+
+        if (LOG.isDebugEnabled()) {
+            NettyHttpConsumer httpConsumer = (NettyHttpConsumer) consumer;
+            LOG.debug("BootstrapFactory on port {} is adding consumer with context-path {}", port, httpConsumer.getConfiguration().getPath());
+        }
+
+        channelFactory.addConsumer((NettyHttpConsumer) consumer);
+    }
+
+    @Override
+    public void removeConsumer(NettyConsumer consumer) {
+        if (LOG.isDebugEnabled()) {
+            NettyHttpConsumer httpConsumer = (NettyHttpConsumer) consumer;
+            LOG.debug("BootstrapFactory on port {} is removing consumer with context-path {}", port, httpConsumer.getConfiguration().getPath());
+        }
+        channelFactory.removeConsumer((NettyHttpConsumer) consumer);
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        LOG.debug("BootstrapFactory on port {} is starting", port);
+        super.doStart();
+    }
+
+    @Override
+    public void stop() throws Exception {
+        // only stop if no more active consumers
+        int consumers = channelFactory.consumers();
+        if (consumers == 0) {
+            LOG.debug("BootstrapFactory on port {} is stopping", port);
+            super.stop();
+        } else {
+            LOG.debug("BootstrapFactory on port {} has {} registered consumers, so cannot stop yet.", port, consumers);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerConsumerChannelFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerConsumerChannelFactory.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerConsumerChannelFactory.java
new file mode 100644
index 0000000..e1d51f6
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerConsumerChannelFactory.java
@@ -0,0 +1,63 @@
+/**
+ * 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 io.netty.channel.ChannelHandler;
+
+/**
+ * Factory for setting up Netty {@link ChannelHandler} bound to a given Netty port.
+ * <p/>
+ * This factory allows for consumers to reuse existing {@link io.netty.bootstrap.ServerBootstrap} which
+ * allows to share the same port for multiple consumers.
+ *
+ * This factory is needed to ensure we can handle the situations when consumers is added and removing in
+ * a dynamic environment such as OSGi, where Camel applications can be hot-deployed. And we want these
+ * Camel applications to be able to share the same Netty port in a easy way.
+ */
+public interface HttpServerConsumerChannelFactory {
+
+    /**
+     * Initializes this consumer channel factory with the given port.
+     */
+    void init(int port);
+
+    /**
+     * The port number this consumer channel factory is using.
+     */
+    int getPort();
+
+    /**
+     * Adds the given consumer.
+     */
+    void addConsumer(NettyHttpConsumer consumer);
+
+    /**
+     * Removes the given consumer
+     */
+    void removeConsumer(NettyHttpConsumer consumer);
+
+    /**
+     * Number of active consumers
+     */
+    int consumers();
+
+    /**
+     * Gets the {@link ChannelHandler}
+     */
+    ChannelHandler getChannelHandler();
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerPipelineFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerPipelineFactory.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerPipelineFactory.java
new file mode 100644
index 0000000..51ae265
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerPipelineFactory.java
@@ -0,0 +1,172 @@
+/**
+ * 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.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.HttpContentCompressor;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.concurrent.EventExecutorGroup;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.netty4.NettyConsumer;
+import org.apache.camel.component.netty4.NettyServerBootstrapConfiguration;
+import org.apache.camel.component.netty4.ServerPipelineFactory;
+import org.apache.camel.component.netty4.ssl.SSLEngineFactory;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link ServerPipelineFactory} for the Netty HTTP server.
+ */
+public class HttpServerPipelineFactory extends ServerPipelineFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpServerPipelineFactory.class);
+    protected NettyHttpConsumer consumer;
+    protected SSLContext sslContext;
+    protected NettyHttpConfiguration configuration;
+
+    public HttpServerPipelineFactory() {
+        // default constructor needed
+    }
+
+    public HttpServerPipelineFactory(NettyHttpConsumer nettyConsumer) {
+        this.consumer = nettyConsumer;
+        this.configuration = nettyConsumer.getConfiguration();
+        try {
+            this.sslContext = createSSLContext(consumer.getContext(), consumer.getConfiguration());
+        } catch (Exception e) {
+            throw ObjectHelper.wrapRuntimeCamelException(e);
+        }
+
+        if (sslContext != null) {
+            LOG.info("Created SslContext {}", sslContext);
+        }
+    }
+
+    @Override
+    public ServerPipelineFactory createPipelineFactory(NettyConsumer nettyConsumer) {
+        return new HttpServerPipelineFactory((NettyHttpConsumer) nettyConsumer);
+    }
+
+    @Override
+    protected void initChannel(Channel ch) throws Exception {
+        // create a new pipeline
+        ChannelPipeline pipeline = ch.pipeline();
+        
+        SslHandler sslHandler = configureServerSSLOnDemand();
+        if (sslHandler != null) {
+            //TODO must close on SSL exception
+            // sslHandler.setCloseOnSSLException(true);
+            LOG.debug("Server SSL handler configured and added as an interceptor against the ChannelPipeline: {}", sslHandler);
+            pipeline.addLast("ssl", sslHandler);
+        }
+
+        pipeline.addLast("decoder", new HttpRequestDecoder());
+        pipeline.addLast("aggregator", new HttpObjectAggregator(configuration.getChunkedMaxContentLength()));
+
+        pipeline.addLast("encoder", new HttpResponseEncoder());
+        if (supportCompressed()) {
+            pipeline.addLast("deflater", new HttpContentCompressor());
+        }
+
+        int port = consumer.getConfiguration().getPort();
+        ChannelHandler handler = consumer.getEndpoint().getComponent().getMultiplexChannelHandler(port).getChannelHandler();
+        
+        if (consumer.getConfiguration().isOrderedThreadPoolExecutor()) {
+            EventExecutorGroup applicationExecutor = consumer.getEndpoint().getComponent().getExecutorService();
+            pipeline.addLast(applicationExecutor, "handler", handler);
+        } else {
+            pipeline.addLast("handler", handler);
+        }
+        
+    }
+
+    private SSLContext createSSLContext(CamelContext camelContext, NettyServerBootstrapConfiguration configuration) throws Exception {
+        if (!configuration.isSsl()) {
+            return null;
+        }
+
+        SSLContext answer;
+
+        // create ssl context once
+        if (configuration.getSslContextParameters() != null) {
+            answer = configuration.getSslContextParameters().createSSLContext();
+        } else {
+            if (configuration.getKeyStoreFile() == null && configuration.getKeyStoreResource() == null) {
+                LOG.debug("keystorefile is null");
+            }
+            if (configuration.getTrustStoreFile() == null && configuration.getTrustStoreResource() == null) {
+                LOG.debug("truststorefile is null");
+            }
+            if (configuration.getPassphrase().toCharArray() == null) {
+                LOG.debug("passphrase is null");
+            }
+
+            SSLEngineFactory sslEngineFactory;
+            if (configuration.getKeyStoreFile() != null || configuration.getTrustStoreFile() != null) {
+                sslEngineFactory = new SSLEngineFactory();
+                answer = sslEngineFactory.createSSLContext(camelContext.getClassResolver(),
+                        configuration.getKeyStoreFormat(),
+                        configuration.getSecurityProvider(),
+                        "file:" + configuration.getKeyStoreFile().getPath(),
+                        "file:" + configuration.getTrustStoreFile().getPath(),
+                        configuration.getPassphrase().toCharArray());
+            } else {
+                sslEngineFactory = new SSLEngineFactory();
+                answer = sslEngineFactory.createSSLContext(camelContext.getClassResolver(),
+                        configuration.getKeyStoreFormat(),
+                        configuration.getSecurityProvider(),
+                        configuration.getKeyStoreResource(),
+                        configuration.getTrustStoreResource(),
+                        configuration.getPassphrase().toCharArray());
+            }
+        }
+
+        return answer;
+    }
+
+    private SslHandler configureServerSSLOnDemand() throws Exception {
+        if (!consumer.getConfiguration().isSsl()) {
+            return null;
+        }
+
+        if (consumer.getConfiguration().getSslHandler() != null) {
+            return consumer.getConfiguration().getSslHandler();
+        } else if (sslContext != null) {
+            SSLEngine engine = sslContext.createSSLEngine();
+            engine.setUseClientMode(false);
+            engine.setNeedClientAuth(consumer.getConfiguration().isNeedClientAuth());
+            return new SslHandler(engine);
+        }
+
+        return null;
+    }
+
+    private boolean supportCompressed() {
+        return consumer.getEndpoint().getConfiguration().isCompression();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerSharedPipelineFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerSharedPipelineFactory.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerSharedPipelineFactory.java
new file mode 100644
index 0000000..3f47ff9
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/HttpServerSharedPipelineFactory.java
@@ -0,0 +1,159 @@
+/**
+ * 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.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.HttpContentCompressor;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.ssl.SslHandler;
+import org.apache.camel.component.netty4.NettyConsumer;
+import org.apache.camel.component.netty4.ServerPipelineFactory;
+import org.apache.camel.component.netty4.ssl.SSLEngineFactory;
+import org.apache.camel.impl.DefaultClassResolver;
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A shared {@link org.apache.camel.component.netty.ServerPipelineFactory} for a shared Netty HTTP server.
+ *
+ * @see NettySharedHttpServer
+ */
+public class HttpServerSharedPipelineFactory extends HttpServerPipelineFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpServerSharedPipelineFactory.class);
+    private final NettySharedHttpServerBootstrapConfiguration configuration;
+    private final HttpServerConsumerChannelFactory channelFactory;
+    private final ClassResolver classResolver;
+    private SSLContext sslContext;
+
+    public HttpServerSharedPipelineFactory(NettySharedHttpServerBootstrapConfiguration configuration, HttpServerConsumerChannelFactory channelFactory,
+                                           ClassResolver classResolver) {
+        this.configuration = configuration;
+        this.channelFactory = channelFactory;
+        // fallback and use default resolver
+        this.classResolver = classResolver != null ? classResolver : new DefaultClassResolver();
+
+        try {
+            this.sslContext = createSSLContext();
+        } catch (Exception e) {
+            throw ObjectHelper.wrapRuntimeCamelException(e);
+        }
+
+        if (sslContext != null) {
+            LOG.info("Created SslContext {}", sslContext);
+        }
+    }
+
+    @Override
+    public ServerPipelineFactory createPipelineFactory(NettyConsumer nettyConsumer) {
+        throw new UnsupportedOperationException("Should not call this operation");
+    }
+
+    @Override
+    protected void initChannel(Channel ch) throws Exception {
+        // create a new pipeline
+        ChannelPipeline pipeline = ch.pipeline();
+
+        SslHandler sslHandler = configureServerSSLOnDemand();
+        if (sslHandler != null) {
+            LOG.debug("Server SSL handler configured and added as an interceptor against the ChannelPipeline: {}", sslHandler);
+            pipeline.addLast("ssl", sslHandler);
+        }
+
+        pipeline.addLast("decoder", new HttpRequestDecoder());
+        if (configuration.isChunked()) {
+            pipeline.addLast("aggregator", new HttpObjectAggregator(configuration.getChunkedMaxContentLength()));
+        }
+        pipeline.addLast("encoder", new HttpResponseEncoder());
+        if (configuration.isCompression()) {
+            pipeline.addLast("deflater", new HttpContentCompressor());
+        }
+
+        pipeline.addLast("handler", channelFactory.getChannelHandler());
+        
+    }
+
+    private SSLContext createSSLContext() throws Exception {
+        if (!configuration.isSsl()) {
+            return null;
+        }
+
+        SSLContext answer;
+
+        // create ssl context once
+        if (configuration.getSslContextParameters() != null) {
+            answer = configuration.getSslContextParameters().createSSLContext();
+        } else {
+            if (configuration.getKeyStoreFile() == null && configuration.getKeyStoreResource() == null) {
+                LOG.debug("keystorefile is null");
+            }
+            if (configuration.getTrustStoreFile() == null && configuration.getTrustStoreResource() == null) {
+                LOG.debug("truststorefile is null");
+            }
+            if (configuration.getPassphrase().toCharArray() == null) {
+                LOG.debug("passphrase is null");
+            }
+
+            SSLEngineFactory sslEngineFactory;
+            if (configuration.getKeyStoreFile() != null || configuration.getTrustStoreFile() != null) {
+                sslEngineFactory = new SSLEngineFactory();
+                answer = sslEngineFactory.createSSLContext(classResolver,
+                        configuration.getKeyStoreFormat(),
+                        configuration.getSecurityProvider(),
+                        "file:" + configuration.getKeyStoreFile().getPath(),
+                        "file:" + configuration.getTrustStoreFile().getPath(),
+                        configuration.getPassphrase().toCharArray());
+            } else {
+                sslEngineFactory = new SSLEngineFactory();
+                answer = sslEngineFactory.createSSLContext(classResolver,
+                        configuration.getKeyStoreFormat(),
+                        configuration.getSecurityProvider(),
+                        configuration.getKeyStoreResource(),
+                        configuration.getTrustStoreResource(),
+                        configuration.getPassphrase().toCharArray());
+            }
+        }
+
+        return answer;
+    }
+
+    private SslHandler configureServerSSLOnDemand() throws Exception {
+        if (!configuration.isSsl()) {
+            return null;
+        }
+
+        if (configuration.getSslHandler() != null) {
+            return configuration.getSslHandler();
+        } else if (sslContext != null) {
+            SSLEngine engine = sslContext.createSSLEngine();
+            engine.setUseClientMode(false);
+            engine.setNeedClientAuth(configuration.isNeedClientAuth());
+            return new SslHandler(engine);
+        }
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/db88eeda/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/JAASSecurityAuthenticator.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/JAASSecurityAuthenticator.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/JAASSecurityAuthenticator.java
new file mode 100644
index 0000000..4f21def
--- /dev/null
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/JAASSecurityAuthenticator.java
@@ -0,0 +1,72 @@
+/**
+ * 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 java.security.Principal;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A JAAS based {@link SecurityAuthenticator} implementation.
+ */
+public class JAASSecurityAuthenticator extends SecurityAuthenticatorSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JAASSecurityAuthenticator.class);
+
+    @Override
+    public Subject login(HttpPrincipal principal) throws LoginException {
+        if (ObjectHelper.isEmpty(getName())) {
+            throw new IllegalArgumentException("Realm has not been configured on this SecurityAuthenticator: " + this);
+        }
+
+        LOG.trace("Login username: {} using realm: {}", principal.getName(), getName());
+        LoginContext context = new LoginContext(getName(), new HttpPrincipalCallbackHandler(principal));
+        context.login();
+        Subject subject = context.getSubject();
+        LOG.debug("Login username: {} successful returning Subject: {}", principal.getName(), subject);
+
+        if (LOG.isTraceEnabled()) {
+            for (Principal p : subject.getPrincipals()) {
+                LOG.trace("Principal on subject {} -> {}", p.getClass().getName(), p.getName());
+            }
+        }
+
+        return subject;
+    }
+
+    @Override
+    public void logout(Subject subject) throws LoginException {
+        if (ObjectHelper.isEmpty(getName())) {
+            throw new LoginException("Realm has not been configured on this SecurityAuthenticator: " + this);
+        }
+
+        String username = "";
+        if (!subject.getPrincipals().isEmpty()) {
+            username = subject.getPrincipals().iterator().next().getName();
+        }
+        LOG.trace("Logging out username: {} using realm: {}", username, getName());
+        LoginContext context = new LoginContext(getName(), subject);
+        context.logout();
+        LOG.debug("Logout username: {} successful", username);
+    }
+
+}


Mime
View raw message