diff --git a/docs/modules/ROOT/pages/reference/extensions/core.adoc b/docs/modules/ROOT/pages/reference/extensions/core.adoc index b09867f1b81..c028d95119a 100644 --- a/docs/modules/ROOT/pages/reference/extensions/core.adoc +++ b/docs/modules/ROOT/pages/reference/extensions/core.adoc @@ -130,12 +130,6 @@ As such, the class `PropertiesCustomBeanWithSetterInjection` needs to be link:ht | Configuration property | Type | Default -|icon:lock[title=Fixed at build time] [[quarkus.camel.bootstrap.enabled]]`link:#quarkus.camel.bootstrap.enabled[quarkus.camel.bootstrap.enabled]` - -When set to true, the `CamelRuntime` will be started automatically. -| `boolean` -| `true` - |icon:lock[title=Fixed at build time] [[quarkus.camel.service.discovery.exclude-patterns]]`link:#quarkus.camel.service.discovery.exclude-patterns[quarkus.camel.service.discovery.exclude-patterns]` A comma-separated list of Ant-path style patterns to match Camel service definition files in the classpath. The @@ -481,6 +475,12 @@ throws a `RuntimeException` ignore - Suppresses any warnings and the application Prints the `CamelMain` usage statement but allows the application startup to proceed as normal | `fail`, `warn`, `ignore` | `warn` + +| [[quarkus.camel.bootstrap.enabled]]`link:#quarkus.camel.bootstrap.enabled[quarkus.camel.bootstrap.enabled]` + +When set to true, the {@link CamelRuntime} will be started automatically. +| `boolean` +| `true` |=== [.configuration-legend] diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelBootstrapProcessor.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelBootstrapProcessor.java index d0d675f8d15..c91e56a80db 100644 --- a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelBootstrapProcessor.java +++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelBootstrapProcessor.java @@ -26,6 +26,7 @@ import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.runtime.ShutdownContext; import org.apache.camel.quarkus.core.CamelBootstrapRecorder; +import org.apache.camel.quarkus.core.CamelRuntimeConfig; import org.apache.camel.quarkus.core.deployment.spi.CamelBootstrapCompletedBuildItem; import org.apache.camel.quarkus.core.deployment.spi.CamelRuntimeBuildItem; import org.apache.camel.quarkus.core.deployment.util.CamelQuarkusVersion; @@ -39,6 +40,7 @@ class CamelBootstrapProcessor { * @param commandLineArguments a reference to the raw command line arguments as they were passed to the application. * @param shutdown a reference to a {@link ShutdownContext} used tor register the Camel's related shutdown * tasks. + * @param camelRuntimeConfig The {@link CamelRuntimeConfig} instance. */ @BuildStep @Record(value = ExecutionTime.RUNTIME_INIT) @@ -48,11 +50,12 @@ void boot( CamelRuntimeBuildItem runtime, RawCommandLineArgumentsBuildItem commandLineArguments, ShutdownContextBuildItem shutdown, - BuildProducer serviceStartBuildItems) { + BuildProducer serviceStartBuildItems, + CamelRuntimeConfig camelRuntimeConfig) { recorder.addShutdownTask(shutdown, runtime.runtime()); if (runtime.isAutoStartup()) { - recorder.start(runtime.runtime(), commandLineArguments, CamelQuarkusVersion.getVersion()); + recorder.start(camelRuntimeConfig, runtime.runtime(), commandLineArguments, CamelQuarkusVersion.getVersion()); } /* Make sure that Quarkus orders this method before starting to serve HTTP endpoints. * Otherwise first requests might reach Camel context in a non-yet-started state. */ diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelBootstrapRecorder.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelBootstrapRecorder.java index 5b679fd5f72..913e197562f 100644 --- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelBootstrapRecorder.java +++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelBootstrapRecorder.java @@ -38,13 +38,16 @@ public void run() { }); } - public void start(RuntimeValue runtime, Supplier arguments, String camelQuarkusVersion) { - try { - Logger logger = Logger.getLogger(CamelBootstrapRecorder.class); - logger.infof("Apache Camel Quarkus %s is starting", camelQuarkusVersion); - runtime.getValue().start(arguments.get()); - } catch (Exception e) { - throw new RuntimeException(e); + public void start(CamelRuntimeConfig camelRuntimeConfig, RuntimeValue runtime, Supplier arguments, + String camelQuarkusVersion) { + if (camelRuntimeConfig.bootstrap.enabled) { + try { + Logger logger = Logger.getLogger(CamelBootstrapRecorder.class); + logger.infof("Apache Camel Quarkus %s is starting", camelQuarkusVersion); + runtime.getValue().start(arguments.get()); + } catch (Exception e) { + throw new RuntimeException(e); + } } } } diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java index 49e54ffe0c2..f341f9dfebd 100644 --- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java +++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelConfig.java @@ -32,14 +32,6 @@ public enum FailureRemedy { fail, warn, ignore } - /** - * Build time configuration options for `CamelRuntime` bootstrap. - * - * @asciidoclet - */ - @ConfigItem - public BootstrapConfig bootstrap; - /** * Build time configuration options for Camel services. * @@ -121,18 +113,6 @@ public enum FailureRemedy { @ConfigItem public TypeConverterConfig typeConverter; - @ConfigGroup - public static class BootstrapConfig { - - /** - * When set to true, the `CamelRuntime` will be started automatically. - * - * @asciidoclet - */ - @ConfigItem(defaultValue = "true") - public boolean enabled; - } - @ConfigGroup public static class RoutesDiscoveryConfig { diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRuntime.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRuntime.java index 933ec1402bb..ae1b1500e52 100644 --- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRuntime.java +++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRuntime.java @@ -22,7 +22,7 @@ * Represent a runnable Camel instance. */ public interface CamelRuntime extends HasCamelContext { - void start(String[] args); + void start(String... args); void stop(); diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRuntimeConfig.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRuntimeConfig.java new file mode 100644 index 00000000000..7c22fb2c391 --- /dev/null +++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRuntimeConfig.java @@ -0,0 +1,44 @@ +/* + * 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.quarkus.core; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot(name = "camel", phase = ConfigPhase.RUN_TIME) +public class CamelRuntimeConfig { + /** + * Runtime configuration options for {@link CamelRuntime} bootstrap. + * + * @asciidoclet + */ + @ConfigItem + public BootstrapConfig bootstrap; + + @ConfigGroup + public static class BootstrapConfig { + /** + * When set to true, the {@link CamelRuntime} will be started automatically. + * + * @asciidoclet + */ + @ConfigItem(defaultValue = "true") + public boolean enabled; + } +} diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/main/CamelMainRuntime.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/main/CamelMainRuntime.java index dd9b329f28a..720dda99531 100644 --- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/main/CamelMainRuntime.java +++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/main/CamelMainRuntime.java @@ -68,7 +68,10 @@ public void start(String[] args) { @Override public void stop() { - main.stop(); + if (!main.isStopped()) { + main.stop(); + } + /* Wait till the Camel shutdown is finished in camel-main thread started in start(String[]) above */ final Thread worker = this.mainThread; if (worker != null) { diff --git a/integration-tests/main/src/main/java/org/apache/camel/quarkus/main/CoreMainResource.java b/integration-tests/main/src/main/java/org/apache/camel/quarkus/main/CoreMainResource.java index 40c48878514..b885520593b 100644 --- a/integration-tests/main/src/main/java/org/apache/camel/quarkus/main/CoreMainResource.java +++ b/integration-tests/main/src/main/java/org/apache/camel/quarkus/main/CoreMainResource.java @@ -41,6 +41,7 @@ import org.apache.camel.component.log.LogComponent; import org.apache.camel.impl.debugger.DebuggerJmxConnectorService; import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.quarkus.core.CamelRuntime; import org.apache.camel.quarkus.core.FastFactoryFinderResolver; import org.apache.camel.quarkus.it.support.typeconverter.MyPair; import org.apache.camel.reactive.vertx.VertXReactiveExecutor; @@ -63,6 +64,9 @@ public class CoreMainResource { @Inject CamelMain main; + @Inject + CamelRuntime camelRuntime; + @Path("/property/{name}") @GET @Produces(MediaType.TEXT_PLAIN) @@ -310,4 +314,17 @@ public void contextReload() { contextReloadStrategy.onReload(this); } } + + @Path("/runtime/status") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String runtimeStatus() { + return main.getStatus().name(); + } + + @Path("/runtime/start") + @POST + public void runtimeStart() { + camelRuntime.start(); + } } diff --git a/integration-tests/main/src/test/java/org/apache/camel/quarkus/main/BootstrapDisabledIT.java b/integration-tests/main/src/test/java/org/apache/camel/quarkus/main/BootstrapDisabledIT.java new file mode 100644 index 00000000000..1bbbbb2d346 --- /dev/null +++ b/integration-tests/main/src/test/java/org/apache/camel/quarkus/main/BootstrapDisabledIT.java @@ -0,0 +1,23 @@ +/* + * 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.quarkus.main; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +class BootstrapDisabledIT extends BootstrapDisabledTest { +} diff --git a/integration-tests/main/src/test/java/org/apache/camel/quarkus/main/BootstrapDisabledTest.java b/integration-tests/main/src/test/java/org/apache/camel/quarkus/main/BootstrapDisabledTest.java new file mode 100644 index 00000000000..424e5a41c41 --- /dev/null +++ b/integration-tests/main/src/test/java/org/apache/camel/quarkus/main/BootstrapDisabledTest.java @@ -0,0 +1,62 @@ +/* + * 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.quarkus.main; + +import java.time.Duration; +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.QuarkusTestProfile; +import io.quarkus.test.junit.TestProfile; +import io.restassured.RestAssured; +import org.apache.camel.ServiceStatus; +import org.junit.jupiter.api.Test; + +import static org.awaitility.Awaitility.await; +import static org.hamcrest.Matchers.is; + +@QuarkusTest +@TestProfile(BootstrapDisabledTest.BootstrapDisabledTestProfile.class) +class BootstrapDisabledTest { + @Test + void initializeManualRuntimeBootstrap() { + // Initial runtime state should be stopped + RestAssured.get("/test/runtime/status") + .then() + .statusCode(200) + .body(is(ServiceStatus.Stopped.name())); + + // Ensure the runtime can be started manually + RestAssured.post("/test/runtime/start") + .then() + .statusCode(204); + + await().atMost(Duration.ofSeconds(10)).pollDelay(Duration.ofMillis(100)).untilAsserted(() -> { + RestAssured.get("/test/runtime/status") + .then() + .statusCode(200) + .body(is(ServiceStatus.Started.name())); + }); + } + + public static final class BootstrapDisabledTestProfile implements QuarkusTestProfile { + @Override + public Map getConfigOverrides() { + return Map.of("quarkus.camel.bootstrap.enabled", "false"); + } + } +}