This is an automated email from the ASF dual-hosted git repository. apupier pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 25784633387d78a00fab4cdeb640a814e34912f2 Author: smjain <[email protected]> AuthorDate: Wed Nov 4 12:55:17 2026 +0530 CAMEL-26432: camel-chaos - review: an address only after a real scheme (not a colon in the query of a scheme alias), the netty-http failure gives the address, docs since CAMEL-26487 Co-Authored-By: Claude Opus 5.5 <[email protected]> --- .../org/apache/camel/catalog/docs/chaos.adoc | 10 +-- components/camel-chaos/src/main/docs/chaos.adoc | 10 +-- .../apache/camel/component/chaos/ChaosFaults.java | 15 ++++- .../camel/component/chaos/ChaosPatterns.java | 32 ++++++--- .../camel/component/chaos/ChaosPatternsTest.java | 78 ++++++++++++++++++++++ 5 files changed, 126 insertions(+), 19 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc index 5875de042a65..84a54c419cd6 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/chaos.adoc @@ -161,11 +161,11 @@ which ignore case and can be regular expressions: a rule, also one from a tool, `endpoint=` pattern is matched against the endpoint URI, with or without its query parameters, and the `//` after the scheme does not count (`kafka:orders*` matches `kafka://orders?brokers=b1`). A `component=` pattern is matched against the scheme of the URI. Some components give their endpoints the URI of their address: -`netty-http:http://inventory/stock` and `undertow:http://inventory/stock` have the endpoint URI -`http://inventory/stock`. When the scheme of the endpoint URI is not a name of the component in the context, chaos puts -the default name of the component in front, and matches `netty-http:http://inventory/stock` (with -`component=netty-http`, not `component=http`; a camel-netty-http component added under another name is matched as -`netty-http` too). A `route=` pattern is matched against the route id, and a `step=` pattern against the id of the step +`undertow:http://inventory/stock` has the endpoint URI `http://inventory/stock`. When the scheme of the endpoint URI is +not a name of the component in the context, chaos puts the default name of the component in front, and matches +`undertow:http://inventory/stock` (with `component=undertow`, not `component=http`). A camel-netty-http endpoint has +the endpoint URI `netty-http://http://inventory/stock`, and a camel-netty-http component added under another name is +matched with `netty-http` in front too. A `route=` pattern is matched against the route id, and a `step=` pattern against the id of the step (`to1`, or the id set with `id("enrich")`). A rule gets an id when it is added (`r1`, `r2`, ...), which change and remove take. A change replaces the rule with a diff --git a/components/camel-chaos/src/main/docs/chaos.adoc b/components/camel-chaos/src/main/docs/chaos.adoc index 5875de042a65..84a54c419cd6 100644 --- a/components/camel-chaos/src/main/docs/chaos.adoc +++ b/components/camel-chaos/src/main/docs/chaos.adoc @@ -161,11 +161,11 @@ which ignore case and can be regular expressions: a rule, also one from a tool, `endpoint=` pattern is matched against the endpoint URI, with or without its query parameters, and the `//` after the scheme does not count (`kafka:orders*` matches `kafka://orders?brokers=b1`). A `component=` pattern is matched against the scheme of the URI. Some components give their endpoints the URI of their address: -`netty-http:http://inventory/stock` and `undertow:http://inventory/stock` have the endpoint URI -`http://inventory/stock`. When the scheme of the endpoint URI is not a name of the component in the context, chaos puts -the default name of the component in front, and matches `netty-http:http://inventory/stock` (with -`component=netty-http`, not `component=http`; a camel-netty-http component added under another name is matched as -`netty-http` too). A `route=` pattern is matched against the route id, and a `step=` pattern against the id of the step +`undertow:http://inventory/stock` has the endpoint URI `http://inventory/stock`. When the scheme of the endpoint URI is +not a name of the component in the context, chaos puts the default name of the component in front, and matches +`undertow:http://inventory/stock` (with `component=undertow`, not `component=http`). A camel-netty-http endpoint has +the endpoint URI `netty-http://http://inventory/stock`, and a camel-netty-http component added under another name is +matched with `netty-http` in front too. A `route=` pattern is matched against the route id, and a `step=` pattern against the id of the step (`to1`, or the id set with `id("enrich")`). A rule gets an id when it is added (`r1`, `r2`, ...), which change and remove take. A change replaces the rule with a diff --git a/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosFaults.java b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosFaults.java index 551fe94e6368..c4b29e28bb0f 100644 --- a/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosFaults.java +++ b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosFaults.java @@ -195,7 +195,20 @@ final class ChaosFaults { return (Throwable) type .getConstructor(String.class, int.class, String.class, String.class, resolve(endpoint, "io.netty.handler.codec.http.HttpContent")) - .newInstance(endpoint.getEndpointBaseUri(), rule.status, statusText(rule.status), location(rule), response); + .newInstance(nettyHttpAddress(endpoint), rule.status, statusText(rule.status), location(rule), response); + } + + /** + * The address that camel-netty-http calls, as the url of its failure: since CAMEL-26487 the endpoint URI of a + * camel-netty-http endpoint is its whole URI ({@code netty-http://http://host/path}) and its address is + * {@code getAddressUri()}. + */ + private static String nettyHttpAddress(Endpoint endpoint) { + try { + return (String) endpoint.getClass().getMethod("getAddressUri").invoke(endpoint); + } catch (ReflectiveOperationException | ClassCastException e) { + return endpoint.getEndpointBaseUri(); + } } private static Class<?> resolve(Endpoint endpoint, String name) throws ClassNotFoundException { diff --git a/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosPatterns.java b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosPatterns.java index c78d61ebe351..f7f05d6a2292 100644 --- a/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosPatterns.java +++ b/components/camel-chaos/src/main/java/org/apache/camel/component/chaos/ChaosPatterns.java @@ -105,11 +105,13 @@ final class ChaosPatterns { } /** - * The URI of an endpoint as the rules see it: its endpoint URI, with the name of its component in front when the - * scheme of that URI is not a name of its component in the context. camel-netty-http and camel-undertow give their - * endpoints the URI of their address ({@code netty-http:http://host/path} has the endpoint URI - * {@code http://host/path}), so their endpoints are matched as {@code netty-http:http://host/path}, by - * {@code component=netty-http} and not by {@code component=http}. + * The URI of an endpoint as the rules see it: its endpoint URI, with the default name of its component in front + * when the URI is the address of the endpoint. camel-undertow gives its endpoints the URI of their address + * ({@code undertow:http://host/path} has the endpoint URI {@code http://host/path}), and a camel-netty-http + * component added under another name gives that name and the address ({@code nh://http://host/path}); both are + * matched with the default name of the component ({@code undertow:http://host/path}, + * {@code netty-http://http://host/path}), by {@code component=undertow} or {@code component=netty-http} and not by + * {@code component=http}. */ static String endpointUri(Endpoint endpoint) { String uri = endpoint.getEndpointUri(); @@ -135,10 +137,24 @@ final class ChaosPatterns { return name != null && !name.equals(scheme) ? name + ":" + uri : uri; } - /** Whether the text is an address with a scheme of its own ({@code http://host/path}). */ + /** + * Whether the text is an address with a scheme of its own ({@code http://host/path}, or + * {@code //http://host/path}): a scheme (letters, digits, {@code +}, {@code -} and {@code .}) then {@code ://}, not + * a colon further on, such as one in the query of an ordinary URI. + */ private static boolean isAddress(String text) { - int colon = text.indexOf(':'); - return colon > 0 && text.startsWith("//", colon + 1); + int start = text.startsWith("//") ? 2 : 0; + int colon = text.indexOf(':', start); + if (colon <= start || !text.startsWith("//", colon + 1)) { + return false; + } + for (int i = start; i < colon; i++) { + char c = text.charAt(i); + if (!Character.isLetterOrDigit(c) && c != '+' && c != '-' && c != '.') { + return false; + } + } + return true; } /** diff --git a/components/camel-chaos/src/test/java/org/apache/camel/component/chaos/ChaosPatternsTest.java b/components/camel-chaos/src/test/java/org/apache/camel/component/chaos/ChaosPatternsTest.java index 8dd0a3106cde..5c233c946973 100644 --- a/components/camel-chaos/src/test/java/org/apache/camel/component/chaos/ChaosPatternsTest.java +++ b/components/camel-chaos/src/test/java/org/apache/camel/component/chaos/ChaosPatternsTest.java @@ -18,9 +18,18 @@ package org.apache.camel.component.chaos; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.concurrent.TimeUnit; +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.impl.DefaultCamelContext; +import org.apache.camel.support.DefaultComponent; +import org.apache.camel.support.DefaultEndpoint; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -131,4 +140,73 @@ class ChaosPatternsTest { assertThat(ChaosPatterns.matches("*".repeat(2000) + "b", text)).isFalse(); assertThat(ChaosPatterns.matches("*".repeat(2000), text)).isTrue(); } + + @Test + void anAddressAfterAnotherNameOfTheComponentIsMatchedWithItsDefaultName() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + // camel-netty-http added as nh: since CAMEL-26487 its endpoint URI is nh://http://host/path + DefaultComponent nh = new NamedComponent("netty-http"); + context.addComponent("nh", nh); + assertThat(ChaosPatterns.endpointUri(new UriEndpoint("nh://http://localhost:9/stock", nh))) + .isEqualTo("netty-http://http://localhost:9/stock"); + assertThat(ChaosPatterns.endpointUri(new UriEndpoint("nh:http://localhost:9/stock?muteException=true", nh))) + .isEqualTo("netty-http:http://localhost:9/stock?muteException=true"); + // the address alone (as camel-undertow gives it) has the default name in front + assertThat(ChaosPatterns.endpointUri(new UriEndpoint("http://localhost:9/stock", nh))) + .isEqualTo("netty-http:http://localhost:9/stock"); + } + } + + @Test + void aSchemeAliasWithAnAddressInTheQueryKeepsItsScheme() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + // as camel-http, whose @Component("http,https") gives the https instance the default name http + DefaultComponent https = new NamedComponent("http"); + context.addComponent("https", https); + String uri = "https://inventory/stock?callback=http://elsewhere/done"; + String seen = ChaosPatterns.endpointUri(new UriEndpoint(uri, https)); + assertThat(seen).isEqualTo(uri); + assertThat(ChaosPatterns.matches("https:inventory*", ChaosPatterns.withoutSlashes(seen))).isTrue(); + assertThat(ChaosPatterns.matchesScheme("https", seen)).isTrue(); + // a renamed component whose URI is not an address keeps the name it has in the context + DefaultComponent myseda = new NamedComponent("seda"); + context.addComponent("myseda", myseda); + assertThat(ChaosPatterns.endpointUri(new UriEndpoint("myseda://orders?timeout=0", myseda))) + .isEqualTo("myseda://orders?timeout=0"); + } + } + + private static final class NamedComponent extends DefaultComponent { + private final String defaultName; + + NamedComponent(String defaultName) { + this.defaultName = defaultName; + } + + @Override + public String getDefaultName() { + return defaultName; + } + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) { + return new UriEndpoint(uri, this); + } + } + + private static final class UriEndpoint extends DefaultEndpoint { + UriEndpoint(String uri, DefaultComponent component) { + super(uri, component); + } + + @Override + public Producer createProducer() { + throw new UnsupportedOperationException(); + } + + @Override + public Consumer createConsumer(Processor processor) { + throw new UnsupportedOperationException(); + } + } }
