Repository: camel
Updated Branches:
  refs/heads/master a2a569630 -> 6e88e7a27


CAMEL-9678 camel-undertow - Keep restarting server when add/remove routes

Refactored camel-undertow consumer to enable hot swapping individual handlers 
which correspond to each consumers without restarting undertow server.


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

Branch: refs/heads/master
Commit: 6e88e7a27bfed8910d736f664281e67236573988
Parents: a2a5696
Author: Tomohisa Igarashi <tm.igara...@gmail.com>
Authored: Wed Oct 26 17:17:13 2016 +0900
Committer: Andrea Cosentino <anco...@gmail.com>
Committed: Wed Oct 26 11:20:55 2016 +0200

----------------------------------------------------------------------
 .../component/undertow/DefaultUndertowHost.java | 100 +++++++++++
 .../component/undertow/UndertowComponent.java   |  98 +++-------
 .../component/undertow/UndertowConsumer.java    | 118 +++++++-----
 .../undertow/UndertowConsumerResolver.java      |  81 ---------
 .../component/undertow/UndertowHostKey.java     |  68 +++++++
 .../component/undertow/UndertowRegistry.java    | 115 ------------
 .../undertow/handlers/CamelMethodHandler.java   |  96 ++++++++++
 .../undertow/handlers/CamelPathHandler.java     |  84 +++++++++
 .../handlers/CamelPathTemplateHandler.java      |  99 ++++++++++
 .../undertow/handlers/CamelRootHandler.java     | 179 +++++++++++++++++++
 .../undertow/handlers/HttpCamelHandler.java     | 135 --------------
 .../UndertowConsumerUnregisterTest.java         |  38 ++++
 .../src/test/resources/log4j2.properties        |   4 +
 13 files changed, 761 insertions(+), 454 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHost.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHost.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHost.java
