This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
The following commit(s) were added to refs/heads/main by this push:
new ab83d59c377 CAMEL-21353: camel-core - Add possibility to set some
condition for Camel to wait during startup before continuing
ab83d59c377 is described below
commit ab83d59c377abdf977a03b0944e408837c4af758
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Oct 19 11:19:04 2024 +0200
CAMEL-21353: camel-core - Add possibility to set some condition for Camel
to wait during startup before continuing
---
.../src/main/docs/spring-boot.json | 51 +++++++++
.../camel/spring/boot/CamelAutoConfiguration.java | 42 ++++++--
...melStartupConditionConfigurationProperties.java | 119 +++++++++++++++++++++
.../spring/boot/CamelStartupConditionEnvTest.java | 90 ++++++++++++++++
4 files changed, 295 insertions(+), 7 deletions(-)
diff --git a/core/camel-spring-boot/src/main/docs/spring-boot.json
b/core/camel-spring-boot/src/main/docs/spring-boot.json
index 0150e215c0c..b357c22774f 100644
--- a/core/camel-spring-boot/src/main/docs/spring-boot.json
+++ b/core/camel-spring-boot/src/main/docs/spring-boot.json
@@ -121,6 +121,11 @@
"type":
"org.apache.camel.spring.boot.security.CamelSSLConfigurationProperties",
"sourceType":
"org.apache.camel.spring.boot.security.CamelSSLConfigurationProperties"
},
+ {
+ "name": "camel.startupcondition",
+ "type":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties"
+ },
{
"name": "camel.threadpool",
"type":
"org.apache.camel.spring.boot.threadpool.CamelThreadPoolConfigurationProperties",
@@ -1439,6 +1444,52 @@
"description": "The optional trust manager configuration for creating
the TrustManager used in constructing an SSLContext.",
"sourceType":
"org.apache.camel.spring.boot.security.CamelSSLConfigurationProperties"
},
+ {
+ "name": "camel.startupcondition.custom-class-names",
+ "type": "java.lang.String",
+ "description": "A list of custom class names (FQN). Multiple classes can
be separated by comma.",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties"
+ },
+ {
+ "name": "camel.startupcondition.enabled",
+ "type": "java.lang.Boolean",
+ "description": "To enable using startup conditions",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties",
+ "defaultValue": false
+ },
+ {
+ "name": "camel.startupcondition.environment-variable-exists",
+ "type": "java.lang.String",
+ "description": "Wait for an environment variable with the given name to
exists before continuing",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties"
+ },
+ {
+ "name": "camel.startupcondition.file-exists",
+ "type": "java.lang.String",
+ "description": "Wait for a file with the given name to exists before
continuing",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties"
+ },
+ {
+ "name": "camel.startupcondition.interval",
+ "type": "java.lang.Integer",
+ "description": "Interval in millis between checking conditions.",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties",
+ "defaultValue": 500
+ },
+ {
+ "name": "camel.startupcondition.on-timeout",
+ "type": "java.lang.String",
+ "description": "What action, to do on timeout. fail = do not startup,
and throw an exception causing camel to fail stop = do not startup, and stop
camel ignore = log a WARN and continue to startup",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties",
+ "defaultValue": "stop"
+ },
+ {
+ "name": "camel.startupcondition.timeout",
+ "type": "java.lang.Integer",
+ "description": "Total timeout (in millis) for all startup conditions.",
+ "sourceType":
"org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties",
+ "defaultValue": 20000
+ },
{
"name": "camel.threadpool.allow-core-thread-time-out",
"type": "java.lang.Boolean",
diff --git
a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
index 9765035b30c..0df0385db1f 100644
---
a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
+++
b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
@@ -40,6 +40,7 @@ import org.apache.camel.spi.CliConnector;
import org.apache.camel.spi.CliConnectorFactory;
import org.apache.camel.spi.PackageScanClassResolver;
import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.StartupConditionStrategy;
import org.apache.camel.spi.StartupStepRecorder;
import org.apache.camel.spi.VariableRepository;
import org.apache.camel.spi.VariableRepositoryFactory;
@@ -51,6 +52,9 @@ import org.apache.camel.support.LanguageSupport;
import org.apache.camel.support.ResetableClock;
import org.apache.camel.support.ResourceHelper;
import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.support.startup.DefaultStartupConditionStrategy;
+import org.apache.camel.support.startup.EnvStartupCondition;
+import org.apache.camel.support.startup.FileStartupCondition;
import org.apache.camel.support.startup.LoggingStartupStepRecorder;
import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
@@ -77,7 +81,7 @@ import org.springframework.core.env.MutablePropertySources;
@ImportRuntimeHints(CamelRuntimeHints.class)
@Configuration(proxyBeanMethods = false)
-@EnableConfigurationProperties({ CamelConfigurationProperties.class })
+@EnableConfigurationProperties({CamelConfigurationProperties.class,
CamelStartupConditionConfigurationProperties.class})
@Import(TypeConversionConfiguration.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class CamelAutoConfiguration {
@@ -97,7 +101,7 @@ public class CamelAutoConfiguration {
@Bean(destroyMethod = "")
@ConditionalOnMissingBean(CamelContext.class)
CamelContext camelContext(ApplicationContext applicationContext,
CamelConfigurationProperties config,
- CamelBeanPostProcessor beanPostProcessor) throws Exception {
+ CamelBeanPostProcessor beanPostProcessor,
StartupConditionStrategy startup) throws Exception {
Clock clock = new ResetableClock();
CamelContext camelContext = new
SpringBootCamelContext(applicationContext,
config.getSpringboot().isWarnOnEarlyShutdown());
@@ -105,6 +109,8 @@ public class CamelAutoConfiguration {
// bean post processor is created before CamelContext
beanPostProcessor.setCamelContext(camelContext);
camelContext.getCamelContextExtension().addContextPlugin(CamelBeanPostProcessor.class,
beanPostProcessor);
+ // startup condition is created before CamelContext
+
camelContext.getCamelContextExtension().addContextPlugin(StartupConditionStrategy.class,
startup);
return doConfigureCamelContext(applicationContext, camelContext,
config);
}
@@ -112,7 +118,7 @@ public class CamelAutoConfiguration {
* Not to be used by Camel end users
*/
public static CamelContext doConfigureCamelContext(ApplicationContext
applicationContext, CamelContext camelContext,
- CamelConfigurationProperties config) throws Exception {
+
CamelConfigurationProperties config) throws Exception {
// setup startup recorder before building context
configureStartupRecorder(camelContext, config);
@@ -185,7 +191,7 @@ public class CamelAutoConfiguration {
new FatJarPackageScanResourceResolver());
if (config.getMain().getRouteFilterIncludePattern() != null
- || config.getMain().getRouteFilterExcludePattern() != null) {
+ || config.getMain().getRouteFilterExcludePattern() != null) {
LOG.info("Route filtering pattern: include={}, exclude={}",
config.getMain().getRouteFilterIncludePattern(),
config.getMain().getRouteFilterExcludePattern());
camelContext.getCamelContextExtension().getContextPlugin(Model.class).setRouteFilterPattern(
@@ -244,7 +250,7 @@ public class CamelAutoConfiguration {
} else if ("logging".equals(config.getMain().getStartupRecorder())) {
camelContext.getCamelContextExtension().setStartupStepRecorder(new
LoggingStartupStepRecorder());
} else if
("java-flight-recorder".equals(config.getMain().getStartupRecorder())
- || config.getMain().getStartupRecorder() == null) {
+ || config.getMain().getStartupRecorder() == null) {
// try to auto discover camel-jfr to use
StartupStepRecorder fr =
camelContext.getCamelContextExtension().getBootstrapFactoryFinder()
.newInstance(StartupStepRecorder.FACTORY,
StartupStepRecorder.class).orElse(null);
@@ -261,7 +267,7 @@ public class CamelAutoConfiguration {
@Bean
CamelSpringBootApplicationController
applicationController(ApplicationContext applicationContext,
- CamelContext camelContext) {
+ CamelContext
camelContext) {
return new CamelSpringBootApplicationController(applicationContext,
camelContext);
}
@@ -275,7 +281,7 @@ public class CamelAutoConfiguration {
@Bean
@ConditionalOnMissingBean(CamelSpringBootApplicationListener.class)
CamelSpringBootApplicationListener
routesCollectorListener(ApplicationContext applicationContext,
- CamelConfigurationProperties config, RoutesCollector
routesCollector) {
+
CamelConfigurationProperties config, RoutesCollector routesCollector) {
Collection<CamelContextConfiguration> configurations =
applicationContext
.getBeansOfType(CamelContextConfiguration.class).values();
return new CamelSpringBootApplicationListener(applicationContext, new
ArrayList(configurations), config,
@@ -374,4 +380,26 @@ public class CamelAutoConfiguration {
return new CamelSpringBootBeanPostProcessor(applicationContext);
}
+ /**
+ * Camel startup strategy - used early by Camel
+ */
+ @Bean
+ StartupConditionStrategy
startupConditionStrategy(CamelStartupConditionConfigurationProperties config) {
+ StartupConditionStrategy scs = new DefaultStartupConditionStrategy();
+ scs.setEnabled(config.isEnabled());
+ scs.setInterval(config.getInterval());
+ scs.setTimeout(config.getTimeout());
+ scs.setOnTimeout(config.getOnTimeout());
+ String envExist = config.getEnvironmentVariableExists();
+ if (envExist != null) {
+ scs.addStartupCondition(new EnvStartupCondition(envExist));
+ }
+ String file = config.getFileExists();
+ if (file != null) {
+ scs.addStartupCondition(new FileStartupCondition(file));
+ }
+ scs.addStartupConditions(config.getCustomClassNames());
+ return scs;
+ }
+
}
diff --git
a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelStartupConditionConfigurationProperties.java
b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelStartupConditionConfigurationProperties.java
new file mode 100644
index 00000000000..428dc30899e
--- /dev/null
+++
b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelStartupConditionConfigurationProperties.java
@@ -0,0 +1,119 @@
+/*
+ * 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.spring.boot;
+
+import org.apache.camel.spi.Metadata;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "camel.startupcondition")
+public class CamelStartupConditionConfigurationProperties {
+
+ /**
+ * To enable using startup conditions
+ */
+ private boolean enabled;
+
+ /**
+ * Interval in millis between checking conditions.
+ */
+ private int interval = 500;
+
+ /**
+ * Total timeout (in millis) for all startup conditions.
+ */
+ private int timeout = 20000;
+
+ /**
+ * What action, to do on timeout.
+ *
+ * fail = do not startup, and throw an exception causing camel to fail
stop = do not startup, and stop camel ignore
+ * = log a WARN and continue to startup
+ */
+ @Metadata(defaultValue = "stop", enums = "fail,stop,ignore")
+ private String onTimeout = "stop";
+
+ /**
+ * Wait for an environment variable with the given name to exists before
continuing
+ */
+ private String environmentVariableExists;
+
+ /**
+ * Wait for a file with the given name to exists before continuing
+ */
+ private String fileExists;
+
+ /**
+ * A list of custom class names (FQN). Multiple classes can be separated
by comma.
+ */
+ private String customClassNames;
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public int getInterval() {
+ return interval;
+ }
+
+ public void setInterval(int interval) {
+ this.interval = interval;
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ public String getOnTimeout() {
+ return onTimeout;
+ }
+
+ public void setOnTimeout(String onTimeout) {
+ this.onTimeout = onTimeout;
+ }
+
+ public String getEnvironmentVariableExists() {
+ return environmentVariableExists;
+ }
+
+ public void setEnvironmentVariableExists(String environmentVariableExists)
{
+ this.environmentVariableExists = environmentVariableExists;
+ }
+
+ public String getFileExists() {
+ return fileExists;
+ }
+
+ public void setFileExists(String fileExists) {
+ this.fileExists = fileExists;
+ }
+
+ public String getCustomClassNames() {
+ return customClassNames;
+ }
+
+ public void setCustomClassNames(String customClassNames) {
+ this.customClassNames = customClassNames;
+ }
+}
diff --git
a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelStartupConditionEnvTest.java
b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelStartupConditionEnvTest.java
new file mode 100644
index 00000000000..e6a90b1b0b7
--- /dev/null
+++
b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelStartupConditionEnvTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.spring.boot;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.support.startup.EnvStartupCondition;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DirtiesContext
+@CamelSpringBootTest
+@EnableAutoConfiguration
+@SpringBootTest(properties = {"camel.startupcondition.enabled=true",
"camel.startupcondition.interval=10",
"camel.startupcondition.customClassNames=org.apache.camel.spring.boot.CamelStartupConditionEnvTest$MyEnvCondition"})
+public class CamelStartupConditionEnvTest {
+
+ private static final AtomicInteger COUNTER = new AtomicInteger();
+
+ private CamelStartupConditionEnvTest() {
+ }
+
+ public static CamelStartupConditionEnvTest
createCamelStartupConditionEnvTest() {
+ return new CamelStartupConditionEnvTest();
+ }
+
+ @Configuration
+ static class Config {
+ @Bean
+ RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:foo").to("mock:foo");
+ }
+ };
+ }
+
+ }
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Autowired
+ ProducerTemplate producerTemplate;
+
+ @Test
+ public void testCustomCondition() throws Exception {
+ Assertions.assertEquals(3, COUNTER.get());
+ }
+
+ public static class MyEnvCondition extends EnvStartupCondition {
+
+ public MyEnvCondition() {
+ super("MY_ENV");
+ }
+
+ @Override
+ protected String lookupEnvironmentVariable(String env) {
+ if (COUNTER.incrementAndGet() < 3) {
+ return null;
+ }
+ return "FOO";
+ }
+ }
+
+}