You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2015/07/15 11:36:41 UTC
[2/6] camel git commit: Initial commit of Camel Undertow component
Initial commit of Camel Undertow component
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/100b2f40
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/100b2f40
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/100b2f40
Branch: refs/heads/master
Commit: 100b2f408d9169e90b222c039e32021fa4638a1a
Parents: f5ab9e4
Author: David Simansky <ds...@redhat.com>
Authored: Tue Jul 14 17:46:35 2015 +0200
Committer: David Simansky <ds...@redhat.com>
Committed: Wed Jul 15 10:56:18 2015 +0200
----------------------------------------------------------------------
components/camel-undertow/pom.xml | 70 ++++
.../undertow/DefaultUndertowHttpBinding.java | 359 +++++++++++++++++++
.../component/undertow/ExchangeHeaders.java | 176 +++++++++
.../component/undertow/UndertowComponent.java | 281 +++++++++++++++
.../component/undertow/UndertowConsumer.java | 58 +++
.../component/undertow/UndertowEndpoint.java | 196 ++++++++++
.../component/undertow/UndertowHttpBinding.java | 50 +++
.../component/undertow/UndertowProducer.java | 159 ++++++++
.../component/undertow/UndertowRegistry.java | 116 ++++++
.../camel/component/undertow/UndertowUtils.java | 49 +++
.../undertow/handlers/HttpCamelHandler.java | 132 +++++++
.../undertow/handlers/NotFoundHandler.java | 36 ++
.../src/main/resources/META-INF/LICENSE.txt | 203 +++++++++++
.../src/main/resources/META-INF/NOTICE.txt | 11 +
.../org/apache/camel/component/undertow | 1 +
.../undertow/UndertowComponentTest.java | 84 +++++
.../undertow/UndertowError500Test.java | 57 +++
.../component/undertow/UndertowHeaderTest.java | 57 +++
.../undertow/UndertowHttpProducerTest.java | 72 ++++
.../undertow/UndertowHttpsSpringTest.java | 72 ++++
.../undertow/UndertowMethodRestricTest.java | 78 ++++
.../undertow/UndertowPrefixMatchingTest.java | 76 ++++
.../undertow/UndertowProducerTest.java | 77 ++++
.../undertow/UndertowSharedPortTest.java | 23 ++
.../src/test/resources/SpringTest.xml | 48 +++
.../src/test/resources/ssl/keystore.jks | Bin 0 -> 2246 bytes
components/pom.xml | 1 +
27 files changed, 2542 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-undertow/pom.xml b/components/camel-undertow/pom.xml
new file mode 100644
index 0000000..bb4b69a
--- /dev/null
+++ b/components/camel-undertow/pom.xml
@@ -0,0 +1,70 @@
+<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>components</artifactId>
+ <version>2.16-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>camel-undertow</artifactId>
+ <packaging>bundle</packaging>
+ <name>Camel :: Undertow</name>
+
+ <properties>
+ <camel.osgi.export.pkg>org.apache.camel.component.undertow.*</camel.osgi.export.pkg>
+ <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=undertow</camel.osgi.export.service>
+ <undertow-version>1.2.8.Final</undertow-version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.undertow</groupId>
+ <artifactId>undertow-core</artifactId>
+ <version>${undertow-version}</version>
+ </dependency>
+
+ <!-- testing -->
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-spring</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java
new file mode 100644
index 0000000..6ef3ba0
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java
@@ -0,0 +1,359 @@
+/**
+ * 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.undertow;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.ClientResponse;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.Headers;
+import io.undertow.util.HttpString;
+import io.undertow.util.Methods;
+import io.undertow.util.MimeMappings;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.component.http.HttpHeaderFilterStrategy;
+import org.apache.camel.impl.DefaultMessage;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.util.ExchangeHelper;
+import org.apache.camel.util.MessageHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xnio.Pooled;
+
+/**
+ * DefaultUndertowHttpBinding represent binding used by default, if user doesn't provide any.
+ * By default {@link HttpHeaderFilterStrategy} is also used.
+ *
+ */
+public class DefaultUndertowHttpBinding implements UndertowHttpBinding {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultUndertowHttpBinding.class);
+
+ //use default filter strategy from Camel HTTP
+ private HeaderFilterStrategy headerFilterStrategy;
+
+ public DefaultUndertowHttpBinding() {
+ this.headerFilterStrategy = new HttpHeaderFilterStrategy();
+ }
+
+ public DefaultUndertowHttpBinding(HeaderFilterStrategy headerFilterStrategy) {
+ this.headerFilterStrategy = headerFilterStrategy;
+ }
+
+ public HeaderFilterStrategy getHeaderFilterStrategy() {
+ return headerFilterStrategy;
+ }
+
+ public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) {
+ this.headerFilterStrategy = headerFilterStrategy;
+ }
+
+ @Override
+ public Message toCamelMessage(HttpServerExchange httpExchange, Exchange exchange) throws Exception {
+ Message result = new DefaultMessage();
+
+ populateCamelHeaders(httpExchange, result.getHeaders(), exchange);
+
+ //extract body if the method is allowed to have one
+ //body is extracted as byte[] then auto TypeConverter kicks in
+ if (Methods.POST.equals(httpExchange.getRequestMethod()) || Methods.PUT.equals(httpExchange.getRequestMethod())) {
+ byte[] bytes = readRequestBody(httpExchange);
+ result.setBody(bytes);
+ } else {
+ result.setBody(null);
+ }
+
+ return result;
+ }
+
+ @Override
+ public Message toCamelMessage(ClientExchange clientExchange, Exchange exchange) throws Exception {
+ Message result = new DefaultMessage();
+
+ //retrieve response headers
+ populateCamelHeaders(clientExchange.getResponse(), result.getHeaders(), exchange);
+
+ result.setBody(readResponseBody(clientExchange));
+
+ return result;
+
+ }
+
+ @Override
+ public void populateCamelHeaders(HttpServerExchange httpExchange, Map<String, Object> headersMap, Exchange exchange) throws Exception {
+ LOG.trace("populateCamelHeaders: {}");
+
+ // NOTE: these headers is applied using the same logic as camel-http/camel-jetty to be consistent
+ headersMap.put(Exchange.HTTP_METHOD, httpExchange.getRequestMethod().toString());
+ // strip query parameters from the uri
+ headersMap.put(Exchange.HTTP_URL, httpExchange.getRequestURL());
+ // uri is without the host and port
+ headersMap.put(Exchange.HTTP_URI, httpExchange.getRequestURI());
+ headersMap.put(Exchange.HTTP_QUERY, httpExchange.getQueryString());
+ headersMap.put(Exchange.HTTP_RAW_QUERY, httpExchange.getQueryString());
+
+
+ String path = httpExchange.getRequestPath();
+ headersMap.put(Exchange.HTTP_PATH, path);
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("HTTP-Method {}", httpExchange.getRequestMethod());
+ LOG.trace("HTTP-Uri {}", httpExchange.getRequestURI());
+ }
+
+ for (HttpString name : httpExchange.getRequestHeaders().getHeaderNames()) {
+ // mapping the content-type
+ //String name = httpName.toString();
+ if (name.toString().toLowerCase(Locale.US).equals("content-type")) {
+ name = ExchangeHeaders.CONTENT_TYPE;
+ }
+
+ if (name.toString().toLowerCase(Locale.US).equals("authorization")) {
+ String value = httpExchange.getRequestHeaders().get(name).toString();
+ // store a special header that this request was authenticated using HTTP Basic
+ if (value != null && value.trim().startsWith("Basic")) {
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(Exchange.AUTHENTICATION, "Basic", exchange)) {
+ UndertowUtils.appendHeader(headersMap, Exchange.AUTHENTICATION, "Basic");
+ }
+ }
+ }
+
+ // add the headers one by one, and use the header filter strategy
+ Iterator<?> it = httpExchange.getRequestHeaders().get(name).iterator();
+ while (it.hasNext()) {
+ Object value = it.next();
+ LOG.trace("HTTP-header: {}", value);
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(name.toString(), value, exchange)) {
+ UndertowUtils.appendHeader(headersMap, name.toString(), value);
+ }
+ }
+ }
+
+ //process uri parameters as headers
+ Map<String, Deque<String>> pathParameters = httpExchange.getQueryParameters();
+ //continue if the map is not empty, otherwise there are no params
+ if (!pathParameters.isEmpty()) {
+
+ for (Map.Entry<String, Deque<String>> entry : pathParameters.entrySet()) {
+ String name = entry.getKey();
+ Object values = entry.getValue();
+ Iterator<?> it = ObjectHelper.createIterator(values);
+ while (it.hasNext()) {
+ Object value = it.next();
+ LOG.trace("URI-Parameter: {}", value);
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) {
+ UndertowUtils.appendHeader(headersMap, name, value);
+ }
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public void populateCamelHeaders(ClientResponse response, Map<String, Object> headersMap, Exchange exchange) throws Exception {
+ LOG.trace("populateCamelHeaders: {}");
+
+ headersMap.put(Exchange.HTTP_RESPONSE_CODE, response.getResponseCode());
+
+ for (HttpString name : response.getResponseHeaders().getHeaderNames()) {
+ // mapping the content-type
+ //String name = httpName.toString();
+ if (name.toString().toLowerCase(Locale.US).equals("content-type")) {
+ name = ExchangeHeaders.CONTENT_TYPE;
+ }
+
+ if (name.toString().toLowerCase(Locale.US).equals("authorization")) {
+ String value = response.getResponseHeaders().get(name).toString();
+ // store a special header that this request was authenticated using HTTP Basic
+ if (value != null && value.trim().startsWith("Basic")) {
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(Exchange.AUTHENTICATION, "Basic", exchange)) {
+ UndertowUtils.appendHeader(headersMap, Exchange.AUTHENTICATION, "Basic");
+ }
+ }
+ }
+
+ // add the headers one by one, and use the header filter strategy
+ Iterator<?> it = response.getResponseHeaders().get(name).iterator();
+ while (it.hasNext()) {
+ Object value = it.next();
+ LOG.trace("HTTP-header: {}", value);
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToExternalHeaders(name.toString(), value, exchange)) {
+ UndertowUtils.appendHeader(headersMap, name.toString(), value);
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public Object toHttpResponse(HttpServerExchange httpExchange, Message message) {
+ boolean failed = message.getExchange().isFailed();
+ int defaultCode = failed ? 500 : 200;
+
+ int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, defaultCode, int.class);
+
+ httpExchange.setResponseCode(code);
+
+ TypeConverter tc = message.getExchange().getContext().getTypeConverter();
+
+ //copy headers from Message to Response
+ 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);
+ httpExchange.getResponseHeaders().add(new HttpString(key), headerValue);
+ }
+ }
+ }
+
+ Exception exception = message.getExchange().getException();
+
+ if (exception != null) {
+ httpExchange.getResponseHeaders().put(Headers.CONTENT_TYPE, MimeMappings.DEFAULT_MIME_MAPPINGS.get("txt"));
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ exception.printStackTrace(pw);
+
+ String exceptionMessage = sw.toString();
+
+ ExchangeHelper.setFailureHandled(message.getExchange());
+ return exceptionMessage;
+ }
+
+ // set the content type in the response.
+ String contentType = MessageHelper.getContentType(message);
+ if (contentType != null) {
+ // set content-type
+ httpExchange.getResponseHeaders().put(Headers.CONTENT_TYPE, contentType);
+ LOG.trace("Content-Type: {}", contentType);
+ }
+
+ return message.getBody();
+
+ }
+
+ @Override
+ public Object toHttpRequest(ClientRequest clientRequest, Message message) {
+
+ Object body = message.getBody();
+
+ String method = message.getHeader(Exchange.HTTP_METHOD, String.class);
+
+ if (method == null) {
+ //fallback if method is not defined, check the body
+ if (body == null) {
+ clientRequest.setMethod(Methods.GET);
+ } else {
+ clientRequest.setMethod(Methods.POST);
+ }
+ } else {
+ //method set, use it
+ clientRequest.setMethod(new HttpString(method));
+ }
+
+ // set the content type in the response.
+ String contentType = MessageHelper.getContentType(message);
+ if (contentType != null) {
+ // set content-type
+ clientRequest.getRequestHeaders().put(Headers.CONTENT_TYPE, contentType);
+ LOG.trace("Content-Type: {}", contentType);
+ }
+
+ TypeConverter tc = message.getExchange().getContext().getTypeConverter();
+
+ //copy headers from Message to Request
+ 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);
+ clientRequest.getRequestHeaders().add(new HttpString(key), headerValue);
+ }
+ }
+ }
+
+
+ return body;
+ }
+
+ private byte[] readRequestBody(HttpServerExchange httpExchange) throws IOException {
+ Pooled<ByteBuffer> pooledByteBuffer = httpExchange.getConnection().getBufferPool().allocate();
+ ByteBuffer byteBuffer = pooledByteBuffer.getResource();
+
+ byteBuffer.clear();
+
+ httpExchange.getRequestChannel().read(byteBuffer);
+ int pos = byteBuffer.position();
+ byteBuffer.rewind();
+ byte[] bytes = new byte[pos];
+ byteBuffer.get(bytes);
+
+ byteBuffer.clear();
+ pooledByteBuffer.free();
+ return bytes;
+ }
+
+ private byte[] readResponseBody(ClientExchange httpExchange) throws IOException {
+ Pooled<ByteBuffer> pooledByteBuffer = httpExchange.getConnection().getBufferPool().allocate();
+ ByteBuffer byteBuffer = pooledByteBuffer.getResource();
+
+ byteBuffer.clear();
+
+ httpExchange.getResponseChannel().read(byteBuffer);
+ int pos = byteBuffer.position();
+ byteBuffer.rewind();
+ byte[] bytes = new byte[pos];
+ byteBuffer.get(bytes);
+
+ byteBuffer.clear();
+ pooledByteBuffer.free();
+ return bytes;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/ExchangeHeaders.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/ExchangeHeaders.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/ExchangeHeaders.java
new file mode 100644
index 0000000..54f9d96
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/ExchangeHeaders.java
@@ -0,0 +1,176 @@
+/**
+ * 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.undertow;
+
+import io.undertow.util.HttpString;
+
+/**
+ * Copy of {@link org.apache.camel.Exchange} headers fields, to return them as {@link HttpString} for Undertow
+ *
+ */
+public final class ExchangeHeaders {
+
+ public static final HttpString AUTHENTICATION = new HttpString("CamelAuthentication");
+ public static final HttpString AUTHENTICATION_FAILURE_POLICY_ID = new HttpString("CamelAuthenticationFailurePolicyId");
+ public static final HttpString ACCEPT_CONTENT_TYPE = new HttpString("CamelAcceptContentType");
+ public static final HttpString AGGREGATED_SIZE = new HttpString("CamelAggregatedSize");
+ public static final HttpString AGGREGATED_TIMEOUT = new HttpString("CamelAggregatedTimeout");
+ public static final HttpString AGGREGATED_COMPLETED_BY = new HttpString("CamelAggregatedCompletedBy");
+ public static final HttpString AGGREGATED_CORRELATION_KEY = new HttpString("CamelAggregatedCorrelationKey");
+ public static final HttpString AGGREGATION_STRATEGY = new HttpString("CamelAggregationStrategy");
+ public static final HttpString AGGREGATION_COMPLETE_ALL_GROUPS = new HttpString("CamelAggregationCompleteAllGroups");
+ public static final HttpString AGGREGATION_COMPLETE_ALL_GROUPS_INCLUSIVE = new HttpString("CamelAggregationCompleteAllGroupsInclusive");
+ public static final HttpString ASYNC_WAIT = new HttpString("CamelAsyncWait");
+
+ public static final HttpString BATCH_INDEX = new HttpString("CamelBatchIndex");
+ public static final HttpString BATCH_SIZE = new HttpString("CamelBatchSize");
+ public static final HttpString BATCH_COMPLETE = new HttpString("CamelBatchComplete");
+ public static final HttpString BEAN_METHOD_NAME = new HttpString("CamelBeanMethodName");
+ public static final HttpString BEAN_MULTI_PARAMETER_ARRAY = new HttpString("CamelBeanMultiParameterArray");
+ public static final HttpString BINDING = new HttpString("CamelBinding");
+ // do not prefix with Camel and use lower-case starting letter as its a shared key
+ // used across other Apache products such as AMQ, SMX etc.
+ public static final HttpString BREADCRUMB_ID = new HttpString("breadcrumbId");
+
+ public static final HttpString CHARSET_NAME = new HttpString("CamelCharsetName");
+ public static final HttpString CREATED_TIMESTAMP = new HttpString("CamelCreatedTimestamp");
+ public static final HttpString CONTENT_ENCODING = new HttpString("Content-Encoding");
+ public static final HttpString CONTENT_LENGTH = new HttpString("Content-Length");
+ public static final HttpString CONTENT_TYPE = new HttpString("Content-Type");
+ public static final HttpString CORRELATION_ID = new HttpString("CamelCorrelationId");
+
+ public static final HttpString DATASET_INDEX = new HttpString("CamelDataSetIndex");
+ public static final HttpString DEFAULT_CHARSET_PROPERTY = new HttpString("org.apache.camel.default.charset");
+ public static final HttpString DESTINATION_OVERRIDE_URL = new HttpString("CamelDestinationOverrideUrl");
+ public static final HttpString DISABLE_HTTP_STREAM_CACHE = new HttpString("CamelDisableHttpStreamCache");
+ public static final HttpString DUPLICATE_MESSAGE = new HttpString("CamelDuplicateMessage");
+
+ public static final HttpString DOCUMENT_BUILDER_FACTORY = new HttpString("CamelDocumentBuilderFactory");
+
+ public static final HttpString EXCEPTION_CAUGHT = new HttpString("CamelExceptionCaught");
+ public static final HttpString EXCEPTION_HANDLED = new HttpString("CamelExceptionHandled");
+ public static final HttpString EVALUATE_EXPRESSION_RESULT = new HttpString("CamelEvaluateExpressionResult");
+ public static final HttpString ERRORHANDLER_HANDLED = new HttpString("CamelErrorHandlerHandled");
+ public static final HttpString EXTERNAL_REDELIVERED = new HttpString("CamelExternalRedelivered");
+
+ public static final HttpString FAILURE_HANDLED = new HttpString("CamelFailureHandled");
+ public static final HttpString FAILURE_ENDPOINT = new HttpString("CamelFailureEndpoint");
+ public static final HttpString FAILURE_ROUTE_ID = new HttpString("CamelFailureRouteId");
+ public static final HttpString FILTER_NON_XML_CHARS = new HttpString("CamelFilterNonXmlChars");
+ public static final HttpString FILE_LOCAL_WORK_PATH = new HttpString("CamelFileLocalWorkPath");
+ public static final HttpString FILE_NAME = new HttpString("CamelFileName");
+ public static final HttpString FILE_NAME_ONLY = new HttpString("CamelFileNameOnly");
+ public static final HttpString FILE_NAME_PRODUCED = new HttpString("CamelFileNameProduced");
+ public static final HttpString FILE_NAME_CONSUMED = new HttpString("CamelFileNameConsumed");
+ public static final HttpString FILE_PATH = new HttpString("CamelFilePath");
+ public static final HttpString FILE_PARENT = new HttpString("CamelFileParent");
+ public static final HttpString FILE_LAST_MODIFIED = new HttpString("CamelFileLastModified");
+ public static final HttpString FILE_LENGTH = new HttpString("CamelFileLength");
+ public static final HttpString FILTER_MATCHED = new HttpString("CamelFilterMatched");
+ public static final HttpString FILE_LOCK_FILE_ACQUIRED = new HttpString("CamelFileLockFileAcquired");
+ public static final HttpString FILE_LOCK_FILE_NAME = new HttpString("CamelFileLockFileName");
+
+ public static final HttpString GROUPED_EXCHANGE = new HttpString("CamelGroupedExchange");
+
+ public static final HttpString HTTP_BASE_URI = new HttpString("CamelHttpBaseUri");
+ public static final HttpString HTTP_CHARACTER_ENCODING = new HttpString("CamelHttpCharacterEncoding");
+ public static final HttpString HTTP_METHOD = new HttpString("CamelHttpMethod");
+ public static final HttpString HTTP_PATH = new HttpString("CamelHttpPath");
+ public static final HttpString HTTP_PROTOCOL_VERSION = new HttpString("CamelHttpProtocolVersion");
+ public static final HttpString HTTP_QUERY = new HttpString("CamelHttpQuery");
+ public static final HttpString HTTP_RAW_QUERY = new HttpString("CamelHttpRawQuery");
+ public static final HttpString HTTP_RESPONSE_CODE = new HttpString("CamelHttpResponseCode");
+ public static final HttpString HTTP_URI = new HttpString("CamelHttpUri");
+ public static final HttpString HTTP_URL = new HttpString("CamelHttpUrl");
+ public static final HttpString HTTP_CHUNKED = new HttpString("CamelHttpChunked");
+ public static final HttpString HTTP_SERVLET_REQUEST = new HttpString("CamelHttpServletRequest");
+ public static final HttpString HTTP_SERVLET_RESPONSE = new HttpString("CamelHttpServletResponse");
+
+ public static final HttpString INTERCEPTED_ENDPOINT = new HttpString("CamelInterceptedEndpoint");
+ public static final HttpString INTERCEPT_SEND_TO_ENDPOINT_WHEN_MATCHED = new HttpString("CamelInterceptSendToEndpointWhenMatched");
+
+ public static final HttpString LANGUAGE_SCRIPT = new HttpString("CamelLanguageScript");
+ public static final HttpString LOG_DEBUG_BODY_MAX_CHARS = new HttpString("CamelLogDebugBodyMaxChars");
+ public static final HttpString LOG_DEBUG_BODY_STREAMS = new HttpString("CamelLogDebugStreams");
+ public static final HttpString LOOP_INDEX = new HttpString("CamelLoopIndex");
+ public static final HttpString LOOP_SIZE = new HttpString("CamelLoopSize");
+
+ public static final HttpString MAXIMUM_CACHE_POOL_SIZE = new HttpString("CamelMaximumCachePoolSize");
+ public static final HttpString MAXIMUM_ENDPOINT_CACHE_SIZE = new HttpString("CamelMaximumEndpointCacheSize");
+ public static final HttpString MESSAGE_HISTORY = new HttpString("CamelMessageHistory");
+ public static final HttpString MULTICAST_INDEX = new HttpString("CamelMulticastIndex");
+ public static final HttpString MULTICAST_COMPLETE = new HttpString("CamelMulticastComplete");
+
+ public static final HttpString NOTIFY_EVENT = new HttpString("CamelNotifyEvent");
+
+ public static final HttpString ON_COMPLETION = new HttpString("CamelOnCompletion");
+ public static final HttpString OVERRULE_FILE_NAME = new HttpString("CamelOverruleFileName");
+
+ public static final HttpString PARENT_UNIT_OF_WORK = new HttpString("CamelParentUnitOfWork");
+
+ public static final HttpString RECIPIENT_LIST_ENDPOINT = new HttpString("CamelRecipientListEndpoint");
+ public static final HttpString RECEIVED_TIMESTAMP = new HttpString("CamelReceivedTimestamp");
+ public static final HttpString REDELIVERED = new HttpString("CamelRedelivered");
+ public static final HttpString REDELIVERY_COUNTER = new HttpString("CamelRedeliveryCounter");
+ public static final HttpString REDELIVERY_MAX_COUNTER = new HttpString("CamelRedeliveryMaxCounter");
+ public static final HttpString REDELIVERY_EXHAUSTED = new HttpString("CamelRedeliveryExhausted");
+ public static final HttpString REDELIVERY_DELAY = new HttpString("CamelRedeliveryDelay");
+ public static final HttpString ROLLBACK_ONLY = new HttpString("CamelRollbackOnly");
+ public static final HttpString ROLLBACK_ONLY_LAST = new HttpString("CamelRollbackOnlyLast");
+ public static final HttpString ROUTE_STOP = new HttpString("CamelRouteStop");
+
+ public static final HttpString SAXPARSER_FACTORY = new HttpString("CamelSAXParserFactory");
+
+ public static final HttpString SOAP_ACTION = new HttpString("CamelSoapAction");
+ public static final HttpString SKIP_GZIP_ENCODING = new HttpString("CamelSkipGzipEncoding");
+ public static final HttpString SKIP_WWW_FORM_URLENCODED = new HttpString("CamelSkipWwwFormUrlEncoding");
+ public static final HttpString SLIP_ENDPOINT = new HttpString("CamelSlipEndpoint");
+ public static final HttpString SPLIT_INDEX = new HttpString("CamelSplitIndex");
+ public static final HttpString SPLIT_COMPLETE = new HttpString("CamelSplitComplete");
+ public static final HttpString SPLIT_SIZE = new HttpString("CamelSplitSize");
+
+ public static final HttpString TIMER_COUNTER = new HttpString("CamelTimerCounter");
+ public static final HttpString TIMER_FIRED_TIME = new HttpString("CamelTimerFiredTime");
+ public static final HttpString TIMER_NAME = new HttpString("CamelTimerName");
+ public static final HttpString TIMER_PERIOD = new HttpString("CamelTimerPeriod");
+ public static final HttpString TIMER_TIME = new HttpString("CamelTimerTime");
+ public static final HttpString TO_ENDPOINT = new HttpString("CamelToEndpoint");
+ public static final HttpString TRACE_EVENT = new HttpString("CamelTraceEvent");
+ public static final HttpString TRACE_EVENT_NODE_ID = new HttpString("CamelTraceEventNodeId");
+ public static final HttpString TRACE_EVENT_TIMESTAMP = new HttpString("CamelTraceEventTimestamp");
+ public static final HttpString TRACE_EVENT_EXCHANGE = new HttpString("CamelTraceEventExchange");
+ public static final HttpString TRY_ROUTE_BLOCK = new HttpString("TryRouteBlock");
+ public static final HttpString TRANSFER_ENCODING = new HttpString("Transfer-Encoding");
+
+ public static final HttpString UNIT_OF_WORK_EXHAUSTED = new HttpString("CamelUnitOfWorkExhausted");
+
+ /**
+ * @deprecated UNIT_OF_WORK_PROCESS_SYNC is not in use and will be removed in future Camel release
+ */
+ @Deprecated
+ public static final HttpString UNIT_OF_WORK_PROCESS_SYNC = new HttpString("CamelUnitOfWorkProcessSync");
+
+ public static final HttpString XSLT_FILE_NAME = new HttpString("CamelXsltFileName");
+ public static final HttpString XSLT_ERROR = new HttpString("CamelXsltError");
+ public static final HttpString XSLT_FATAL_ERROR = new HttpString("CamelXsltFatalError");
+ public static final HttpString XSLT_WARNING = new HttpString("CamelXsltWarning");
+
+ private ExchangeHeaders() {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
new file mode 100644
index 0000000..91bd8a8
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
@@ -0,0 +1,281 @@
+/**
+ * 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.undertow;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import javax.net.ssl.SSLContext;
+
+import io.undertow.Handlers;
+import io.undertow.Undertow;
+import io.undertow.server.handlers.PathHandler;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Consumer;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
+import org.apache.camel.component.http.HttpBinding;
+import org.apache.camel.component.http.HttpClientConfigurer;
+import org.apache.camel.component.http.HttpComponent;
+import org.apache.camel.component.http.HttpConfiguration;
+import org.apache.camel.component.undertow.handlers.HttpCamelHandler;
+import org.apache.camel.component.undertow.handlers.NotFoundHandler;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.RestConsumerFactory;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.URISupport;
+import org.apache.camel.util.UnsafeUriCharactersEncoder;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents the component that manages {@link UndertowEndpoint}.
+ *
+ */
+public class UndertowComponent extends HttpComponent implements RestConsumerFactory {
+ private static final Logger LOG = LoggerFactory.getLogger(UndertowEndpoint.class);
+
+ private UndertowHttpBinding undertowHttpBinding;
+ private Map<Integer, UndertowRegistry> serversRegistry = new HashMap<Integer, UndertowRegistry>();
+
+ public UndertowComponent() {
+ this.undertowHttpBinding = new DefaultUndertowHttpBinding();
+ }
+
+ @Override
+ protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+ //extract parameters from URI
+ Boolean matchOnUriPrefix = getAndRemoveParameter(parameters, "matchOnUriPrefix", Boolean.class);
+ HeaderFilterStrategy headerFilterStrategy = resolveAndRemoveReferenceParameter(parameters, "headerFilterStrategy", HeaderFilterStrategy.class);
+ SSLContextParameters sslContextParameters = resolveAndRemoveReferenceParameter(parameters, "sslContextParametersRef", SSLContextParameters.class);
+ Boolean throwExceptionOnFailure = getAndRemoveParameter(parameters, "throwExceptionOnFailure", Boolean.class);
+ Boolean transferException = getAndRemoveParameter(parameters, "transferException", Boolean.class);
+
+ String httpMethodRestrict = getAndRemoveParameter(parameters, "httpMethodRestrict", String.class);
+
+ System.out.println("Remaining: " + remaining);
+ String address = remaining;
+ URI httpUri = new URI(UnsafeUriCharactersEncoder.encodeHttpURI(address));
+ URI endpointUri = URISupport.createRemainingURI(httpUri, parameters);
+
+ UndertowEndpoint endpoint = new UndertowEndpoint(endpointUri.toString(), this, httpUri);
+
+ if (endpoint.getUndertowHttpBinding() == null) {
+ endpoint.setUndertowHttpBinding(undertowHttpBinding);
+ }
+
+ //set parameters if they exists in URI
+ if (httpMethodRestrict != null) {
+ endpoint.setHttpMethodRestrict(httpMethodRestrict);
+ }
+ if (matchOnUriPrefix != null) {
+ endpoint.setMatchOnUriPrefix(matchOnUriPrefix);
+ }
+ if (headerFilterStrategy != null) {
+ endpoint.setHeaderFilterStrategy(headerFilterStrategy);
+ }
+ if (sslContextParameters != null) {
+ SSLContext sslContext = sslContextParameters.createSSLContext();
+ endpoint.setSslContext(sslContext);
+ }
+ if (throwExceptionOnFailure != null) {
+ endpoint.setThrowExceptionOnFailure(throwExceptionOnFailure);
+ }
+ if (transferException != null) {
+ endpoint.setTransferException(transferException);
+ }
+
+ setProperties(endpoint, parameters);
+ return endpoint;
+ }
+
+ @Override
+ public Consumer createConsumer(CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate,
+ String consumes, String produces, Map<String, Object> parameters) throws Exception {
+ String path = basePath;
+ if (uriTemplate != null) {
+ // make sure to avoid double slashes
+ if (uriTemplate.startsWith("/")) {
+ path = path + uriTemplate;
+ } else {
+ path = path + "/" + uriTemplate;
+ }
+ }
+ path = FileUtil.stripLeadingSeparator(path);
+ String scheme = "http";
+ String host = "";
+ int port = 0;
+ RestConfiguration config = getCamelContext().getRestConfiguration();
+ if (config.getComponent() == null || config.getComponent().equals("undertow")) {
+ if (config.getScheme() != null) {
+ scheme = config.getScheme();
+ }
+ if (config.getHost() != null) {
+ host = config.getHost();
+ }
+ int num = config.getPort();
+ if (num > 0) {
+ port = num;
+ }
+ }
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ // build query string, and append any endpoint configuration properties
+ if (config != null && (config.getComponent() == null || config.getComponent().equals("undertow"))) {
+ // setup endpoint options
+ if (config.getEndpointProperties() != null && !config.getEndpointProperties().isEmpty()) {
+ map.putAll(config.getEndpointProperties());
+ }
+ }
+
+ String query = URISupport.createQueryString(map);
+
+ String url = "undertow:%s://%s:%s/%s";
+ url = String.format(url, scheme, host, port, path);
+ if (!query.isEmpty()) {
+ url = url + "&" + query;
+ }
+
+ UndertowEndpoint endpoint = camelContext.getEndpoint(url, UndertowEndpoint.class);
+ setProperties(endpoint, parameters);
+
+ Consumer consumer = endpoint.createConsumer(processor);
+
+ return consumer;
+
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ super.doStop();
+ }
+
+ protected Undertow rebuildServer(UndertowRegistry registy) {
+ Undertow.Builder result = Undertow.builder();
+ int port = registy.getPort();
+ if (registy.getSslContext() != null) {
+ result = result.addHttpsListener(registy.getPort(), registy.getHost(), registy.getSslContext());
+ } else {
+ result = result.addHttpListener(registy.getPort(), registy.getHost());
+ }
+ PathHandler path = Handlers.path(new NotFoundHandler());
+ for (URI key : registy.getConsumersRegistry().keySet()) {
+ UndertowConsumer consumer = registy.getConsumersRegistry().get(key);
+ URI httpUri = consumer.getEndpoint().getHttpURI();
+ if (consumer.getEndpoint().getMatchOnUriPrefix()) {
+ path.addPrefixPath(httpUri.getPath(), new HttpCamelHandler(consumer));
+
+ } else {
+ path.addExactPath(httpUri.getPath(), new HttpCamelHandler(consumer));
+
+ }
+ LOG.debug("::Rebuild for path: {}", httpUri.getPath());
+ }
+ result = result.setHandler(path);
+ return result.build();
+ }
+
+ public void registerConsumer(UndertowConsumer consumer) {
+ int port = consumer.getEndpoint().getHttpURI().getPort();
+ if (serversRegistry.containsKey(port)) {
+ //server listens on port, we need add configuration for path
+ UndertowRegistry undertowRegistry = serversRegistry.get(port);
+ undertowRegistry.registerConsumer(consumer);
+ } else {
+ //create new server to listen on specified port
+ serversRegistry.put(port, new UndertowRegistry(consumer, port));
+ }
+ }
+
+ public void unregisterConsumer(UndertowConsumer consumer) {
+ int port = consumer.getEndpoint().getHttpURI().getPort();
+ if (serversRegistry.containsKey(port)) {
+ serversRegistry.get(port).unregisterConsumer(consumer);
+ }
+ if (serversRegistry.get(port).isEmpty()) {
+ //if there no Consumer left, we can shut down server
+ serversRegistry.get(port).getServer().stop();
+ serversRegistry.remove(port);
+ } else {
+ //call startServer to rebuild otherwise
+ startServer(consumer);
+ }
+ }
+
+ public void startServer(UndertowConsumer consumer) {
+ int port = consumer.getEndpoint().getHttpURI().getPort();
+ LOG.info("Starting server on port: {}", port);
+ UndertowRegistry undertowRegistry = serversRegistry.get(port);
+
+ if (undertowRegistry.getServer() != null) {
+ //server is running, we need to stop it first and then rebuild
+ undertowRegistry.getServer().stop();
+ }
+ Undertow newServer = rebuildServer(undertowRegistry);
+ newServer.start();
+ undertowRegistry.setServer(newServer);
+ }
+
+ /**
+ * To use the custom HttpClientConfigurer to perform configuration of the HttpClient that will be used.
+ *
+ * @param httpClientConfigurer
+ */
+ @Override
+ public void setHttpClientConfigurer(HttpClientConfigurer httpClientConfigurer) {
+ super.setHttpClientConfigurer(httpClientConfigurer);
+ }
+
+ /**
+ * To use a custom HttpConnectionManager to manage connections
+ *
+ * @param httpConnectionManager
+ */
+ @Override
+ public void setHttpConnectionManager(HttpConnectionManager httpConnectionManager) {
+ super.setHttpConnectionManager(httpConnectionManager);
+ }
+
+ /**
+ * To use a custom HttpBinding to control the mapping between Camel message and HttpClient.
+ *
+ * @param httpBinding
+ */
+ @Override
+ public void setHttpBinding(HttpBinding httpBinding) {
+ super.setHttpBinding(httpBinding);
+ }
+
+ /**
+ * To use the shared HttpConfiguration as base configuration.
+ *
+ * @param httpConfiguration
+ */
+ @Override
+ public void setHttpConfiguration(HttpConfiguration httpConfiguration) {
+ super.setHttpConfiguration(httpConfiguration);
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
new file mode 100644
index 0000000..52c0cbf
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java
@@ -0,0 +1,58 @@
+/**
+ * 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.undertow;
+
+import org.apache.camel.Processor;
+import org.apache.camel.impl.DefaultConsumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Undertow consumer.
+ *
+ */
+public class UndertowConsumer extends DefaultConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UndertowConsumer.class);
+
+ public UndertowConsumer(UndertowEndpoint endpoint, Processor processor) {
+ super(endpoint, processor);
+
+ }
+
+ @Override
+ public UndertowEndpoint getEndpoint() {
+ return (UndertowEndpoint) super.getEndpoint();
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+ LOG.debug("Undertow consumer is starting");
+ getEndpoint().getComponent().registerConsumer(this);
+ getEndpoint().getComponent().startServer(this);
+ }
+
+ @Override
+ protected void doStop() {
+ LOG.debug("Undertow consumer is stopping");
+ getEndpoint().getComponent().unregisterConsumer(this);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/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
new file mode 100644
index 0000000..064f18c
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java
@@ -0,0 +1,196 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.undertow;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import javax.net.ssl.SSLContext;
+
+import io.undertow.server.HttpServerExchange;
+import org.apache.camel.Consumer;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.PollingConsumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.HeaderFilterStrategyAware;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents an Undertow endpoint.
+ *
+ */
+@UriEndpoint(scheme = "undertow", title = "Undertow", syntax = "undertow:host:port/path",
+ consumerClass = UndertowConsumer.class, label = "http")
+public class UndertowEndpoint extends DefaultEndpoint implements HeaderFilterStrategyAware {
+ private static final Logger LOG = LoggerFactory.getLogger(UndertowEndpoint.class);
+
+ private UndertowHttpBinding undertowHttpBinding;
+ private UndertowComponent component;
+ private HeaderFilterStrategy headerFilterStrategy;
+ private SSLContext sslContext;
+
+ @UriPath
+ private URI httpURI;
+ @UriParam
+ private String httpMethodRestrict;
+ @UriParam
+ private Boolean matchOnUriPrefix = true;
+ @UriParam
+ private Boolean throwExceptionOnFailure;
+ @UriParam
+ private Boolean transferException;
+
+ public UndertowEndpoint(String uri, UndertowComponent component, URI httpURI) throws URISyntaxException {
+ super(uri, component);
+ this.component = component;
+ this.httpURI = httpURI;
+ }
+
+ @Override
+ public Producer createProducer() throws Exception {
+ return new UndertowProducer(this);
+ }
+
+ public Exchange createExchange(HttpServerExchange httpExchange) throws Exception {
+ Exchange exchange = createExchange();
+
+ Message in = getUndertowHttpBinding().toCamelMessage(httpExchange, exchange);
+
+ exchange.setProperty(Exchange.CHARSET_NAME, httpExchange.getRequestCharset());
+ in.setHeader(Exchange.HTTP_CHARACTER_ENCODING, httpExchange.getRequestCharset());
+
+ exchange.setIn(in);
+ return exchange;
+ }
+
+ public Consumer createConsumer(Processor processor) throws Exception {
+ return new UndertowConsumer(this, processor);
+ }
+
+ @Override
+ public PollingConsumer createPollingConsumer() throws Exception {
+ //throw exception as polling consumer is not supported
+ throw new UnsupportedOperationException("This component does not support polling consumer");
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public URI getHttpURI() {
+ return httpURI;
+ }
+
+ /**
+ * Set full HTTP URI
+ * @param httpURI
+ */
+ public void setHttpURI(URI httpURI) {
+ this.httpURI = httpURI;
+ }
+
+
+ public String getHttpMethodRestrict() {
+ return httpMethodRestrict;
+ }
+
+ /**
+ * Configure set of allowed HTTP request method
+ * @param httpMethodRestrict
+ */
+ public void setHttpMethodRestrict(String httpMethodRestrict) {
+ this.httpMethodRestrict = httpMethodRestrict;
+ }
+
+ public Boolean getMatchOnUriPrefix() {
+ return matchOnUriPrefix;
+ }
+
+ /**
+ * Set if URI should be matched on prefix
+ * @param matchOnUriPrefix
+ */
+ public void setMatchOnUriPrefix(Boolean matchOnUriPrefix) {
+ this.matchOnUriPrefix = matchOnUriPrefix;
+ }
+
+ public HeaderFilterStrategy getHeaderFilterStrategy() {
+ return headerFilterStrategy;
+ }
+
+ public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) {
+ this.headerFilterStrategy = headerFilterStrategy;
+ undertowHttpBinding.setHeaderFilterStrategy(headerFilterStrategy);
+ }
+
+ public SSLContext getSslContext() {
+ return sslContext;
+ }
+
+ public void setSslContext(SSLContext sslContext) {
+ this.sslContext = sslContext;
+ }
+
+ public Boolean getThrowExceptionOnFailure() {
+ return throwExceptionOnFailure;
+ }
+
+ /**
+ * Configure if exception should be thrown on failure
+ * @param throwExceptionOnFailure
+ */
+ public void setThrowExceptionOnFailure(Boolean throwExceptionOnFailure) {
+ this.throwExceptionOnFailure = throwExceptionOnFailure;
+ }
+
+ public Boolean getTransferException() {
+ return transferException;
+ }
+
+ /**
+ * Configure if expcetion should be transfered to client
+ * @param transferException
+ */
+ public void setTransferException(Boolean transferException) {
+ this.transferException = transferException;
+ }
+
+ public UndertowHttpBinding getUndertowHttpBinding() {
+ return undertowHttpBinding;
+ }
+
+ public void setUndertowHttpBinding(UndertowHttpBinding undertowHttpBinding) {
+ this.undertowHttpBinding = undertowHttpBinding;
+ }
+
+ @Override
+ public UndertowComponent getComponent() {
+ return component;
+ }
+
+ public void setComponent(UndertowComponent component) {
+ this.component = component;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHttpBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHttpBinding.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHttpBinding.java
new file mode 100644
index 0000000..b9aad5b
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHttpBinding.java
@@ -0,0 +1,50 @@
+/**
+ * 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.undertow;
+
+import java.util.Map;
+
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.ClientResponse;
+import io.undertow.server.HttpServerExchange;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.spi.HeaderFilterStrategy;
+
+/**
+ * Interface to define custom binding for the component
+ *
+ */
+public interface UndertowHttpBinding {
+
+ Message toCamelMessage(HttpServerExchange httpExchange, Exchange exchange) throws Exception;
+
+ Message toCamelMessage(ClientExchange clientExchange, Exchange exchange) throws Exception;
+
+ void populateCamelHeaders(HttpServerExchange httpExchange, Map<String, Object> headerMap, Exchange exchange) throws Exception;
+
+ void populateCamelHeaders(ClientResponse response, Map<String, Object> headerMap, Exchange exchange) throws Exception;
+
+ Object toHttpResponse(HttpServerExchange httpExchange, Message message);
+
+ Object toHttpRequest(ClientRequest clientRequest, Message message);
+
+ void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy);
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/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
new file mode 100644
index 0000000..4136824
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowProducer.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.undertow;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.UndertowClient;
+import io.undertow.util.Headers;
+import io.undertow.util.Protocols;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.impl.DefaultProducer;
+import org.apache.camel.util.ExchangeHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xnio.BufferAllocator;
+import org.xnio.ByteBufferSlicePool;
+import org.xnio.IoFuture;
+import org.xnio.OptionMap;
+import org.xnio.Xnio;
+import org.xnio.XnioWorker;
+
+/**
+ * The Undertow producer.
+ *
+ * The implementation of Producer is considered as experimental. The Undertow client classes are not thread safe,
+ * their purpose is for the reverse proxy usage inside Undertow itself. This may change in the future versions and
+ * general purpose HTTP client wrapper will be added. Therefore this Producer may be changed too.
+ *
+ */
+public class UndertowProducer extends DefaultProducer {
+ private static final Logger LOG = LoggerFactory.getLogger(UndertowProducer.class);
+ private UndertowEndpoint endpoint;
+
+ public UndertowProducer(UndertowEndpoint endpoint) {
+ super(endpoint);
+ this.endpoint = endpoint;
+ }
+
+ @Override
+ public UndertowEndpoint getEndpoint() {
+ return endpoint;
+ }
+
+ public void setEndpoint(UndertowEndpoint endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ LOG.info("Producer endpoint uri " + endpoint.getHttpURI());
+
+ final UndertowClient client = UndertowClient.getInstance();
+ XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY);
+ IoFuture<ClientConnection> connect = client.connect(endpoint.getHttpURI(), worker, new ByteBufferSlicePool(BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR, 8192, 8192 * 8192), OptionMap.EMPTY);
+
+ ClientRequest request = new ClientRequest();
+ request.setProtocol(Protocols.HTTP_1_1);
+
+ Object body = getRequestBody(request, exchange);
+
+
+ TypeConverter tc = endpoint.getCamelContext().getTypeConverter();
+ ByteBuffer bodyAsByte = tc.convertTo(ByteBuffer.class, body);
+
+ if (body != null) {
+ request.getRequestHeaders().put(Headers.CONTENT_LENGTH, bodyAsByte.array().length);
+ }
+
+ connect.get().sendRequest(request, new UndertowProducerCallback(bodyAsByte, exchange));
+
+ }
+
+ private Object getRequestBody(ClientRequest request, Exchange camelExchange) {
+ Object result;
+ result = endpoint.getUndertowHttpBinding().toHttpRequest(request, camelExchange.getIn());
+ return result;
+ }
+
+ /**
+ * Everything important happens in callback
+ */
+ private class UndertowProducerCallback implements ClientCallback<ClientExchange> {
+
+ private ByteBuffer body;
+ private Exchange camelExchange;
+
+ public UndertowProducerCallback(ByteBuffer body, Exchange camelExchange) {
+ this.body = body;
+ this.camelExchange = camelExchange;
+ }
+
+ @Override
+ public void completed(ClientExchange clientExchange) {
+ clientExchange.setResponseListener(new ClientCallback<ClientExchange>() {
+ @Override
+ public void completed(ClientExchange clientExchange) {
+ Message message = null;
+ try {
+ message = endpoint.getUndertowHttpBinding().toCamelMessage(clientExchange, camelExchange);
+ } catch (Exception e) {
+ camelExchange.setException(e);
+ }
+ if (ExchangeHelper.isOutCapable(camelExchange)) {
+ camelExchange.setOut(message);
+ } else {
+ camelExchange.setIn(message);
+ }
+
+ }
+
+ @Override
+ public void failed(IOException e) {
+ camelExchange.setException(e);
+
+ }
+ });
+ try {
+ //send body if exists
+ if (body != null) {
+ clientExchange.getRequestChannel().write(body);
+ }
+ } catch (IOException e) {
+ LOG.error("Failed with: " + e.getMessage());
+ camelExchange.setException(e);
+ }
+
+ }
+
+ @Override
+ public void failed(IOException e) {
+ LOG.error("Failed with: " + e.getMessage());
+ camelExchange.setException(e);
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowRegistry.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowRegistry.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowRegistry.java
new file mode 100644
index 0000000..f05adc3
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowRegistry.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.undertow;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import javax.net.ssl.SSLContext;
+
+import io.undertow.Undertow;
+import org.apache.camel.RuntimeCamelException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to hold Undertow instances during runtime.
+ * One of the benefits is reuse of same TCP port for more endpoints.
+ *
+ */
+public class UndertowRegistry {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UndertowRegistry.class);
+
+ int port;
+ SSLContext sslContext;
+ String host;
+ Undertow server;
+ Map<URI, UndertowConsumer> consumersRegistry = new HashMap<URI, UndertowConsumer>();
+
+ public UndertowRegistry(UndertowConsumer consumer, int port) {
+ registerConsumer(consumer);
+ this.port = port;
+ if (consumer.getEndpoint().getSslContext() != null) {
+ sslContext = consumer.getEndpoint().getSslContext();
+ }
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public void registerConsumer(UndertowConsumer consumer) {
+ URI httpUri = consumer.getEndpoint().getHttpURI();
+ if (host != null && !host.equals(httpUri.getHost())) {
+ throw new RuntimeCamelException("Can't register UndertowConsumer on different host and same port: {}" + host + " " + httpUri.getHost());
+ } else {
+ host = httpUri.getHost();
+ }
+ LOG.info("Adding consumer to consumerRegistry: {}", httpUri);
+ consumersRegistry.put(httpUri, consumer);
+ if (sslContext != null && consumer.getEndpoint().getSslContext() != null) {
+ throw new RuntimeCamelException("Can't register UndertowConsumer with different SSL config");
+ }
+
+ }
+
+ public void unregisterConsumer(UndertowConsumer consumer) {
+ URI httpUri = consumer.getEndpoint().getHttpURI();
+ if (consumersRegistry.containsKey(httpUri)) {
+ consumersRegistry.remove(httpUri);
+ } else {
+ throw new RuntimeCamelException("This consumer is not registered");
+ }
+ }
+
+ public boolean isEmpty() {
+ return consumersRegistry.isEmpty();
+ }
+
+ public Undertow getServer() {
+ return server;
+ }
+
+ public void setServer(Undertow server) {
+ this.server = server;
+ }
+
+ public Map<URI, UndertowConsumer> getConsumersRegistry() {
+ return consumersRegistry;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public SSLContext getSslContext() {
+ return sslContext;
+ }
+
+ public void setSslContext(SSLContext sslContext) {
+ this.sslContext = sslContext;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowUtils.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowUtils.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowUtils.java
new file mode 100644
index 0000000..188de3b
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowUtils.java
@@ -0,0 +1,49 @@
+/**
+ * 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.undertow;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Util class for useful methods used all over the component
+ *
+ */
+public final class UndertowUtils {
+
+ private UndertowUtils() {
+ }
+
+ public static void appendHeader(Map<String, Object> headers, String key, Object value) {
+ if (headers.containsKey(key)) {
+ Object existing = headers.get(key);
+ List<Object> list;
+ if (existing instanceof List) {
+ list = (List<Object>) existing;
+ } else {
+ list = new ArrayList<Object>();
+ list.add(existing);
+ }
+ list.add(value);
+ value = list;
+ }
+
+ headers.put(key, value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/HttpCamelHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/HttpCamelHandler.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/HttpCamelHandler.java
new file mode 100644
index 0000000..3900dd3
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/HttpCamelHandler.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.undertow.handlers;
+
+import java.nio.ByteBuffer;
+
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.Headers;
+import io.undertow.util.HttpString;
+import io.undertow.util.Methods;
+import io.undertow.util.MimeMappings;
+import io.undertow.util.StatusCodes;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.component.undertow.ExchangeHeaders;
+import org.apache.camel.component.undertow.UndertowConsumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Custom handler to process incoming HTTP request and prepare them
+ * to be used in the Camel route.
+ *
+ * This class can be considered part of UndertowConsumer implementation.
+ *
+ */
+public class HttpCamelHandler implements HttpHandler {
+ private static final Logger LOG = LoggerFactory.getLogger(UndertowConsumer.class);
+
+ private UndertowConsumer consumer;
+
+ public HttpCamelHandler(UndertowConsumer consumer) {
+ this.consumer = consumer;
+ }
+
+ public UndertowConsumer getConsumer() {
+ return consumer;
+ }
+
+ @Override
+ public void handleRequest(HttpServerExchange httpExchange) throws Exception {
+ HttpString requestMethod = httpExchange.getRequestMethod();
+
+ if (Methods.OPTIONS.equals(requestMethod)) {
+ String allowedMethods;
+ if (consumer.getEndpoint().getHttpMethodRestrict() != null) {
+ allowedMethods = "OPTIONS" + consumer.getEndpoint().getHttpMethodRestrict();
+ } else {
+ allowedMethods = "GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,CONNECT,PATCH";
+ }
+ //return list of allowed methods in response headers
+ httpExchange.setResponseCode(StatusCodes.OK);
+ httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_TYPE, MimeMappings.DEFAULT_MIME_MAPPINGS.get("txt"));
+ httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_LENGTH, 0);
+ httpExchange.getResponseHeaders().put(Headers.ALLOW, allowedMethods);
+ httpExchange.getResponseSender().close();
+ return;
+ }
+
+ //reject if the method is not allowed
+ if (consumer.getEndpoint().getHttpMethodRestrict() != null
+ && !consumer.getEndpoint().getHttpMethodRestrict().contains(requestMethod.toString())) {
+ httpExchange.setResponseCode(StatusCodes.METHOD_NOT_ALLOWED);
+ httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_TYPE, MimeMappings.DEFAULT_MIME_MAPPINGS.get("txt"));
+ httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_LENGTH, 0);
+ httpExchange.getResponseSender().close();
+ return;
+ }
+
+ //perform blocking operation on exchange
+ if (httpExchange.isInIoThread()) {
+ httpExchange.dispatch(this);
+ return;
+ }
+
+ //create new Exchange
+ //binding is used to extract header and payload(if available)
+ Exchange camelExchange = consumer.getEndpoint().createExchange(httpExchange);
+
+ //Unit of Work to process the Exchange
+ consumer.createUoW(camelExchange);
+ try {
+ consumer.getProcessor().process(camelExchange);
+ } catch (Exception e) {
+ consumer.getExceptionHandler().handleException(e);
+ } finally {
+ consumer.doneUoW(camelExchange);
+ }
+
+ Object body = getResponseBody(httpExchange, camelExchange);
+ TypeConverter tc = consumer.getEndpoint().getCamelContext().getTypeConverter();
+
+ if (body == null) {
+ LOG.trace("No payload to send as reply for exchange: " + camelExchange);
+ httpExchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_TYPE, MimeMappings.DEFAULT_MIME_MAPPINGS.get("txt"));
+ httpExchange.getResponseSender().send("No response available");
+ } else {
+ ByteBuffer bodyAsByteBuffer = tc.convertTo(ByteBuffer.class, body);
+ httpExchange.getResponseSender().send(bodyAsByteBuffer);
+ }
+ httpExchange.getResponseSender().close();
+ }
+
+
+ private Object getResponseBody(HttpServerExchange httpExchange, Exchange camelExchange) {
+ Object result;
+ if (camelExchange.hasOut()) {
+ result = consumer.getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, camelExchange.getOut());
+ } else {
+ result = consumer.getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, camelExchange.getIn());
+ }
+ return result;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/100b2f40/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/NotFoundHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/NotFoundHandler.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/NotFoundHandler.java
new file mode 100644
index 0000000..932380c
--- /dev/null
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/NotFoundHandler.java
@@ -0,0 +1,36 @@
+/**
+ * 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.undertow.handlers;
+
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.Headers;
+
+/**
+ * Custom handler to inform client that no matching path was found
+ *
+ */
+public class NotFoundHandler implements HttpHandler {
+
+ @Override
+ public void handleRequest(HttpServerExchange exchange) throws Exception {
+ exchange.setResponseCode(404);
+ exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
+ exchange.getResponseSender().send("No matching path found");
+ }
+}