Return-Path: X-Original-To: apmail-camel-commits-archive@www.apache.org Delivered-To: apmail-camel-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 96D72C2CB for ; Tue, 18 Jun 2013 11:03:09 +0000 (UTC) Received: (qmail 21415 invoked by uid 500); 18 Jun 2013 11:03:07 -0000 Delivered-To: apmail-camel-commits-archive@camel.apache.org Received: (qmail 21346 invoked by uid 500); 18 Jun 2013 11:02:55 -0000 Mailing-List: contact commits-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@camel.apache.org Delivered-To: mailing list commits@camel.apache.org Received: (qmail 21327 invoked by uid 99); 18 Jun 2013 11:02:54 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Jun 2013 11:02:54 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id A4CC88A6EDC; Tue, 18 Jun 2013 11:02:54 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: davsclaus@apache.org To: commits@camel.apache.org Date: Tue, 18 Jun 2013 11:02:56 -0000 Message-Id: <215aced3c4214a84bccb9ddb78495ce7@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [3/3] git commit: CAMEL-6327: More work on new camel-netty-http component. CAMEL-6327: More work on new camel-netty-http component. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/cf1273af Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/cf1273af Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/cf1273af Branch: refs/heads/master Commit: cf1273af032e28b187a99a9f525fc1db7eff461c Parents: aac9428 Author: Claus Ibsen Authored: Tue Jun 18 13:02:43 2013 +0200 Committer: Claus Ibsen Committed: Tue Jun 18 13:02:43 2013 +0200 ---------------------------------------------------------------------- .../netty/http/ContextPathMatcher.java | 36 ++++++++++ .../netty/http/DefaultContextPathMatcher.java | 72 ++++++++++++++++++++ .../netty/http/HttpServerBootstrapFactory.java | 3 +- .../netty/http/NettyHttpComponent.java | 1 - .../netty/http/NettyHttpConfiguration.java | 9 +++ .../HttpServerMultiplexChannelHandler.java | 22 ++++-- .../NettyHttpTwoRoutesMatchOnUriPrefixTest.java | 68 ++++++++++++++++++ .../camel/component/netty/NettyConsumer.java | 18 ++--- 8 files changed, 210 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ContextPathMatcher.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ContextPathMatcher.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ContextPathMatcher.java new file mode 100644 index 0000000..030fb9f --- /dev/null +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/ContextPathMatcher.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.netty.http; + +/** + * A matcher used for selecting the correct {@link org.apache.camel.component.netty.http.handlers.HttpServerChannelHandler} + * to handle an incoming {@link org.jboss.netty.handler.codec.http.HttpRequest} when you use multiple routes on the same + * port. + *

+ * As when we do that, we need to multiplex and select the correct consumer route to process the HTTP request. + * To do that we need to match on the incoming HTTP request context-path from the request. + */ +public interface ContextPathMatcher { + + /** + * Whether the target context-path matches. + * + * @param target the context-path from the incoming HTTP request + * @return true to match, false if not. + */ + boolean matches(String target); +} http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultContextPathMatcher.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultContextPathMatcher.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultContextPathMatcher.java new file mode 100644 index 0000000..55bfb58 --- /dev/null +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/DefaultContextPathMatcher.java @@ -0,0 +1,72 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.netty.http; + +import java.util.Locale; + +/** + * A default {@link ContextPathMatcher} which supports the matchOnUriPrefix option. + */ +public class DefaultContextPathMatcher implements ContextPathMatcher { + + private final String path; + private final boolean matchOnUriPrefix; + + public DefaultContextPathMatcher(String path, boolean matchOnUriPrefix) { + this.path = path.toLowerCase(Locale.US); + this.matchOnUriPrefix = matchOnUriPrefix; + } + + public boolean matches(String target) { + target = target.toLowerCase(Locale.US); + if (!matchOnUriPrefix) { + // exact match + return target.equals(path); + } else { + // match on prefix, then we just need to match the start of the context-path + return target.startsWith(path); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DefaultContextPathMatcher that = (DefaultContextPathMatcher) o; + + if (matchOnUriPrefix != that.matchOnUriPrefix) { + return false; + } + if (!path.equals(that.path)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = path.hashCode(); + result = 31 * result + (matchOnUriPrefix ? 1 : 0); + return result; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerBootstrapFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerBootstrapFactory.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerBootstrapFactory.java index d004d96..223ccdb 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerBootstrapFactory.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerBootstrapFactory.java @@ -73,8 +73,7 @@ public class HttpServerBootstrapFactory extends SingleTCPNettyServerBootstrapFac LOG.debug("BootstrapFactory on port {} is stopping", port); super.stop(); } else { - LOG.debug("BootstrapFactory on port {} has {} active consumers, so cannot stop {} yet.", - new Object[]{port, consumers, HttpServerBootstrapFactory.class.getName()}); + LOG.debug("BootstrapFactory on port {} has {} registered consumers, so cannot stop yet.", port, consumers); } } http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java index 8dfe774..6d8183b 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java @@ -37,7 +37,6 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt // TODO: support on consumer // - validate routes on same port cannot have different SSL etc // - bridgeEndpoint - // - matchOnUriPrefix // - urlrewrite private final Map multiplexChannelHandlers = new HashMap(); http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpConfiguration.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpConfiguration.java index a89ef96..cc71f9f 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpConfiguration.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpConfiguration.java @@ -34,6 +34,7 @@ public class NettyHttpConfiguration extends NettyConfiguration { private boolean compression; private boolean throwExceptionOnFailure = true; private boolean transferException; + private boolean matchOnUriPrefix; private String path; public NettyHttpConfiguration() { @@ -108,6 +109,14 @@ public class NettyHttpConfiguration extends NettyConfiguration { this.mapHeaders = mapHeaders; } + public boolean isMatchOnUriPrefix() { + return matchOnUriPrefix; + } + + public void setMatchOnUriPrefix(boolean matchOnUriPrefix) { + this.matchOnUriPrefix = matchOnUriPrefix; + } + public String getPath() { return path; } http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerMultiplexChannelHandler.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerMultiplexChannelHandler.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerMultiplexChannelHandler.java index 3760d2a..e00faf8 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerMultiplexChannelHandler.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerMultiplexChannelHandler.java @@ -16,9 +16,12 @@ */ package org.apache.camel.component.netty.http.handlers; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.apache.camel.component.netty.http.ContextPathMatcher; +import org.apache.camel.component.netty.http.DefaultContextPathMatcher; import org.apache.camel.component.netty.http.NettyHttpConsumer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; @@ -30,7 +33,6 @@ import org.jboss.netty.handler.codec.http.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.SERVICE_UNAVAILABLE; import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1; @@ -43,7 +45,7 @@ public class HttpServerMultiplexChannelHandler extends SimpleChannelUpstreamHand // use NettyHttpConsumer as logger to make it easier to read the logs as this is part of the consumer private static final transient Logger LOG = LoggerFactory.getLogger(NettyHttpConsumer.class); - private final ConcurrentMap consumers = new ConcurrentHashMap(); + private final ConcurrentMap consumers = new ConcurrentHashMap(); private final String token; private final int len; @@ -54,12 +56,14 @@ public class HttpServerMultiplexChannelHandler extends SimpleChannelUpstreamHand public void addConsumer(NettyHttpConsumer consumer) { String path = pathAsKey(consumer.getConfiguration().getPath()); - consumers.put(path, new HttpServerChannelHandler(consumer)); + ContextPathMatcher matcher = new DefaultContextPathMatcher(path, consumer.getConfiguration().isMatchOnUriPrefix()); + consumers.put(matcher, new HttpServerChannelHandler(consumer)); } public void removeConsumer(NettyHttpConsumer consumer) { String path = pathAsKey(consumer.getConfiguration().getPath()); - consumers.remove(path); + ContextPathMatcher matcher = new DefaultContextPathMatcher(path, consumer.getConfiguration().isMatchOnUriPrefix()); + consumers.remove(matcher); } /** @@ -106,12 +110,16 @@ public class HttpServerMultiplexChannelHandler extends SimpleChannelUpstreamHand path = path.substring(idx + len); } - // TODO: support matchOnUriPrefix - // use the path as key to find the consumer handler to use path = pathAsKey(path); - return consumers.get(path); + // find the one that matches + for (Map.Entry entry : consumers.entrySet()) { + if (entry.getKey().matches(path)) { + return entry.getValue(); + } + } + return null; } private static String pathAsKey(String path) { http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpTwoRoutesMatchOnUriPrefixTest.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpTwoRoutesMatchOnUriPrefixTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpTwoRoutesMatchOnUriPrefixTest.java new file mode 100644 index 0000000..382e2c9 --- /dev/null +++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpTwoRoutesMatchOnUriPrefixTest.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.netty.http; + +import org.apache.camel.CamelExecutionException; +import org.apache.camel.builder.RouteBuilder; +import org.junit.Test; + +public class NettyHttpTwoRoutesMatchOnUriPrefixTest extends BaseNettyTest { + + @Test + public void testTwoRoutesMatchOnUriPrefix() throws Exception { + getMockEndpoint("mock:foo").expectedBodiesReceived("Hello World"); + getMockEndpoint("mock:bar").expectedBodiesReceived("Hello Camel", "Hi Camel"); + + String out = template.requestBody("netty-http:http://localhost:{{port}}/foo", "Hello World", String.class); + assertEquals("Bye World", out); + + // the foo is not match on prefix so we cannot do /foo/beer + try { + template.requestBody("netty-http:http://localhost:{{port}}/foo/beer", "Hello World", String.class); + fail("Should have thrown exception"); + } catch (CamelExecutionException e) { + NettyHttpOperationFailedException cause = assertIsInstanceOf(NettyHttpOperationFailedException.class, e.getCause()); + assertEquals(503, cause.getStatusCode()); + } + + out = template.requestBody("netty-http:http://localhost:{{port}}/bar", "Hello Camel", String.class); + assertEquals("Bye Camel", out); + + // the bar is match on prefix so we can do /bar/beer + out = template.requestBody("netty-http:http://localhost:{{port}}/bar/beer", "Hi Camel", String.class); + assertEquals("Bye Camel", out); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("netty-http:http://0.0.0.0:{{port}}/foo") + .to("mock:foo") + .transform().constant("Bye World"); + + from("netty-http:http://0.0.0.0:{{port}}/bar?matchOnUriPrefix=true") + .to("mock:bar") + .transform().constant("Bye Camel"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/cf1273af/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConsumer.java b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConsumer.java index 6234cba..6435b40 100644 --- a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConsumer.java +++ b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConsumer.java @@ -47,16 +47,16 @@ public class NettyConsumer extends DefaultConsumer { LOG.debug("Netty consumer binding to: {}", configuration.getAddress()); - // setup pipeline factory - ServerPipelineFactory pipelineFactory; - ServerPipelineFactory factory = configuration.getServerPipelineFactory(); - if (factory != null) { - pipelineFactory = factory.createPipelineFactory(this); - } else { - pipelineFactory = new DefaultServerPipelineFactory(this); - } - if (nettyServerBootstrapFactory == null) { + // setup pipeline factory + ServerPipelineFactory pipelineFactory; + ServerPipelineFactory factory = configuration.getServerPipelineFactory(); + if (factory != null) { + pipelineFactory = factory.createPipelineFactory(this); + } else { + pipelineFactory = new DefaultServerPipelineFactory(this); + } + if (isTcp()) { nettyServerBootstrapFactory = new SingleTCPNettyServerBootstrapFactory(); } else {