This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch backport/29221-to-camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit cd41cc87b75e3bc7e761808a0362b9c355fd0a49
Author: Guillaume Nodet <[email protected]>
AuthorDate: Thu Nov 5 15:54:46 2026 +0000

    [backport camel-4.22.x] CAMEL-26606: camel-platform-http-vertx - fail the 
start when the HTTP server cannot bind its port
---
 .../http/vertx/VertxPlatformHttpServer.java        | 26 ++++++---
 .../VertxPlatformHttpServerPortInUseTest.java      | 67 ++++++++++++++++++++++
 2 files changed, 84 insertions(+), 9 deletions(-)

diff --git 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
index 62650db1781e..22b5516a7a83 100644
--- 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
+++ 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.platform.http.vertx;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
 
 import io.vertx.core.Handler;
 import io.vertx.core.Vertx;
@@ -29,6 +30,7 @@ import io.vertx.ext.web.Router;
 import io.vertx.ext.web.RoutingContext;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.StaticService;
 import org.apache.camel.api.management.ManagedAttribute;
 import org.apache.camel.api.management.ManagedResource;
@@ -224,22 +226,20 @@ public class VertxPlatformHttpServer extends 
ServiceSupport implements CamelCont
         executor = 
context.getExecutorServiceManager().newSingleThreadExecutor(this, 
"platform-http-service");
         server = vertx.createHttpServer(options);
 
+        // the result of listen is handled on a Vert.x thread: an exception 
thrown there does not reach this thread,
+        // so keep the failure and throw it from here, or the server (and the 
CamelContext) starts with nothing listening
+        AtomicReference<Throwable> failure = new AtomicReference<>();
         CompletableFuture.runAsync(
                 () -> {
                     CountDownLatch latch = new CountDownLatch(1);
                     
server.requestHandler(router).listen(configuration.getBindPort(), 
configuration.getBindHost(), result -> {
                         try {
                             if (result.failed()) {
-                                LOGGER.warn("Failed to start Vert.x HttpServer 
on {}:{}, reason: {}",
-                                        configuration.getBindHost(),
-                                        configuration.getBindPort(),
-                                        result.cause().getMessage());
-
-                                throw new RuntimeException(result.cause());
+                                failure.set(result.cause());
+                            } else {
+                                LOGGER.info("Vert.x HttpServer started on 
{}:{}", configuration.getBindHost(),
+                                        server.actualPort());
                             }
-
-                            LOGGER.info("Vert.x HttpServer started on {}:{}", 
configuration.getBindHost(),
-                                    server.actualPort());
                         } finally {
                             latch.countDown();
                         }
@@ -253,6 +253,14 @@ public class VertxPlatformHttpServer extends 
ServiceSupport implements CamelCont
                     }
                 },
                 executor).toCompletableFuture().join();
+
+        Throwable cause = failure.get();
+        if (cause != null) {
+            throw new RuntimeCamelException(
+                    "Failed to start Vert.x HttpServer on " + 
configuration.getBindHost() + ":" + configuration.getBindPort()
+                                            + ", reason: " + cause,
+                    cause);
+        }
     }
 
     protected void stopServer() {
diff --git 
a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServerPortInUseTest.java
 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServerPortInUseTest.java
new file mode 100644
index 000000000000..42d28023f2bf
--- /dev/null
+++ 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServerPortInUseTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.platform.http.vertx;
+
+import java.net.BindException;
+import java.net.ServerSocket;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class VertxPlatformHttpServerPortInUseTest {
+    @RegisterExtension
+    AvailablePortFinder.Port port = AvailablePortFinder.find();
+
+    @Test
+    void startFailsWhenPortIsInUse() throws Exception {
+        try (ServerSocket portInUse = new ServerSocket(port.getPort());
+             CamelContext context = new DefaultCamelContext()) {
+            VertxPlatformHttpServerConfiguration configuration = new 
VertxPlatformHttpServerConfiguration();
+            configuration.setBindPort(port.getPort());
+            VertxPlatformHttpServer server = new 
VertxPlatformHttpServer(configuration);
+
+            context.addService(server);
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("platform-http:/test")
+                            .setBody().constant("Hello World");
+                }
+            });
+
+            RuntimeCamelException e = 
assertThrows(RuntimeCamelException.class, context::start);
+            assertInstanceOf(BindException.class, e.getCause());
+            assertTrue(e.getMessage().contains(":" + port.getPort()), 
e.getMessage());
+            assertFalse(context.isStarted());
+
+            // the failed start stopped the server, so it holds neither the 
HTTP server nor its own Vert.x instance
+            assertNull(server.getServer());
+            assertNull(server.getVertx());
+        }
+    }
+}

Reply via email to