new file mode 100644
index 0000000..7db4c99
--- /dev/null
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHost.java
@@ -0,0 +1,100 @@
+/**
+ * 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.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import io.undertow.Handlers;
+import io.undertow.Undertow;
+import io.undertow.server.HttpHandler;
+import io.undertow.server.handlers.PathHandler;
+import io.undertow.server.handlers.PathTemplateHandler;
+import io.undertow.util.PathTemplate;
+import org.apache.camel.component.undertow.handlers.CamelRootHandler;
+import org.apache.camel.component.undertow.handlers.NotFoundHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default UndertowHost which manages standalone Undertow server.
+ */
+public class DefaultUndertowHost implements UndertowHost {
+    private static final Logger LOG = 
LoggerFactory.getLogger(DefaultUndertowHost.class);
+
+    private UndertowHostKey key;
+    private CamelRootHandler rootHandler;
+    private Undertow undertow;
+    private String hostString;
+
+    public DefaultUndertowHost(UndertowHostKey key) {
+        this.key = key;
+        rootHandler = new CamelRootHandler(new NotFoundHandler());
+    }
+
+    @Override
+    public void validateEndpointURI(URI httpURI) {
+        // all URIs are good
+    }
+
+    @Override
+    public synchronized void registerHandler(HttpHandlerRegistrationInfo 
registrationInfo, HttpHandler handler) {
+        if (undertow == null) {
+            Undertow.Builder builder = Undertow.builder();
+            if (key.getSslContext() != null) {
+                builder.addHttpsListener(key.getPort(), key.getHost(), 
key.getSslContext());
+            } else {
+                builder.addHttpListener(key.getPort(), key.getHost());
+            }
+
+            undertow = builder.setHandler(rootHandler).build();
+            LOG.info("Starting Undertow server on {}://{}:{}", 
key.getSslContext() != null ? "https" : "http", key.getHost(), key.getPort());
+            undertow.start();
+        }
+
+        String path = registrationInfo.getUri().getPath();
+        String methods = registrationInfo.getMethodRestrict();
+        boolean prefixMatch = registrationInfo.isMatchOnUriPrefix();
+        rootHandler.add(path, methods != null ? methods.split(",") : null, 
prefixMatch, handler);
+    }
+
+    @Override
+    public synchronized void unregisterHandler(HttpHandlerRegistrationInfo 
registrationInfo) {
+        if (undertow == null) {
+            return;
+        }
+
+        String path = registrationInfo.getUri().getPath();
+        String methods = registrationInfo.getMethodRestrict();
+        boolean prefixMatch = registrationInfo.isMatchOnUriPrefix();
+        rootHandler.remove(path, methods != null ? methods.split(",") : null, 
prefixMatch);
+
+        if (rootHandler.isEmpty()) {
+            LOG.info("Stopping Undertow server on {}://{}:{}", 
key.getSslContext() != null ? "https" : "http", key.getHost(), key.getPort());
+            undertow.stop();
+            undertow = null;
+        }
+    }
+
+    public String toString() {
+        if (hostString == null) {
+            hostString = String.format("DefaultUndertowHost[%s://%s:%s]", 
key.getSslContext() != null ? "https" : "http", key.getHost(), key.getPort());
+        }
+        return hostString;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/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
index f2b78c3..d757070 100644
--- 
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
@@ -23,6 +23,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.net.ssl.SSLContext;
 
 import io.undertow.Handlers;
 import io.undertow.Undertow;
@@ -30,15 +33,16 @@ import io.undertow.attribute.ExchangeAttributes;
 import io.undertow.predicate.PathTemplatePredicate;
 import io.undertow.predicate.Predicate;
 import io.undertow.predicate.Predicates;
+import io.undertow.server.HttpHandler;
 import io.undertow.server.handlers.PathHandler;
+import io.undertow.server.handlers.PathTemplateHandler;
 import io.undertow.server.handlers.PredicateHandler;
-
+import io.undertow.util.PathTemplate;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
-import org.apache.camel.component.undertow.handlers.HttpCamelHandler;
 import org.apache.camel.component.undertow.handlers.NotFoundHandler;
 import org.apache.camel.impl.UriEndpointComponent;
 import org.apache.camel.spi.RestApiConsumerFactory;
@@ -63,7 +67,7 @@ public class UndertowComponent extends UriEndpointComponent 
implements RestConsu
     private static final Logger LOG = 
LoggerFactory.getLogger(UndertowEndpoint.class);
 
     private UndertowHttpBinding undertowHttpBinding;
-    private final Map<Integer, UndertowRegistry> serversRegistry = new 
HashMap<Integer, UndertowRegistry>();
+    private Map<UndertowHostKey, UndertowHost> undertowRegistry = new 
ConcurrentHashMap<UndertowHostKey, UndertowHost>();
     private SSLContextParameters sslContextParameters;
 
     public UndertowComponent() {
@@ -275,86 +279,26 @@ public class UndertowComponent extends 
UriEndpointComponent implements RestConsu
     }
 
     public void registerConsumer(UndertowConsumer consumer) {
-        int port = consumer.getEndpoint().getHttpURI().getPort();
-        if (serversRegistry.containsKey(port)) {
-            UndertowRegistry undertowRegistry = serversRegistry.get(port);
-            undertowRegistry.registerConsumer(consumer);
-        } else {
-            // Create a new server to listen on the specified port
-            serversRegistry.put(port, new UndertowRegistry(consumer, port));
+        URI uri = consumer.getEndpoint().getHttpURI();
+        UndertowHostKey key = new UndertowHostKey(uri.getHost(), 
uri.getPort(), consumer.getEndpoint().getSslContext());
+        UndertowHost host = undertowRegistry.get(key);
+        if (host == null) {
+            host = createUndertowHost(key);
+            undertowRegistry.put(key, host);
         }
+        host.validateEndpointURI(uri);
+        host.registerHandler(consumer.getHttpHandlerRegistrationInfo(), 
consumer);
     }
 
     public void unregisterConsumer(UndertowConsumer consumer) {
-        int port = consumer.getEndpoint().getHttpURI().getPort();
-        if (serversRegistry.containsKey(port)) {
-            UndertowRegistry undertowRegistry = serversRegistry.get(port);
-            undertowRegistry.unregisterConsumer(consumer);
-
-            if (undertowRegistry.isEmpty()) {
-                // If there are no consumers left, we can shut down the server
-                Undertow server = undertowRegistry.getServer();
-                if (server != null) {
-                    server.stop();
-                }
-                serversRegistry.remove(port);
-            } else {
-                // Else, rebuild the server
-                startServer(consumer);
-            }
-        }
+        URI uri = consumer.getEndpoint().getHttpURI();
+        UndertowHostKey key = new UndertowHostKey(uri.getHost(), 
uri.getPort(), consumer.getEndpoint().getSslContext());
+        UndertowHost host = undertowRegistry.get(key);
+        host.unregisterHandler(consumer.getHttpHandlerRegistrationInfo());
     }
 
-    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);
-    }
-
-    protected Undertow rebuildServer(UndertowRegistry registry) {
-        Undertow.Builder result = Undertow.builder();
-        if (registry.getSslContext() != null) {
-            result = result.addHttpsListener(registry.getPort(), 
registry.getHost(), registry.getSslContext());
-        } else {
-            result = result.addHttpListener(registry.getPort(), 
registry.getHost());
-        }
-
-        PathHandler pathHandler = Handlers.path(new NotFoundHandler());
-        HttpCamelHandler handler = new HttpCamelHandler();
-        List<Predicate> predicates = new ArrayList<Predicate>();
-        for (String key : registry.getConsumersRegistry().keySet()) {
-            UndertowConsumer consumer = 
registry.getConsumersRegistry().get(key);
-            UndertowEndpoint endpoint = consumer.getEndpoint();
-            String path = endpoint.getHttpURI().getPath();
-
-            // Assume URI contains REST variables
-            if (path.contains("{")) {
-                predicates.add(new PathTemplatePredicate(path, 
ExchangeAttributes.relativePath()));
-            } else {
-                if (endpoint.getMatchOnUriPrefix()) {
-                    predicates.add(Predicates.prefix(path));
-                } else {
-                    predicates.add(Predicates.path(path));
-                }
-            }
-
-            handler.connectConsumer(consumer);
-
-            LOG.debug("Rebuild for pathHandler: {}", path);
-        }
-
-        Predicate combinedPathPredicate = Predicates.or(predicates.toArray(new 
Predicate[0]));
-        pathHandler.addPrefixPath("/", new 
PredicateHandler(combinedPathPredicate, handler, new NotFoundHandler()));
-
-        result = result.setHandler(pathHandler);
-        return result.build();
+    protected UndertowHost createUndertowHost(UndertowHostKey key) {
+        return new DefaultUndertowHost(key);
     }
 
     public UndertowHttpBinding getUndertowHttpBinding() {

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/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
index 49efe0a..6a80892 100644
--- 
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
@@ -16,24 +16,30 @@
  */
 package org.apache.camel.component.undertow;
 
-import java.net.URI;
+import java.io.IOException;
+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.Processor;
-import org.apache.camel.component.undertow.handlers.HttpCamelHandler;
+import org.apache.camel.TypeConverter;
 import org.apache.camel.impl.DefaultConsumer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The Undertow consumer.
+ * The Undertow consumer which is also an Undertow HttpHandler implementation 
to handle incoming request.
  */
-public class UndertowConsumer extends DefaultConsumer {
+public class UndertowConsumer extends DefaultConsumer implements HttpHandler {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(UndertowConsumer.class);
 
-    private UndertowHost undertowHost;
     private HttpHandlerRegistrationInfo registrationInfo;
 
     public UndertowConsumer(UndertowEndpoint endpoint, Processor processor) {
@@ -45,46 +51,19 @@ public class UndertowConsumer extends DefaultConsumer {
         return (UndertowEndpoint) super.getEndpoint();
     }
 
-    public UndertowHost getUndertowHost() {
-        if (undertowHost == null) {
-            undertowHost = createUndertowHost();
-        }
-        return undertowHost;
-    }
-
-    protected UndertowHost createUndertowHost() {
-        return new DefaultUndertowHost();
-    }
-
     @Override
     protected void doStart() throws Exception {
         super.doStart();
-        LOG.debug("Undertow consumer is starting");
         getEndpoint().getComponent().registerConsumer(this);
-
-        UndertowHost host = getUndertowHost();
-
-        HttpCamelHandler httpCamelHandler = new HttpCamelHandler();
-        httpCamelHandler.connectConsumer(this);
-
-        HttpHandlerRegistrationInfo registrationInfo = 
getHttpHandlerRegistrationInfo();
-
-        host.validateEndpointURI(registrationInfo.getUri());
-        host.registerHandler(registrationInfo, httpCamelHandler);
     }
 
     @Override
-    protected void doStop() {
-        LOG.debug("Undertow consumer is stopping");
-
-        HttpHandlerRegistrationInfo registrationInfo = 
getHttpHandlerRegistrationInfo();
-        UndertowHost host = getUndertowHost();
-        host.unregisterHandler(registrationInfo);
-
+    protected void doStop() throws Exception {
+        super.doStop();
         getEndpoint().getComponent().unregisterConsumer(this);
     }
 
-    private HttpHandlerRegistrationInfo getHttpHandlerRegistrationInfo() {
+    public HttpHandlerRegistrationInfo getHttpHandlerRegistrationInfo() {
         if (registrationInfo == null) {
             UndertowEndpoint endpoint = getEndpoint();
 
@@ -96,21 +75,68 @@ public class UndertowConsumer extends DefaultConsumer {
         return registrationInfo;
     }
 
-    class DefaultUndertowHost implements UndertowHost {
+    @Override
+    public void handleRequest(HttpServerExchange httpExchange) throws 
Exception {
+        HttpString requestMethod = httpExchange.getRequestMethod();
+
+        if (Methods.OPTIONS.equals(requestMethod) && 
!getEndpoint().isOptionsEnabled()) {
+            String allowedMethods;
+            if (getEndpoint().getHttpMethodRestrict() != null) {
+                allowedMethods = "OPTIONS," + 
getEndpoint().getHttpMethodRestrict();
+            } else {
+                allowedMethods = 
"GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,CONNECT,PATCH";
+            }
+            //return list of allowed methods in response headers
+            httpExchange.setStatusCode(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;
+        }
 
-        @Override
-        public void validateEndpointURI(URI httpURI) {
-            // all URIs are good
+        //perform blocking operation on exchange
+        if (httpExchange.isInIoThread()) {
+            httpExchange.dispatch(this);
+            return;
         }
 
-        @Override
-        public void registerHandler(HttpHandlerRegistrationInfo 
registrationInfo, HttpHandler handler) {
-            getEndpoint().getComponent().startServer(UndertowConsumer.this);
+        //create new Exchange
+        //binding is used to extract header and payload(if available)
+        Exchange camelExchange = getEndpoint().createExchange(httpExchange);
+
+        //Unit of Work to process the Exchange
+        createUoW(camelExchange);
+        try {
+            getProcessor().process(camelExchange);
+        } catch (Exception e) {
+            getExceptionHandler().handleException(e);
+        } finally {
+            doneUoW(camelExchange);
         }
 
-        @Override
-        public void unregisterHandler(HttpHandlerRegistrationInfo 
registrationInfo) {
-            // do nothing
+        Object body = getResponseBody(httpExchange, camelExchange);
+        TypeConverter tc = 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) throws IOException {
+        Object result;
+        if (camelExchange.hasOut()) {
+            result = 
getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, 
camelExchange.getOut());
+        } else {
+            result = 
getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, 
camelExchange.getIn());
+        }
+        return result;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumerResolver.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumerResolver.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumerResolver.java
deleted file mode 100644
index 9a56c2a..0000000
--- 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumerResolver.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * 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;
-
-import io.undertow.server.HttpServerExchange;
-import io.undertow.util.HttpString;
-import org.apache.camel.support.RestConsumerContextPathMatcher;
-
-public class UndertowConsumerResolver {
-
-    public UndertowConsumer resolve(HttpServerExchange exchange, Map<String, 
UndertowConsumer> consumers) {
-        UndertowConsumer answer = null;
-
-        String path = exchange.getRequestPath();
-        if (path == null) {
-            return null;
-        }
-        HttpString method = exchange.getRequestMethod();
-        if (method == null) {
-            return null;
-        }
-
-        List<RestConsumerContextPathMatcher.ConsumerPath> paths = new 
ArrayList<RestConsumerContextPathMatcher.ConsumerPath>();
-        for (final Map.Entry<String, UndertowConsumer> entry : 
consumers.entrySet()) {
-            paths.add(new 
RestConsumerContextPathMatcher.ConsumerPath<UndertowConsumer>() {
-                @Override
-                public String getRestrictMethod() {
-                    return 
entry.getValue().getEndpoint().getHttpMethodRestrict();
-                }
-
-                @Override
-                public String getConsumerPath() {
-                    return 
entry.getValue().getEndpoint().getHttpURI().getPath();
-                }
-
-                @Override
-                public UndertowConsumer getConsumer() {
-                    return entry.getValue();
-                }
-            });
-        }
-
-        RestConsumerContextPathMatcher.ConsumerPath<UndertowConsumer> best = 
RestConsumerContextPathMatcher.matchBestPath(method.toString(), path, paths);
-        if (best != null) {
-            answer = best.getConsumer();
-        }
-
-        if (answer == null) {
-            for (String key : consumers.keySet()) {
-                String consumerPath = 
consumers.get(key).getEndpoint().getHttpURI().getPath();
-                UndertowConsumer consumer = consumers.get(key);
-                boolean matchOnUriPrefix = 
consumer.getEndpoint().getMatchOnUriPrefix();
-                if (RestConsumerContextPathMatcher.matchPath(path, 
consumerPath, matchOnUriPrefix)) {
-                    answer = consumers.get(key);
-                    break;
-                }
-            }
-        }
-
-        return answer;
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHostKey.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHostKey.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHostKey.java
new file mode 100644
index 0000000..be64d09
--- /dev/null
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowHostKey.java
@@ -0,0 +1,68 @@
+/**
+ * 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 javax.net.ssl.SSLContext;
+
+/**
+ * The key to identify an Undertow host.
+ */
+public final class UndertowHostKey {
+    private final String host;
+    private final int port;
+    private final SSLContext sslContext;
+
+    public UndertowHostKey(String host, int port, SSLContext ssl) {
+        this.host = host;
+        this.port = port;
+        this.sslContext = ssl;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public SSLContext getSslContext() {
+        return sslContext;
+    }
+
+    @Override
+    public boolean equals(Object target) {
+        if (!(target instanceof UndertowHostKey)) {
+            return false;
+        }
+        UndertowHostKey targetKey = (UndertowHostKey)target;
+        boolean answer = true;
+        if (this.sslContext != null || targetKey.sslContext != null) {
+            answer = this.sslContext != null && targetKey.sslContext != null
+                && this.sslContext.equals(targetKey.sslContext);
+        }
+        return answer && this.host != null && targetKey.host != null
+            && this.host.equals(targetKey.host) && this.port == targetKey.port;
+    }
+
+    @Override
+    public int hashCode() {
+        int answer = host.hashCode();
+        answer = answer * 31 + Integer.hashCode(port);
+        return answer * 31 + (sslContext != null ? sslContext.hashCode() : 0);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/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
deleted file mode 100644
index 6d7e434..0000000
--- 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowRegistry.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * 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.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);
-
-    private int port;
-    private SSLContext sslContext;
-    private String host;
-    private Undertow server;
-    private Map<String, UndertowConsumer> consumersRegistry = new 
HashMap<String, 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) {
-        UndertowEndpoint endpoint = consumer.getEndpoint();
-        URI httpUri = endpoint.getHttpURI();
-        if (host != null && !host.equals(httpUri.getHost())) {
-            throw new IllegalArgumentException("Cannot register 
UndertowConsumer on different host and same port: {}" + host + " " + 
httpUri.getHost());
-        } else {
-            host = httpUri.getHost();
-        }
-        LOG.info("Adding consumer to consumerRegistry: {}", httpUri);
-        consumersRegistry.put(endpoint.getEndpointUri(), consumer);
-        if (sslContext != null && endpoint.getSslContext() != null) {
-            throw new IllegalArgumentException("Cannot register 
UndertowConsumer with different SSL config");
-        }
-
-    }
-
-    public void unregisterConsumer(UndertowConsumer consumer) {
-        UndertowEndpoint endpoint = consumer.getEndpoint();
-        String endpointUri = endpoint.getEndpointUri();
-        if (consumersRegistry.containsKey(endpointUri)) {
-            consumersRegistry.remove(endpointUri);
-        } else {
-            LOG.debug("Cannot unregister consumer {} as it was not 
registered", consumer);
-        }
-    }
-
-    public boolean isEmpty() {
-        return consumersRegistry.isEmpty();
-    }
-
-    public Undertow getServer() {
-        return server;
-    }
-
-    public void setServer(Undertow server) {
-        this.server = server;
-    }
-
-    public Map<String, 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/6e88e7a2/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelMethodHandler.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelMethodHandler.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelMethodHandler.java
new file mode 100644
index 0000000..26584b5
--- /dev/null
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelMethodHandler.java
@@ -0,0 +1,96 @@
+/**
+ * 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.util.HashMap;
+import java.util.Map;
+
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.MimeMappings;
+import io.undertow.util.StatusCodes;
+import org.apache.camel.component.undertow.ExchangeHeaders;
+
+/**
+ * A HttpHandler build a mapping between HTTP methods and handlers and 
dispatch requests along the map.
+ */
+public class CamelMethodHandler implements HttpHandler {
+    private Map<String, HttpHandler> methodMap = new HashMap<String, 
HttpHandler>();
+    private HttpHandler defaultHandler;
+    private String handlerString;
+
+    @Override
+    public void handleRequest(HttpServerExchange exchange) throws Exception {
+        HttpHandler handler = 
methodMap.get(exchange.getRequestMethod().toString());
+        if (handler != null) {
+            handler.handleRequest(exchange);
+        } else if (defaultHandler != null) {
+            defaultHandler.handleRequest(exchange);
+        } else {
+            exchange.setStatusCode(StatusCodes.METHOD_NOT_ALLOWED);
+            exchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_TYPE, 
MimeMappings.DEFAULT_MIME_MAPPINGS.get("txt"));
+            exchange.getResponseHeaders().put(ExchangeHeaders.CONTENT_LENGTH, 
0);
+            exchange.endExchange();
+        }
+    }
+
+    public synchronized void add(String[] methods, HttpHandler handler) {
+        Map<String, HttpHandler> adding = new HashMap<String, HttpHandler>();
+        for (String method : methods) {
+            HttpHandler existing = methodMap.get(method);
+            if (methodMap.get(method) != null) {
+                throw new IllegalArgumentException(String.format(
+                    "Duplicate handler for a method '%s': '%s', '%s'", method, 
existing, handler));
+            }
+            adding.put(method, handler);
+        }
+        methodMap.putAll(adding);
+        handlerString = null;
+    }
+
+    public synchronized void remove(String[] methods) {
+        for (String method : methods) {
+            methodMap.remove(method);
+        }
+        handlerString = null;
+    }
+
+    public synchronized void addDefault(HttpHandler handler) {
+        if (defaultHandler != null) {
+            throw new IllegalArgumentException(String.format(
+                "Duplicate default handler: '%s', '%s'", defaultHandler, 
handler));
+        }
+        defaultHandler = handler;
+        handlerString = null;
+    }
+
+    public synchronized void removeDefault() {
+        defaultHandler = null;
+        handlerString = null;
+    }
+
+    public boolean isEmpty() {
+        return defaultHandler == null && methodMap.isEmpty();
+    }
+
+    public String toString() {
+        if (handlerString == null) {
+            handlerString = "CamelMethodHandler[default=" + defaultHandler + 
", " + methodMap + "]";
+        }
+        return handlerString;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathHandler.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathHandler.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathHandler.java
new file mode 100644
index 0000000..f9284c2
--- /dev/null
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathHandler.java
@@ -0,0 +1,84 @@
+/**
+ * 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.util.HashMap;
+import java.util.Map;
+
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.PathHandler;
+
+/**
+ * Extended PathHandler to monitor add/remove handlers.
+ */
+public class CamelPathHandler extends PathHandler {
+    private Map<String, HttpHandler> handlers = new HashMap<String, 
HttpHandler>();
+    private String handlerString;
+
+    public CamelPathHandler(HttpHandler defaultHandler) {
+        super(defaultHandler);
+    }
+
+    @Override
+    public synchronized PathHandler addPrefixPath(final String path, final 
HttpHandler handler) {
+        super.addPrefixPath(path, handler);
+        handlers.put(path, handler);
+        handlerString = null;
+        return this;
+    }
+
+    @Override
+    public synchronized PathHandler addExactPath(final String path, final 
HttpHandler handler) {
+        super.addExactPath(path, handler);
+        handlers.put(path, handler);
+        handlerString = null;
+        return this;
+    }
+
+    @Override
+    public synchronized PathHandler removePrefixPath(final String path) {
+        super.removePrefixPath(path);
+        handlers.remove(path);
+        handlerString = null;
+        return this;
+    }
+
+    @Override
+    public synchronized PathHandler removeExactPath(final String path) {
+        super.removeExactPath(path);
+        handlers.remove(path);
+        handlerString = null;
+        return this;
+    }
+
+    public HttpHandler getHandler(String path) {
+        return handlers.get(path);
+    }
+
+    public boolean isEmpty() {
+        return handlers.isEmpty();
+    }
+
+    public String toString() {
+        if (handlerString == null) {
+            handlerString = "CamelPathHandler[" + handlers + "]";
+        }
+        return handlerString;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathTemplateHandler.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathTemplateHandler.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathTemplateHandler.java
new file mode 100644
index 0000000..ff086da
--- /dev/null
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelPathTemplateHandler.java
@@ -0,0 +1,99 @@
+/**
+ * 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.util.HashMap;
+import java.util.Map;
+
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.PathTemplateHandler;
+
+/**
+ * Extended PathTemplateHandler to monitor add/remove handlers. Also this 
enables hot swapping a default handler.
+ */
+public class CamelPathTemplateHandler implements HttpHandler {
+    private Map<String, CamelMethodHandler> handlers = new HashMap<String, 
CamelMethodHandler>();
+    private Wrapper defaultHandlerWrapper = new Wrapper();
+    private PathTemplateHandler delegate;
+    private String handlerString;
+
+    public CamelPathTemplateHandler(CamelMethodHandler defaultHandler) {
+        defaultHandlerWrapper.set(defaultHandler);
+        delegate = new PathTemplateHandler(defaultHandlerWrapper);
+    }
+
+    @Override
+    public void handleRequest(HttpServerExchange exchange) throws Exception {
+        delegate.handleRequest(exchange);
+    }
+
+    public synchronized CamelPathTemplateHandler add(final String uriTemplate, 
final CamelMethodHandler handler) {
+        delegate.add(uriTemplate, handler);
+        handlers.put(uriTemplate, handler);
+        handlerString = null;
+        return this;
+    }
+
+    public synchronized CamelPathTemplateHandler remove(final String 
uriTemplate) {
+        delegate.remove(uriTemplate);
+        handlers.remove(uriTemplate);
+        handlerString = null;
+        return this;
+    }
+
+    public CamelMethodHandler get(final String uriTemplate) {
+        return handlers.get(uriTemplate);
+    }
+
+    public boolean isEmpty() {
+        return handlers.isEmpty();
+    }
+
+    public CamelMethodHandler getDefault() {
+        return this.defaultHandlerWrapper.get();
+    }
+
+    public synchronized void setDefault(final CamelMethodHandler 
defaultHandler) {
+        this.defaultHandlerWrapper.set(defaultHandler);
+        handlerString = null;
+    }
+
+    public String toString() {
+        if (handlerString == null) {
+            handlerString = "CamelPathTemplateHandler[default=" + 
defaultHandlerWrapper.get() + ", " + handlers + "]";
+        }
+        return handlerString;
+    }
+
+    class Wrapper implements HttpHandler {
+        private CamelMethodHandler handler;
+
+        public void set(CamelMethodHandler handler) {
+            this.handler = handler;
+        }
+
+        public CamelMethodHandler get() {
+            return this.handler;
+        }
+
+        @Override
+        public void handleRequest(HttpServerExchange exchange) throws 
Exception {
+            handler.handleRequest(exchange);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelRootHandler.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelRootHandler.java
 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelRootHandler.java
new file mode 100644
index 0000000..a0a8ae3
--- /dev/null
+++ 
b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/CamelRootHandler.java
@@ -0,0 +1,179 @@
+/**
+ * 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.util.HashMap;
+import java.util.Map;
+
+import io.undertow.Handlers;
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.PathHandler;
+import io.undertow.server.handlers.PathTemplateHandler;
+import io.undertow.util.Headers;
+import io.undertow.util.PathTemplate;
+
+/**
+ * Custom root handler to enable hot swapping individual handlers assigned for 
each path template and/or HTTP method.
+ */
+public class CamelRootHandler implements HttpHandler {
+    private CamelPathHandler pathHandler;
+
+    public CamelRootHandler(HttpHandler defaultHandler) {
+        pathHandler = new CamelPathHandler(defaultHandler);
+    }
+
+    public void handleRequest(HttpServerExchange exchange) throws Exception {
+        pathHandler.handleRequest(exchange);
+    }
+
+    public synchronized void add(String path, String[] methods, boolean 
prefixMatch, HttpHandler handler) {
+        String basePath = getBasePath(path);
+        HttpHandler basePathHandler = pathHandler.getHandler(basePath);
+
+        CamelMethodHandler targetHandler;
+        if (path.contains("{")) {
+            // Adding a handler for the template path
+            String relativePath = path.substring(basePath.length());
+            if (basePathHandler instanceof CamelPathTemplateHandler) {
+                CamelPathTemplateHandler templateHandler = 
(CamelPathTemplateHandler)basePathHandler;
+                targetHandler = templateHandler.get(relativePath);
+                if (targetHandler == null) {
+                    targetHandler = new CamelMethodHandler();
+                    templateHandler.add(relativePath, targetHandler);
+                }
+            } else {
+                CamelPathTemplateHandler templateHandler;
+                if (basePathHandler instanceof CamelMethodHandler) {
+                    // A static path handler is already set for the base path. 
Use it as a default handler
+                    templateHandler = new 
CamelPathTemplateHandler((CamelMethodHandler)basePathHandler);
+                } else if (basePathHandler == null) {
+                    templateHandler = new CamelPathTemplateHandler(new 
CamelMethodHandler());
+                } else {
+                    throw new 
IllegalArgumentException(String.format("Unsupported handler '%s' was found", 
basePathHandler));
+                }
+                targetHandler = new CamelMethodHandler();
+                templateHandler.add(relativePath, targetHandler);
+                pathHandler.addPrefixPath(basePath, templateHandler);
+            }
+
+        } else {
+            // Adding a handler for the static path
+            if (basePathHandler instanceof CamelPathTemplateHandler) {
+                CamelPathTemplateHandler templateHandler = 
(CamelPathTemplateHandler)basePathHandler;
+                if (prefixMatch) {
+                    targetHandler = templateHandler.getDefault();
+                } else {
+                    throw new 
IllegalArgumentException(String.format("Duplicate handlers on a path '%s'", 
path));
+                }
+            } else {
+                if (basePathHandler instanceof CamelMethodHandler) {
+                    targetHandler = (CamelMethodHandler)basePathHandler;
+                } else if (basePathHandler == null) {
+                    targetHandler = new CamelMethodHandler();
+                    if (prefixMatch) {
+                        pathHandler.addPrefixPath(basePath, targetHandler);
+                    } else {
+                        pathHandler.addExactPath(basePath, targetHandler);
+                    }
+                } else {
+                    throw new 
IllegalArgumentException(String.format("Unsupported handler '%s' was found", 
basePathHandler));
+                }
+            }
+        }
+
+        if (methods != null && methods.length != 0) {
+            targetHandler.add(methods, handler);
+        } else {
+            targetHandler.addDefault(handler);
+        }
+    }
+
+    public synchronized void remove(String path, String[] methods, boolean 
prefixMatch) {
+        String basePath = getBasePath(path);
+        HttpHandler basePathHandler = pathHandler.getHandler(basePath);
+        if (basePathHandler == null) {
+            return;
+        }
+
+        if (path.contains("{")) {
+            // Removing a handler for the template path
+            String relativePath = path.substring(basePath.length());
+            CamelPathTemplateHandler templateHandler = 
(CamelPathTemplateHandler)basePathHandler;
+            CamelMethodHandler targetHandler = 
templateHandler.get(relativePath);
+            if (methods != null && methods.length != 0) {
+                targetHandler.remove(methods);
+            } else {
+                targetHandler.removeDefault();
+            }
+            if (targetHandler.isEmpty()) {
+                templateHandler.remove(relativePath);
+                if (templateHandler.isEmpty()) {
+                    pathHandler.removePrefixPath(basePath);
+                }
+            }
+
+        } else {
+            // Removing a handler for the static path
+            if (basePathHandler instanceof CamelPathTemplateHandler) {
+                String relativePath = path.substring(basePath.length());
+                CamelPathTemplateHandler templateHandler = 
(CamelPathTemplateHandler)basePathHandler;
+                CamelMethodHandler targetHandler = 
templateHandler.getDefault();
+                if (methods != null && methods.length != 0) {
+                    targetHandler.remove(methods);
+                } else {
+                    targetHandler.removeDefault();
+                }
+                if (targetHandler.isEmpty()) {
+                    templateHandler.remove(relativePath);
+                    if (templateHandler.isEmpty()) {
+                        pathHandler.removePrefixPath(basePath);
+                    }
+                }
+            } else {
+                CamelMethodHandler targetHandler = 
(CamelMethodHandler)basePathHandler;
+                if (methods != null && methods.length != 0) {
+                    targetHandler.remove(methods);
+                } else {
+                    targetHandler.removeDefault();
+                }
+                if (targetHandler.isEmpty()) {
+                    if (prefixMatch) {
+                        pathHandler.removePrefixPath(basePath);
+                    } else {
+                        pathHandler.removeExactPath(basePath);
+                    }
+                }
+            }
+        }
+    }
+
+    public synchronized boolean isEmpty() {
+        return pathHandler.isEmpty();
+    }
+
+    public String toString() {
+        return pathHandler.toString();
+    }
+
+    private String getBasePath(String path) {
+        if (path.contains("{")) {
+            return PathTemplate.create(path).getBase();
+        }
+        return path;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/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
deleted file mode 100644
index d9778c5..0000000
--- 
a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/handlers/HttpCamelHandler.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * 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.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-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.apache.camel.component.undertow.UndertowConsumerResolver;
-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(HttpCamelHandler.class);
-    private UndertowConsumerResolver resolver = new UndertowConsumerResolver();
-    private ConcurrentMap<String, UndertowConsumer> consumers = new 
ConcurrentHashMap<String, UndertowConsumer>();
-
-    @Override
-    public void handleRequest(HttpServerExchange httpExchange) throws 
Exception {
-        UndertowConsumer consumer = resolver.resolve(httpExchange, consumers);
-
-        if (consumer == null) {
-            LOG.debug("Unable to resolve consumer matching path {}", 
httpExchange.getRequestPath());
-            new NotFoundHandler().handleRequest(httpExchange);
-            return;
-        }
-
-        HttpString requestMethod = httpExchange.getRequestMethod();
-
-        if (Methods.OPTIONS.equals(requestMethod) && 
!consumer.getEndpoint().isOptionsEnabled()) {
-            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.setStatusCode(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.setStatusCode(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, consumer);
-        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, UndertowConsumer consumer) throws IOException {
-        Object result;
-        if (camelExchange.hasOut()) {
-            result = 
consumer.getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, 
camelExchange.getOut());
-        } else {
-            result = 
consumer.getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, 
camelExchange.getIn());
-        }
-        return result;
-    }
-
-    public void connectConsumer(UndertowConsumer consumer) {
-        consumers.put(consumer.getEndpoint().getEndpointUri(), consumer);
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java
 
b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java
index 1d6c0a2..ad06451 100644
--- 
a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java
+++ 
b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java
@@ -19,7 +19,11 @@ package org.apache.camel.component.undertow;
 import java.net.ConnectException;
 
 import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class UndertowConsumerUnregisterTest extends BaseUndertowTest {
@@ -42,6 +46,40 @@ public class UndertowConsumerUnregisterTest extends 
BaseUndertowTest {
         }
     }
 
+    @Test
+    public void testUnregisterOneOfUndertowConsumers() throws Exception {
+        MockEndpoint mockFoo = getMockEndpoint("mock:foo");
+        mockFoo.expectedBodiesReceived("test");
+        MockEndpoint mockBar = getMockEndpoint("mock:bar");
+        mockBar.expectedBodiesReceived("test", "test");
+
+        Processor sender = new Processor() {
+            public void process(Exchange exchange) {
+                exchange.getIn().setBody("test");
+            }
+        };
+        Exchange ret = 
template.request("undertow:http://localhost:{{port}}/foo";, sender);
+        Assert.assertEquals(200, 
ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+        Assert.assertEquals("test", ret.getOut().getBody(String.class));
+        ret = template.request("undertow:http://localhost:{{port}}/bar";, 
sender);
+        Assert.assertEquals(200, 
ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+        Assert.assertEquals("test", ret.getOut().getBody(String.class));
+
+        UndertowComponent component = context.getComponent("undertow", 
UndertowComponent.class);
+        UndertowConsumer consumerFoo = (UndertowConsumer) 
context.getRoute("route-foo").getConsumer();
+        component.unregisterConsumer(consumerFoo);
+        
+        ret = template.request("undertow:http://localhost:{{port}}/foo";, 
sender);
+        Assert.assertEquals(404, 
ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+        Assert.assertEquals("No matching path found", 
ret.getOut().getBody(String.class));
+        ret = template.request("undertow:http://localhost:{{port}}/bar";, 
sender);
+        Assert.assertEquals(200, 
ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+        Assert.assertEquals("test", ret.getOut().getBody(String.class));
+
+        mockFoo.assertIsSatisfied();
+        mockBar.assertIsSatisfied();
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {

http://git-wip-us.apache.org/repos/asf/camel/blob/6e88e7a2/components/camel-undertow/src/test/resources/log4j2.properties
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/test/resources/log4j2.properties 
b/components/camel-undertow/src/test/resources/log4j2.properties
index d969033..bfd5f67 100644
--- a/components/camel-undertow/src/test/resources/log4j2.properties
+++ b/components/camel-undertow/src/test/resources/log4j2.properties
@@ -26,3 +26,7 @@ appender.out.layout.type = PatternLayout
 appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
 rootLogger.level = INFO
 rootLogger.appenderRef.file.ref = file
+
+loggers=camel-undertow
+logger.camel-undertow.name=org.apache.camel.component.undertow
+logger.camel-undertow.level=DEBUG

Reply via email to