From 0cb5c93ad3a35b5ceca2ccf81d9dd84a60d08a15 Mon Sep 17 00:00:00 2001 From: Otavio Rodolfo Piske Date: Fri, 23 Oct 2026 16:05:27 +0200 Subject: [PATCH 1/3] CAMEL-26108: camel-avro-rpc - the component should configure all options on the endpoint Co-Authored-By: Claude Opus 5.5 (1M context) (cherry picked from commit 55b266d9403f6d35e08752726156a8cf9bdc4387) --- .../camel/component/avro/AvroListener.java | 2 +- .../avro/AvroHttpConsumerHostTest.java | 80 +++++++++++++++++++ .../avro/spi/JettyHttpServerFactory.java | 5 ++ .../avro/spi/AvroRpcHttpServerFactory.java | 19 +++++ .../pages/camel-4x-upgrade-guide-4_18.adoc | 9 +++ 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java diff --git a/components/camel-avro-rpc/camel-avro-rpc-component/src/main/java/org/apache/camel/component/avro/AvroListener.java b/components/camel-avro-rpc/camel-avro-rpc-component/src/main/java/org/apache/camel/component/avro/AvroListener.java index 8e5dacbbec512..b006335f2037e 100644 --- a/components/camel-avro-rpc/camel-avro-rpc-component/src/main/java/org/apache/camel/component/avro/AvroListener.java +++ b/components/camel-avro-rpc/camel-avro-rpc-component/src/main/java/org/apache/camel/component/avro/AvroListener.java @@ -88,7 +88,7 @@ private static Server createServer(AvroConfiguration configuration, CamelContext .newInstance("avro-rpc-http-server-factory", AvroRpcHttpServerFactory.class) .orElseThrow(() -> new IllegalStateException( "AvroRpcHttpServerFactory is neither set on this endpoint neither found in Camel Registry or FactoryFinder.")); - return factory.create(responder, configuration.getPort()); + return factory.create(responder, configuration.getHost(), configuration.getPort()); } else if (AVRO_NETTY_TRANSPORT.equalsIgnoreCase(configuration.getTransport().name())) { return new NettyServer(responder, new InetSocketAddress(configuration.getHost(), configuration.getPort())); } else { diff --git a/components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java b/components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java new file mode 100644 index 0000000000000..53253fc2d534f --- /dev/null +++ b/components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java @@ -0,0 +1,80 @@ +/* + * 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.avro; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.Socket; +import java.net.SocketException; + +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +/** + * The http consumer listens on the host of the endpoint, as the netty consumer does. + */ +public class AvroHttpConsumerHostTest extends AvroTestSupport { + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("avro:http:127.0.0.1:" + avroPort + + "/getName?protocolClassName=org.apache.camel.avro.test.TestReflection") + .setBody(constant("Camel")); + } + }; + } + + @Test + public void testListensOnConfiguredHostOnly() throws Exception { + InetAddress other = findNonLoopbackAddress(); + assumeTrue(other != null, "No non-loopback IPv4 address available"); + + assertDoesNotThrow(() -> connect(InetAddress.getByName("127.0.0.1"))); + assertThrows(IOException.class, () -> connect(other)); + } + + private void connect(InetAddress address) throws IOException { + try (Socket socket = new Socket()) { + socket.connect(new InetSocketAddress(address, avroPort), 2000); + } + } + + private static InetAddress findNonLoopbackAddress() throws SocketException { + return NetworkInterface.networkInterfaces() + .filter(nic -> { + try { + return nic.isUp() && !nic.isLoopback(); + } catch (SocketException e) { + return false; + } + }) + .flatMap(NetworkInterface::inetAddresses) + .filter(address -> address instanceof Inet4Address && !address.isLoopbackAddress()) + .findFirst() + .orElse(null); + } +} diff --git a/components/camel-avro-rpc/camel-avro-rpc-jetty/src/main/java/org/apache/camel/component/avro/spi/JettyHttpServerFactory.java b/components/camel-avro-rpc/camel-avro-rpc-jetty/src/main/java/org/apache/camel/component/avro/spi/JettyHttpServerFactory.java index 0e428fc559f79..1a5c905dd6b5d 100644 --- a/components/camel-avro-rpc/camel-avro-rpc-jetty/src/main/java/org/apache/camel/component/avro/spi/JettyHttpServerFactory.java +++ b/components/camel-avro-rpc/camel-avro-rpc-jetty/src/main/java/org/apache/camel/component/avro/spi/JettyHttpServerFactory.java @@ -32,4 +32,9 @@ public class JettyHttpServerFactory implements AvroRpcHttpServerFactory { public Server create(SpecificResponder responder, int port) throws IOException { return new HttpServer(responder, port); } + + @Override + public Server create(SpecificResponder responder, String host, int port) throws IOException { + return new HttpServer(responder, host, port); + } } diff --git a/components/camel-avro-rpc/camel-avro-rpc-spi/src/main/java/org/apache/camel/component/avro/spi/AvroRpcHttpServerFactory.java b/components/camel-avro-rpc/camel-avro-rpc-spi/src/main/java/org/apache/camel/component/avro/spi/AvroRpcHttpServerFactory.java index c53fde1fcffe6..136d5052096a6 100644 --- a/components/camel-avro-rpc/camel-avro-rpc-spi/src/main/java/org/apache/camel/component/avro/spi/AvroRpcHttpServerFactory.java +++ b/components/camel-avro-rpc/camel-avro-rpc-spi/src/main/java/org/apache/camel/component/avro/spi/AvroRpcHttpServerFactory.java @@ -25,5 +25,24 @@ */ public interface AvroRpcHttpServerFactory { + /** + * Creates a server that listens on the given port on all interfaces. + */ Server create(SpecificResponder responder, int port) throws Exception; + + /** + * Creates a server that listens on the given host and port. + * + * The default implementation ignores the host and calls {@link #create(SpecificResponder, int)}, so an + * implementation should override it to listen on the host the endpoint is configured with. + * + * @param responder the responder + * @param host the host or address to listen on + * @param port the port to listen on + * @return the server + * @since 4.18.6 + */ + default Server create(SpecificResponder responder, String host, int port) throws Exception { + return create(responder, port); + } } diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index 19a7f0f652537..9333e7beb726f 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -1875,3 +1875,12 @@ now refuses to send a request path, query or header value that contains a contro framing, are still allowed. Routes that put a percent-encoded control character (such as `%0D%0A`) into the `CamelHttpPath` or `CamelHttpQuery` header, which the producer decodes before building the request, are the ones most likely to be affected. + +=== camel-avro-rpc - the http consumer listens on the host of the endpoint + +The `avro:http` consumer now uses the host of the endpoint URI (`avro:http:[host]:[port]`) for its HTTP server, as the `avro:netty` consumer does. + +Use `0.0.0.0` as the host to accept connections on all network interfaces. + +`AvroRpcHttpServerFactory` has a new method `create(SpecificResponder, String, int)` that receives the host. A custom factory should implement it. + From 80689d176c98324f0adb8d860e48f190508da171 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 26 Oct 2026 09:17:58 +0000 Subject: [PATCH 2/3] CAMEL-26108: camel-avro-rpc - address review comments Use 127.0.0.2 in the test instead of looking up a non-loopback address, so it always runs, and remove trailing whitespace in the upgrade guide. Co-Authored-By: Claude Opus 5.5 (1M context) (cherry picked from commit aa2c0c3687da0ee0bfedd8c0721a844b5c8a535d) --- .../avro/AvroHttpConsumerHostTest.java | 33 +++---------------- .../pages/camel-4x-upgrade-guide-4_18.adoc | 3 +- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java b/components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java index 53253fc2d534f..7706cc6d58dca 100644 --- a/components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java +++ b/components/camel-avro-rpc/camel-avro-rpc-component/src/test/java/org/apache/camel/component/avro/AvroHttpConsumerHostTest.java @@ -17,19 +17,14 @@ package org.apache.camel.component.avro; import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.NetworkInterface; import java.net.Socket; -import java.net.SocketException; import org.apache.camel.builder.RouteBuilder; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assumptions.assumeTrue; /** * The http consumer listens on the host of the endpoint, as the netty consumer does. @@ -49,32 +44,14 @@ public void configure() { } @Test - public void testListensOnConfiguredHostOnly() throws Exception { - InetAddress other = findNonLoopbackAddress(); - assumeTrue(other != null, "No non-loopback IPv4 address available"); - - assertDoesNotThrow(() -> connect(InetAddress.getByName("127.0.0.1"))); - assertThrows(IOException.class, () -> connect(other)); + public void testListensOnConfiguredHostOnly() { + assertDoesNotThrow(() -> connect("127.0.0.1")); + assertThrows(IOException.class, () -> connect("127.0.0.2")); } - private void connect(InetAddress address) throws IOException { + private void connect(String host) throws IOException { try (Socket socket = new Socket()) { - socket.connect(new InetSocketAddress(address, avroPort), 2000); + socket.connect(new InetSocketAddress(host, avroPort), 2000); } } - - private static InetAddress findNonLoopbackAddress() throws SocketException { - return NetworkInterface.networkInterfaces() - .filter(nic -> { - try { - return nic.isUp() && !nic.isLoopback(); - } catch (SocketException e) { - return false; - } - }) - .flatMap(NetworkInterface::inetAddresses) - .filter(address -> address instanceof Inet4Address && !address.isLoopbackAddress()) - .findFirst() - .orElse(null); - } } diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index 9333e7beb726f..3ff0f9897ce7d 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -1878,9 +1878,8 @@ likely to be affected. === camel-avro-rpc - the http consumer listens on the host of the endpoint -The `avro:http` consumer now uses the host of the endpoint URI (`avro:http:[host]:[port]`) for its HTTP server, as the `avro:netty` consumer does. +The `avro:http` consumer now uses the host of the endpoint URI (`avro:http:[host]:[port]`) for its HTTP server, as the `avro:netty` consumer does. Use `0.0.0.0` as the host to accept connections on all network interfaces. `AvroRpcHttpServerFactory` has a new method `create(SpecificResponder, String, int)` that receives the host. A custom factory should implement it. - From 0ff1a6b4bfa891f4c3c26ef9402c19fb1636c093 Mon Sep 17 00:00:00 2001 From: Otavio Rodolfo Piske Date: Mon, 26 Oct 2026 14:53:28 +0100 Subject: [PATCH 3/3] CAMEL-26108: Move Avro upgrade note to 4.18.6 section --- .../ROOT/pages/camel-4x-upgrade-guide-4_18.adoc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index 3ff0f9897ce7d..4cb7a34343d53 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -63,6 +63,14 @@ With `includeTrace=true`, the URI of the from endpoint in the SQL comment is now an endpoint URI, and it is left out when the exchange has no from endpoint, which failed with a `NullPointerException` before. +=== camel-avro-rpc - the http consumer listens on the host of the endpoint + +The `avro:http` consumer now uses the host of the endpoint URI (`avro:http:[host]:[port]`) for its HTTP server, as the `avro:netty` consumer does. + +Use `0.0.0.0` as the host to accept connections on all network interfaces. + +`AvroRpcHttpServerFactory` has a new method `create(SpecificResponder, String, int)` that receives the host. A custom factory should implement it. + == Upgrading from 4.18.4 to 4.18.5 === camel-docling - output path handling @@ -1875,11 +1883,3 @@ now refuses to send a request path, query or header value that contains a contro framing, are still allowed. Routes that put a percent-encoded control character (such as `%0D%0A`) into the `CamelHttpPath` or `CamelHttpQuery` header, which the producer decodes before building the request, are the ones most likely to be affected. - -=== camel-avro-rpc - the http consumer listens on the host of the endpoint - -The `avro:http` consumer now uses the host of the endpoint URI (`avro:http:[host]:[port]`) for its HTTP server, as the `avro:netty` consumer does. - -Use `0.0.0.0` as the host to accept connections on all network interfaces. - -`AvroRpcHttpServerFactory` has a new method `create(SpecificResponder, String, int)` that receives the host. A custom factory should implement it.