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 <claus.ib...@gmail.com>
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";
+        }
+    }
+
+}

Reply via email to