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 80b6541d6cab..85836fd4ea6b 100644 --- a/core/camel-spring-boot/src/main/docs/spring-boot.json +++ b/core/camel-spring-boot/src/main/docs/spring-boot.json @@ -1208,10 +1208,10 @@ }, { "name": "camel.routecontroller.back-off-delay", - "type": "java.lang.Long", - "description": "Backoff delay in millis when restarting a route that failed to startup.", + "type": "java.time.Duration", + "description": "Backoff delay when restarting a route that failed to startup. Plain numbers are treated as milliseconds.", "sourceType": "org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerConfiguration", - "defaultValue": 2000 + "defaultValue": "2000ms" }, { "name": "camel.routecontroller.back-off-max-attempts", @@ -1222,17 +1222,15 @@ }, { "name": "camel.routecontroller.back-off-max-delay", - "type": "java.lang.Long", - "description": "Backoff maximum delay in millis when restarting a route that failed to startup.", - "sourceType": "org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerConfiguration", - "defaultValue": 0 + "type": "java.time.Duration", + "description": "Backoff maximum delay when restarting a route that failed to startup. Plain numbers are treated as milliseconds.", + "sourceType": "org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerConfiguration" }, { "name": "camel.routecontroller.back-off-max-elapsed-time", - "type": "java.lang.Long", - "description": "Backoff maximum elapsed time in millis, after which the backoff should be considered exhausted and no more attempts should be made.", - "sourceType": "org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerConfiguration", - "defaultValue": 0 + "type": "java.time.Duration", + "description": "Backoff maximum elapsed time, after which the backoff should be considered exhausted and no more attempts should be made. Plain numbers are treated as milliseconds.", + "sourceType": "org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerConfiguration" }, { "name": "camel.routecontroller.back-off-multiplier", @@ -1262,10 +1260,9 @@ }, { "name": "camel.routecontroller.initial-delay", - "type": "java.lang.Long", - "description": "Initial delay in milli seconds before the route controller starts, after CamelContext has been started.", - "sourceType": "org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerConfiguration", - "defaultValue": 0 + "type": "java.time.Duration", + "description": "Initial delay before the route controller starts, after CamelContext has been started. Plain numbers are treated as milliseconds.", + "sourceType": "org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerConfiguration" }, { "name": "camel.routecontroller.thread-pool-size", @@ -1473,10 +1470,10 @@ }, { "name": "camel.startupcondition.interval", - "type": "java.lang.Integer", - "description": "Interval in millis between checking conditions.", + "type": "java.time.Duration", + "description": "Interval between checking conditions. Plain numbers are treated as milliseconds.", "sourceType": "org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties", - "defaultValue": 500 + "defaultValue": "500ms" }, { "name": "camel.startupcondition.on-timeout", @@ -1487,10 +1484,10 @@ }, { "name": "camel.startupcondition.timeout", - "type": "java.lang.Integer", - "description": "Total timeout (in millis) for all startup conditions.", + "type": "java.time.Duration", + "description": "Total timeout for all startup conditions. Plain numbers are treated as milliseconds.", "sourceType": "org.apache.camel.spring.boot.CamelStartupConditionConfigurationProperties", - "defaultValue": 20000 + "defaultValue": "20000ms" }, { "name": "camel.threadpool.allow-core-thread-time-out", @@ -2036,6 +2033,19 @@ "description": "Specify the username to access IBM Event Stream", "sourceType": "org.apache.camel.spring.boot.vault.IBMVaultConfigurationProperties" }, + { + "name": "camel.vault.ibm.refresh-enabled", + "type": "java.lang.Boolean", + "description": "Whether to automatically refresh the secrets on update", + "sourceType": "org.apache.camel.spring.boot.vault.IBMVaultConfigurationProperties", + "defaultValue": false + }, + { + "name": "camel.vault.ibm.secrets", + "type": "java.lang.String", + "description": "Define the secrets to look at", + "sourceType": "org.apache.camel.spring.boot.vault.IBMVaultConfigurationProperties" + }, { "name": "camel.vault.ibm.service-url", "type": "java.lang.String", 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 7dcb59651945..28f902447e55 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 @@ -482,8 +482,8 @@ CamelBeanPostProcessor camelBeanPostProcessor(ApplicationContext applicationCont StartupConditionStrategy startupConditionStrategy(CamelStartupConditionConfigurationProperties config) { StartupConditionStrategy scs = new DefaultStartupConditionStrategy(); scs.setEnabled(config.isEnabled()); - scs.setInterval(config.getInterval()); - scs.setTimeout(config.getTimeout()); + scs.setInterval(Math.toIntExact(config.getInterval().toMillis())); + scs.setTimeout(Math.toIntExact(config.getTimeout().toMillis())); scs.setOnTimeout(config.getOnTimeout()); String envExist = config.getEnvironmentVariableExists(); if (envExist != null) { diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelMainRunController.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelMainRunController.java index e146adfd2d07..4a4e7a63ef81 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelMainRunController.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelMainRunController.java @@ -17,12 +17,9 @@ package org.apache.camel.spring.boot; import org.apache.camel.CamelContext; -import org.apache.camel.main.MainListener; import org.apache.camel.main.MainShutdownStrategy; import org.springframework.context.ApplicationContext; -import java.util.Map; - /** * Controller to keep the main running and perform graceful shutdown when the JVM is stopped. */ @@ -32,15 +29,12 @@ public class CamelMainRunController { private final Thread daemon; public CamelMainRunController(ApplicationContext applicationContext, CamelContext camelContext) { - controller = new CamelSpringBootApplicationController(applicationContext); + // do not register the MainListener beans on this controller: they are already notified + // via the controller created by CamelAutoConfiguration, and this Main is only used + // to keep the JVM running + controller = new CamelSpringBootApplicationController(applicationContext, false); controller.setCamelContext(camelContext); - // setup main listeners eager on controller - final Map listeners = applicationContext.getBeansOfType(MainListener.class); - for (MainListener listener : listeners.values()) { - controller.getMain().addMainListener(listener); - } - daemon = new Thread(new DaemonTask(), "CamelMainRunController"); } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationController.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationController.java index 859f332fb61d..b157f48164e3 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationController.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationController.java @@ -37,11 +37,24 @@ public class CamelSpringBootApplicationController implements CamelContextAware { private CamelContext camelContext; public CamelSpringBootApplicationController(final ApplicationContext applicationContext) { + this(applicationContext, true); + } + + /** + * @param registerMainListeners whether to register the {@link MainListener} beans from the application context on + * the internal {@link Main}. The controller used by the main run controller must not + * register them, as the listeners are already notified via the controller created by + * {@link CamelAutoConfiguration}, and registering them on both would notify each + * listener twice. + */ + CamelSpringBootApplicationController(final ApplicationContext applicationContext, boolean registerMainListeners) { this.main = new CamelSpringMain(applicationContext, this); - // inject main listeners - final Map listeners = applicationContext.getBeansOfType(MainListener.class); - for (MainListener listener : listeners.values()) { - this.main.addMainListener(listener); + if (registerMainListeners) { + // inject main listeners + final Map listeners = applicationContext.getBeansOfType(MainListener.class); + for (MainListener listener : listeners.values()) { + this.main.addMainListener(listener); + } } } 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 index 428dc30899e3..ce69a060d243 100644 --- 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 @@ -16,8 +16,12 @@ */ package org.apache.camel.spring.boot; +import java.time.Duration; +import java.time.temporal.ChronoUnit; + import org.apache.camel.spi.Metadata; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.convert.DurationUnit; @ConfigurationProperties(prefix = "camel.startupcondition") public class CamelStartupConditionConfigurationProperties { @@ -28,14 +32,16 @@ public class CamelStartupConditionConfigurationProperties { private boolean enabled; /** - * Interval in millis between checking conditions. + * Interval between checking conditions. Plain numbers are treated as milliseconds. */ - private int interval = 500; + @DurationUnit(ChronoUnit.MILLIS) + private Duration interval = Duration.ofMillis(500); /** - * Total timeout (in millis) for all startup conditions. + * Total timeout for all startup conditions. Plain numbers are treated as milliseconds. */ - private int timeout = 20000; + @DurationUnit(ChronoUnit.MILLIS) + private Duration timeout = Duration.ofMillis(20000); /** * What action, to do on timeout. @@ -69,19 +75,19 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public int getInterval() { + public Duration getInterval() { return interval; } - public void setInterval(int interval) { + public void setInterval(Duration interval) { this.interval = interval; } - public int getTimeout() { + public Duration getTimeout() { return timeout; } - public void setTimeout(int timeout) { + public void setTimeout(Duration timeout) { this.timeout = timeout; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/console/CamelDevConsoleAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/console/CamelDevConsoleAutoConfiguration.java index 0ae35238ece4..d5d918be5f88 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/console/CamelDevConsoleAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/console/CamelDevConsoleAutoConfiguration.java @@ -19,7 +19,6 @@ import org.apache.camel.CamelContext; import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.spring.boot.actuate.endpoint.CamelRouteControllerEndpoint; -import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerAutoConfiguration.java index b9652cbbc9aa..ed9b9d567105 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerAutoConfiguration.java @@ -30,13 +30,13 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @AutoConfiguration(before = CamelAutoConfiguration.class) -@ConditionalOnProperty(prefix = "camel.clustered.controller", name = "enabled") +@ConditionalOnBooleanProperty("camel.clustered.controller.enabled") @EnableConfigurationProperties(ClusteredRouteControllerConfiguration.class) public class ClusteredRouteControllerAutoConfiguration { diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerConfiguration.java index ca32cbd0f097..8d3bf32d47c8 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/cluster/ClusteredRouteControllerConfiguration.java @@ -39,11 +39,6 @@ public class ClusteredRouteControllerConfiguration { */ private String namespace; - /** - * The reference to a cluster service. - */ - private String clusterServiceRef; - /** * The cluster service. */ diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/errorregistry/CamelErrorRegistryAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/errorregistry/CamelErrorRegistryAutoConfiguration.java index 401ca4d9690b..7cd3267a2872 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/errorregistry/CamelErrorRegistryAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/errorregistry/CamelErrorRegistryAutoConfiguration.java @@ -34,10 +34,10 @@ public class CamelErrorRegistryAutoConfiguration { @Bean public ErrorRegistry errorRegistry(CamelContext camelContext, CamelErrorRegistryConfigurationProperties config) { // dev profile enables error registry to capture routing errors for tooling (TUI) - if (!config.isEnabled() && "dev".equals(camelContext.getCamelContextExtension().getProfile())) { - config.setEnabled(true); - } - if (!config.isEnabled()) { + // (do not mutate the shared configuration properties bean) + boolean enabled = config.isEnabled() + || "dev".equals(camelContext.getCamelContextExtension().getProfile()); + if (!enabled) { return null; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerAutoConfiguration.java index cc4717a9310d..f8e169313f2e 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerAutoConfiguration.java @@ -17,58 +17,53 @@ package org.apache.camel.spring.boot.routecontroller; import org.apache.camel.impl.engine.DefaultSupervisingRouteController; -import org.apache.camel.spi.RouteController; import org.apache.camel.spi.SupervisingRouteController; import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @AutoConfiguration(before = CamelAutoConfiguration.class) -@ConditionalOnProperty(prefix = "camel.routecontroller", name = "enabled") +@ConditionalOnBooleanProperty("camel.routecontroller.enabled") @EnableConfigurationProperties(SupervisingRouteControllerConfiguration.class) public class SupervisingRouteControllerAutoConfiguration { @Bean @ConditionalOnMissingBean public SupervisingRouteController supervisingRouteController(SupervisingRouteControllerConfiguration config) { - SupervisingRouteController src = null; - - if (config.isEnabled()) { - // switch to supervising route controller - src = new DefaultSupervisingRouteController(); - if (config.getIncludeRoutes() != null) { - src.setIncludeRoutes(config.getIncludeRoutes()); - } - if (config.getExcludeRoutes() != null) { - src.setExcludeRoutes(config.getExcludeRoutes()); - } - if (config.getThreadPoolSize() > 0) { - src.setThreadPoolSize(config.getThreadPoolSize()); - } - if (config.getBackOffDelay() > 0) { - src.setBackOffDelay(config.getBackOffDelay()); - } - if (config.getInitialDelay() > 0) { - src.setInitialDelay(config.getInitialDelay()); - } - if (config.getBackOffMaxAttempts() > 0) { - src.setBackOffMaxAttempts(config.getBackOffMaxAttempts()); - } - if (config.getBackOffMaxDelay() > 0) { - src.setBackOffMaxDelay(config.getBackOffMaxDelay()); - } - if (config.getBackOffMaxElapsedTime() > 0) { - src.setBackOffMaxElapsedTime(config.getBackOffMaxElapsedTime()); - } - if (config.getBackOffMultiplier() > 0) { - src.setBackOffMultiplier(config.getBackOffMultiplier()); - } - src.setUnhealthyOnExhausted(config.isUnhealthyOnExhausted()); - src.setUnhealthyOnRestarting(config.isUnhealthyOnRestarting()); + // switch to supervising route controller + SupervisingRouteController src = new DefaultSupervisingRouteController(); + if (config.getIncludeRoutes() != null) { + src.setIncludeRoutes(config.getIncludeRoutes()); + } + if (config.getExcludeRoutes() != null) { + src.setExcludeRoutes(config.getExcludeRoutes()); + } + if (config.getThreadPoolSize() > 0) { + src.setThreadPoolSize(config.getThreadPoolSize()); + } + if (config.getBackOffDelay() != null && config.getBackOffDelay().toMillis() > 0) { + src.setBackOffDelay(config.getBackOffDelay().toMillis()); + } + if (config.getInitialDelay() != null && config.getInitialDelay().toMillis() > 0) { + src.setInitialDelay(config.getInitialDelay().toMillis()); + } + if (config.getBackOffMaxAttempts() > 0) { + src.setBackOffMaxAttempts(config.getBackOffMaxAttempts()); + } + if (config.getBackOffMaxDelay() != null && config.getBackOffMaxDelay().toMillis() > 0) { + src.setBackOffMaxDelay(config.getBackOffMaxDelay().toMillis()); + } + if (config.getBackOffMaxElapsedTime() != null && config.getBackOffMaxElapsedTime().toMillis() > 0) { + src.setBackOffMaxElapsedTime(config.getBackOffMaxElapsedTime().toMillis()); + } + if (config.getBackOffMultiplier() > 0) { + src.setBackOffMultiplier(config.getBackOffMultiplier()); } + src.setUnhealthyOnExhausted(config.isUnhealthyOnExhausted()); + src.setUnhealthyOnRestarting(config.isUnhealthyOnRestarting()); return src; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerConfiguration.java index 14269d03cdd4..fc7875349eb3 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/routecontroller/SupervisingRouteControllerConfiguration.java @@ -16,8 +16,12 @@ */ package org.apache.camel.spring.boot.routecontroller; +import java.time.Duration; +import java.time.temporal.ChronoUnit; + import org.apache.camel.spi.Metadata; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.convert.DurationUnit; @ConfigurationProperties(prefix = "camel.routecontroller") public class SupervisingRouteControllerConfiguration { @@ -42,26 +46,32 @@ public class SupervisingRouteControllerConfiguration { int threadPoolSize = 1; /** - * Initial delay in milli seconds before the route controller starts, after CamelContext has been started. + * Initial delay before the route controller starts, after CamelContext has been started. Plain numbers are + * treated as milliseconds. */ - long initialDelay; + @DurationUnit(ChronoUnit.MILLIS) + Duration initialDelay; /** - * Backoff delay in millis when restarting a route that failed to startup. + * Backoff delay when restarting a route that failed to startup. Plain numbers are treated as milliseconds. */ @Metadata(defaultValue = "2000") - long backOffDelay = 2000; + @DurationUnit(ChronoUnit.MILLIS) + Duration backOffDelay = Duration.ofMillis(2000); /** - * Backoff maximum delay in millis when restarting a route that failed to startup. + * Backoff maximum delay when restarting a route that failed to startup. Plain numbers are treated as + * milliseconds. */ - long backOffMaxDelay; + @DurationUnit(ChronoUnit.MILLIS) + Duration backOffMaxDelay; /** - * Backoff maximum elapsed time in millis, after which the backoff should be considered exhausted and no more - * attempts should be made. + * Backoff maximum elapsed time, after which the backoff should be considered exhausted and no more attempts + * should be made. Plain numbers are treated as milliseconds. */ - long backOffMaxElapsedTime; + @DurationUnit(ChronoUnit.MILLIS) + Duration backOffMaxElapsedTime; /** * Backoff maximum number of attempts to restart a route that failed to startup. When this threshold has been @@ -133,35 +143,35 @@ public void setThreadPoolSize(int threadPoolSize) { this.threadPoolSize = threadPoolSize; } - public long getInitialDelay() { + public Duration getInitialDelay() { return initialDelay; } - public void setInitialDelay(long initialDelay) { + public void setInitialDelay(Duration initialDelay) { this.initialDelay = initialDelay; } - public long getBackOffDelay() { + public Duration getBackOffDelay() { return backOffDelay; } - public void setBackOffDelay(long backOffDelay) { + public void setBackOffDelay(Duration backOffDelay) { this.backOffDelay = backOffDelay; } - public long getBackOffMaxDelay() { + public Duration getBackOffMaxDelay() { return backOffMaxDelay; } - public void setBackOffMaxDelay(long backOffMaxDelay) { + public void setBackOffMaxDelay(Duration backOffMaxDelay) { this.backOffMaxDelay = backOffMaxDelay; } - public long getBackOffMaxElapsedTime() { + public Duration getBackOffMaxElapsedTime() { return backOffMaxElapsedTime; } - public void setBackOffMaxElapsedTime(long backOffMaxElapsedTime) { + public void setBackOffMaxElapsedTime(Duration backOffMaxElapsedTime) { this.backOffMaxElapsedTime = backOffMaxElapsedTime; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java index 909287d45c7e..5fc7414c1875 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java @@ -51,14 +51,17 @@ SecurityPolicyResult camelSecurityPolicyResult(CamelContext camelContext, CamelSecurityPolicyConfigurationProperties config, Environment environment) { // apply profile-based security defaults + // (do not mutate the shared configuration properties bean) String profile = camelContext.getCamelContextExtension().getProfile(); - if ("dev".equals(profile) && config.getInsecureDevPolicy() == null) { - config.setInsecureDevPolicy("allow"); - } else if ("prod".equals(profile) && "warn".equals(config.getPolicy())) { - config.setPolicy("fail"); + String policy = config.getPolicy(); + String insecureDevPolicy = config.getInsecureDevPolicy(); + if ("dev".equals(profile) && insecureDevPolicy == null) { + insecureDevPolicy = "allow"; + } else if ("prod".equals(profile) && "warn".equals(policy)) { + policy = "fail"; } - SecurityConfigurationProperties securityConfig = applySecurityProperties(camelContext, config); + SecurityConfigurationProperties securityConfig = applySecurityProperties(config, policy, insecureDevPolicy); Map camelProperties = extractCamelProperties(environment); @@ -74,14 +77,14 @@ SecurityPolicyResult camelSecurityPolicyResult(CamelContext camelContext, return result; } - private SecurityConfigurationProperties applySecurityProperties(CamelContext camelContext, - CamelSecurityPolicyConfigurationProperties config) { + private SecurityConfigurationProperties applySecurityProperties(CamelSecurityPolicyConfigurationProperties config, + String policy, String insecureDevPolicy) { // get the security config from camel-main's MainConfigurationProperties // which is already bound by CamelAutoConfiguration via CamelConfigurationProperties SecurityConfigurationProperties securityConfig = new SecurityConfigurationProperties(null); - securityConfig.setPolicy(config.getPolicy()); + securityConfig.setPolicy(policy); if (config.getSecretPolicy() != null) { securityConfig.setSecretPolicy(config.getSecretPolicy()); } @@ -91,8 +94,8 @@ private SecurityConfigurationProperties applySecurityProperties(CamelContext cam if (config.getInsecureSerializationPolicy() != null) { securityConfig.setInsecureSerializationPolicy(config.getInsecureSerializationPolicy()); } - if (config.getInsecureDevPolicy() != null) { - securityConfig.setInsecureDevPolicy(config.getInsecureDevPolicy()); + if (insecureDevPolicy != null) { + securityConfig.setInsecureDevPolicy(insecureDevPolicy); } if (config.getAllowedProperties() != null) { securityConfig.setAllowedProperties(config.getAllowedProperties()); diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/trace/CamelTraceAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/trace/CamelTraceAutoConfiguration.java index 9c03a19d5ba2..c3f3c1ac6c90 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/trace/CamelTraceAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/trace/CamelTraceAutoConfiguration.java @@ -33,10 +33,10 @@ public class CamelTraceAutoConfiguration { public BacklogTracer backlogTracer(CamelContext camelContext, CamelTraceConfigurationProperties config) throws Exception { // dev profile enables tracer standby so tooling (TUI) can activate tracing on demand - if (!config.isStandby() && "dev".equals(camelContext.getCamelContextExtension().getProfile())) { - config.setStandby(true); - } - if (!config.isEnabled() && !config.isStandby()) { + // (do not mutate the shared configuration properties bean) + boolean standby = config.isStandby() + || "dev".equals(camelContext.getCamelContextExtension().getProfile()); + if (!config.isEnabled() && !standby) { return null; } @@ -45,12 +45,12 @@ public BacklogTracer backlogTracer(CamelContext camelContext, CamelTraceConfigur // enable tracer on camel camelContext.setBacklogTracing(config.isEnabled()); - camelContext.setBacklogTracingStandby(config.isStandby()); + camelContext.setBacklogTracingStandby(standby); camelContext.setBacklogTracingTemplates(config.isTraceTemplates()); BacklogTracer tracer = org.apache.camel.impl.debugger.BacklogTracer.createTracer(camelContext); tracer.setEnabled(config.isEnabled()); - tracer.setStandby(config.isStandby()); + tracer.setStandby(standby); tracer.setBacklogSize(config.getBacklogSize()); tracer.setRemoveOnDump(config.isRemoveOnDump()); tracer.setBodyMaxChars(config.getBodyMaxChars()); diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/CompositeConversionService.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/CompositeConversionService.java deleted file mode 100644 index d649135515b9..000000000000 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/CompositeConversionService.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.util; - -import java.util.List; -import org.springframework.core.convert.ConversionException; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.TypeDescriptor; - -public class CompositeConversionService implements ConversionService { - private final List delegates; - - public CompositeConversionService(List delegates) { - this.delegates = delegates; - } - - @Override - public boolean canConvert(Class sourceType, Class targetType) { - for (ConversionService service : this.delegates) { - if (service.canConvert(sourceType, targetType)) { - return true; - } - } - return false; - } - - @Override - public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) { - for (ConversionService service : this.delegates) { - if (service.canConvert(sourceType, targetType)) { - return true; - } - } - return false; - } - - @Override - public T convert(Object source, Class targetType) { - for (int i = 0; i < this.delegates.size() - 1; i++) { - try { - ConversionService delegate = this.delegates.get(i); - if (delegate.canConvert(source.getClass(), targetType)) { - return delegate.convert(source, targetType); - } - } catch (ConversionException e) { - // ignored - } - } - - return this.delegates.get(this.delegates.size() - 1).convert(source, targetType); - } - - @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { - for (int i = 0; i < this.delegates.size() - 1; i++) { - try { - ConversionService delegate = this.delegates.get(i); - if (delegate.canConvert(sourceType, targetType)) { - return delegate.convert(source, sourceType, targetType); - } - } catch (ConversionException e) { - // ignored - } - } - - return this.delegates.get(this.delegates.size() - 1).convert(source, sourceType, targetType); - } -} diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/HierarchicalCondition.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/HierarchicalCondition.java deleted file mode 100644 index 261f9b149c4a..000000000000 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/HierarchicalCondition.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.util; - -import java.util.Arrays; -import org.springframework.boot.autoconfigure.condition.ConditionMessage; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.env.Environment; -import org.springframework.core.type.AnnotatedTypeMetadata; - -public class HierarchicalCondition extends SpringBootCondition { - private final String[] items; - - public HierarchicalCondition(String... items) { - this.items = Arrays.copyOf(items, items.length); - } - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext conditionContext, - AnnotatedTypeMetadata annotatedTypeMetadata) { - if (items.length == 0) { - return ConditionOutcome.match(ConditionMessage.forCondition("no condition").because("no conditions")); - } - - final ConditionMessage.Builder message = ConditionMessage.forCondition(this.items[0]); - final Environment environment = conditionContext.getEnvironment(); - - return HierarchicalPropertiesEvaluator.evaluate(environment, items) - ? ConditionOutcome.match(message.because("enabled")) - : ConditionOutcome.noMatch(message.because("not enabled")); - } -} diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AwsVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AwsVaultAutoConfiguration.java index 843bd0340037..88c8327bee20 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AwsVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AwsVaultAutoConfiguration.java @@ -18,6 +18,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.AwsVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -31,19 +32,7 @@ public class AwsVaultAutoConfiguration { @Bean public AwsVaultConfiguration awsVaultConfiguration(AwsVaultConfigurationProperties config) { AwsVaultConfiguration answer = new AwsVaultConfiguration(); - answer.setAccessKey(config.getAccessKey()); - answer.setSecretKey(config.getSecretKey()); - answer.setRegion(config.getRegion()); - answer.setDefaultCredentialsProvider(config.isDefaultCredentialsProvider()); - answer.setProfileCredentialsProvider(config.isProfileCredentialsProvider()); - answer.setProfileName(config.getProfileName()); - answer.setRefreshEnabled(config.isRefreshEnabled()); - answer.setRefreshPeriod(config.getRefreshPeriod()); - answer.setSecrets(config.getSecrets()); - answer.setUseSqsNotification(config.isUseSqsNotification()); - answer.setSqsQueueUrl(config.getSqsQueueUrl()); - answer.setUriEndpointOverride(config.getUriEndpointOverride()); - answer.setOverrideEndpoint(config.isOverrideEndpoint()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AzureVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AzureVaultAutoConfiguration.java index 4e6874704430..c7c859a8d804 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AzureVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/AzureVaultAutoConfiguration.java @@ -18,6 +18,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.AzureVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -31,18 +32,7 @@ public class AzureVaultAutoConfiguration { @Bean public AzureVaultConfiguration azureVaultConfiguration(AzureVaultConfigurationProperties config) { AzureVaultConfiguration answer = new AzureVaultConfiguration(); - answer.setClientId(config.getClientId()); - answer.setClientSecret(config.getClientSecret()); - answer.setVaultName(config.getVaultName()); - answer.setTenantId(config.getTenantId()); - answer.setAzureIdentityEnabled(config.isAzureIdentityEnabled()); - answer.setRefreshEnabled(config.isRefreshEnabled()); - answer.setRefreshPeriod(config.getRefreshPeriod()); - answer.setSecrets(config.getSecrets()); - answer.setEventhubConnectionString(config.getEventhubConnectionString()); - answer.setBlobAccessKey(config.getBlobAccessKey()); - answer.setBlobAccountName(config.getBlobAccountName()); - answer.setBlobContainerName(config.getBlobContainerName()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/CyberArkVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/CyberArkVaultAutoConfiguration.java index 7055aad6da25..4d86ee4c2364 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/CyberArkVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/CyberArkVaultAutoConfiguration.java @@ -18,6 +18,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.CyberArkVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -31,15 +32,7 @@ public class CyberArkVaultAutoConfiguration { @Bean public CyberArkVaultConfiguration cyberarkVaultConfiguration(CyberArkVaultConfigurationProperties config) { CyberArkVaultConfiguration answer = new CyberArkVaultConfiguration(); - answer.setUrl(config.getUrl()); - answer.setAccount(config.getAccount()); - answer.setUsername(config.getUsername()); - answer.setPassword(config.getPassword()); - answer.setApiKey(config.getApiKey()); - answer.setAuthToken(config.getAuthToken()); - answer.setVerifySsl(config.isVerifySsl()); - answer.setCertificatePath(config.getCertificatePath()); - answer.setSecrets(config.getSecrets()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/GcpVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/GcpVaultAutoConfiguration.java index f13e654fb2f9..260e2fcd074e 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/GcpVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/GcpVaultAutoConfiguration.java @@ -18,6 +18,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.GcpVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -31,13 +32,7 @@ public class GcpVaultAutoConfiguration { @Bean public GcpVaultConfiguration gcpVaultConfiguration(GcpVaultConfigurationProperties config) { GcpVaultConfiguration answer = new GcpVaultConfiguration(); - answer.setServiceAccountKey(config.getServiceAccountKey()); - answer.setProjectId(config.getProjectId()); - answer.setUseDefaultInstance(config.isUseDefaultInstance()); - answer.setRefreshEnabled(config.isRefreshEnabled()); - answer.setRefreshPeriod(config.getRefreshPeriod()); - answer.setSecrets(config.getSecrets()); - answer.setSubscriptionName(config.getSubscriptionName()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/HashicorpVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/HashicorpVaultAutoConfiguration.java index 1165a6505100..603ac58d1703 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/HashicorpVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/HashicorpVaultAutoConfiguration.java @@ -18,6 +18,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.HashicorpVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -31,15 +32,7 @@ public class HashicorpVaultAutoConfiguration { @Bean public HashicorpVaultConfiguration hashicorpVaultConfiguration(HashicorpVaultConfigurationProperties config) { HashicorpVaultConfiguration answer = new HashicorpVaultConfiguration(); - answer.setToken(config.getToken()); - answer.setHost(config.getHost()); - answer.setPort(config.getPort()); - answer.setScheme(config.getScheme()); - answer.setCloud(config.isCloud()); - answer.setNamespace(config.getNamespace()); - answer.setRefreshEnabled(config.isRefreshEnabled()); - answer.setRefreshPeriod(config.getRefreshPeriod()); - answer.setSecrets(config.getSecrets()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultAutoConfiguration.java index 5ed5263b8038..edca703c5d82 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultAutoConfiguration.java @@ -18,6 +18,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.IBMSecretsManagerVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -31,14 +32,7 @@ public class IBMVaultAutoConfiguration { @Bean public IBMSecretsManagerVaultConfiguration ibmSecretsManagerVaultConfiguration(IBMVaultConfigurationProperties config) { IBMSecretsManagerVaultConfiguration answer = new IBMSecretsManagerVaultConfiguration(); - answer.setToken(config.getToken()); - answer.setServiceUrl(config.getServiceUrl()); - answer.setEventStreamTopic(config.getEventStreamTopic()); - answer.setEventStreamBootstrapServers(config.getEventStreamBootstrapServers()); - answer.setEventStreamUsername(config.getEventStreamUsername()); - answer.setEventStreamPassword(config.getEventStreamPassword()); - answer.setEventStreamGroupId(config.getEventStreamGroupId()); - answer.setEventStreamConsumerPollTimeout(config.getEventStreamConsumerPollTimeout()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultConfigurationProperties.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultConfigurationProperties.java index c637c5ed5a51..51cbfcb4434a 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultConfigurationProperties.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/IBMVaultConfigurationProperties.java @@ -63,6 +63,32 @@ public class IBMVaultConfigurationProperties { */ private long eventStreamConsumerPollTimeout = 3000; + /** + * Whether to automatically refresh the secrets on update + */ + private boolean refreshEnabled; + + /** + * Define the secrets to look at + */ + private String secrets; + + public boolean isRefreshEnabled() { + return refreshEnabled; + } + + public void setRefreshEnabled(boolean refreshEnabled) { + this.refreshEnabled = refreshEnabled; + } + + public String getSecrets() { + return secrets; + } + + public void setSecrets(String secrets) { + this.secrets = secrets; + } + public String getToken() { return token; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesConfigMapVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesConfigMapVaultAutoConfiguration.java index 8f25ba71d90d..44e8d1fcf9a9 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesConfigMapVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesConfigMapVaultAutoConfiguration.java @@ -19,6 +19,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.KubernetesConfigMapVaultConfiguration; import org.apache.camel.vault.KubernetesVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -32,8 +33,7 @@ public class KubernetesConfigMapVaultAutoConfiguration { @Bean public KubernetesConfigMapVaultConfiguration kubernetesConfigMapVaultConfiguration(KubernetesConfigMapVaultConfigurationProperties config) { KubernetesConfigMapVaultConfiguration answer = new KubernetesConfigMapVaultConfiguration(); - answer.setRefreshEnabled(config.isRefreshEnabled()); - answer.setConfigmaps(config.getConfigmaps()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesVaultAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesVaultAutoConfiguration.java index e211914765aa..fcb5d4faec75 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesVaultAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/vault/KubernetesVaultAutoConfiguration.java @@ -18,6 +18,7 @@ import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.apache.camel.vault.KubernetesVaultConfiguration; +import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -31,8 +32,7 @@ public class KubernetesVaultAutoConfiguration { @Bean public KubernetesVaultConfiguration kubernetesVaultConfiguration(KubernetesVaultConfigurationProperties config) { KubernetesVaultConfiguration answer = new KubernetesVaultConfiguration(); - answer.setRefreshEnabled(config.isRefreshEnabled()); - answer.setSecrets(config.getSecrets()); + BeanUtils.copyProperties(config, answer); return answer; } diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelMainListenerRunControllerTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelMainListenerRunControllerTest.java new file mode 100644 index 000000000000..c7d377e57831 --- /dev/null +++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelMainListenerRunControllerTest.java @@ -0,0 +1,155 @@ +/* + * 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 java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.main.BaseMainSupport; +import org.apache.camel.main.MainListener; +import org.apache.camel.main.MainListenerSupport; +import org.apache.camel.test.spring.junit6.CamelSpringBootTest; +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 static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Verifies that a {@link MainListener} bean receives each lifecycle callback exactly once when the main run + * controller is enabled (camel.main.run-controller=true). + */ +@DirtiesContext +@CamelSpringBootTest +@EnableAutoConfiguration +@SpringBootTest(properties = "camel.main.run-controller=true") +public class CamelMainListenerRunControllerTest { + + @Configuration + static class Config { + + @Bean + RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start").to("mock:result"); + } + }; + } + + @Bean + CountingMainListener countingMainListener() { + return new CountingMainListener(); + } + + } + + @Autowired + CamelContext camelContext; + + @Autowired + CountingMainListener listener; + + @Test + public void testMainListenerCallbacksFireExactlyOnce() { + // the run controller notifies listeners from a background daemon thread, + // so wait until the start phase has completed + await().atMost(20, TimeUnit.SECONDS) + .untilAsserted(() -> assertTrue(listener.count("afterStart") >= 1, + "afterStart should have been invoked")); + + // the counts must remain exactly 1 (hold for a while to catch late duplicate notifications + // from the run controller background thread) + await().during(2, TimeUnit.SECONDS).atMost(10, TimeUnit.SECONDS) + .untilAsserted(() -> { + assertEquals(1, listener.count("beforeInitialize"), () -> "beforeInitialize: " + listener.counts); + assertEquals(1, listener.count("beforeConfigure"), () -> "beforeConfigure: " + listener.counts); + assertEquals(1, listener.count("afterConfigure"), () -> "afterConfigure: " + listener.counts); + assertEquals(1, listener.count("beforeStart"), () -> "beforeStart: " + listener.counts); + assertEquals(1, listener.count("afterStart"), () -> "afterStart: " + listener.counts); + }); + + camelContext.stop(); + + await().during(2, TimeUnit.SECONDS).atMost(10, TimeUnit.SECONDS) + .untilAsserted(() -> { + assertEquals(1, listener.count("beforeStop"), () -> "beforeStop: " + listener.counts); + assertEquals(1, listener.count("afterStop"), () -> "afterStop: " + listener.counts); + }); + } + + public static class CountingMainListener extends MainListenerSupport { + + private final Map counts = new ConcurrentHashMap<>(); + + int count(String callback) { + AtomicInteger counter = counts.get(callback); + return counter != null ? counter.get() : 0; + } + + private void record(String callback) { + counts.computeIfAbsent(callback, k -> new AtomicInteger()).incrementAndGet(); + } + + @Override + public void beforeInitialize(BaseMainSupport main) { + record("beforeInitialize"); + } + + @Override + public void beforeConfigure(BaseMainSupport main) { + record("beforeConfigure"); + } + + @Override + public void afterConfigure(BaseMainSupport main) { + record("afterConfigure"); + } + + @Override + public void beforeStart(BaseMainSupport main) { + record("beforeStart"); + } + + @Override + public void afterStart(BaseMainSupport main) { + record("afterStart"); + } + + @Override + public void beforeStop(BaseMainSupport main) { + record("beforeStop"); + } + + @Override + public void afterStop(BaseMainSupport main) { + record("afterStop"); + } + } + +} diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/vault/VaultConfigurationPropertiesMappingTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/vault/VaultConfigurationPropertiesMappingTest.java new file mode 100644 index 000000000000..c83ead470d95 --- /dev/null +++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/vault/VaultConfigurationPropertiesMappingTest.java @@ -0,0 +1,96 @@ +/* + * 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.vault; + +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import org.apache.camel.vault.AwsVaultConfiguration; +import org.apache.camel.vault.AzureVaultConfiguration; +import org.apache.camel.vault.CyberArkVaultConfiguration; +import org.apache.camel.vault.GcpVaultConfiguration; +import org.apache.camel.vault.HashicorpVaultConfiguration; +import org.apache.camel.vault.IBMSecretsManagerVaultConfiguration; +import org.apache.camel.vault.KubernetesConfigMapVaultConfiguration; +import org.apache.camel.vault.KubernetesVaultConfiguration; +import org.apache.camel.vault.VaultConfiguration; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +/** + * Guards against drift between the Camel core vault configurations and the corresponding Spring Boot + * {@code camel.vault.*} configuration properties classes. + * + * The vault auto-configurations copy the Spring Boot properties onto the Camel configuration with + * {@link org.springframework.beans.BeanUtils#copyProperties(Object, Object)}, which matches properties by name and + * type. When a vault option is added to Camel core, this test fails until the matching property (same name and type) + * is added to the starter properties class, so the option stays configurable from Spring Boot. + */ +public class VaultConfigurationPropertiesMappingTest { + + static Stream vaultPairs() { + return Stream.of( + arguments(AwsVaultConfiguration.class, AwsVaultConfigurationProperties.class), + arguments(AzureVaultConfiguration.class, AzureVaultConfigurationProperties.class), + arguments(GcpVaultConfiguration.class, GcpVaultConfigurationProperties.class), + arguments(HashicorpVaultConfiguration.class, HashicorpVaultConfigurationProperties.class), + arguments(KubernetesVaultConfiguration.class, KubernetesVaultConfigurationProperties.class), + arguments(KubernetesConfigMapVaultConfiguration.class, + KubernetesConfigMapVaultConfigurationProperties.class), + arguments(IBMSecretsManagerVaultConfiguration.class, IBMVaultConfigurationProperties.class), + arguments(CyberArkVaultConfiguration.class, CyberArkVaultConfigurationProperties.class)); + } + + @ParameterizedTest + @MethodSource("vaultPairs") + void starterExposesAllCamelVaultOptions(Class camelConfiguration, Class starterProperties) throws Exception { + Map starter = new HashMap<>(); + for (PropertyDescriptor pd : Introspector.getBeanInfo(starterProperties, Object.class) + .getPropertyDescriptors()) { + starter.put(pd.getName(), pd); + } + + List missing = new ArrayList<>(); + // only the options declared on the concrete configuration class, not the + // per-provider sub-configurations inherited from VaultConfiguration + for (PropertyDescriptor pd : Introspector.getBeanInfo(camelConfiguration, VaultConfiguration.class) + .getPropertyDescriptors()) { + if (pd.getWriteMethod() == null || pd.getReadMethod() == null) { + continue; + } + PropertyDescriptor sp = starter.get(pd.getName()); + if (sp == null || sp.getReadMethod() == null || sp.getWriteMethod() == null + || !sp.getPropertyType().equals(pd.getPropertyType())) { + missing.add(pd.getName() + " (" + pd.getPropertyType().getSimpleName() + ")"); + } + } + + assertTrue(missing.isEmpty(), + () -> camelConfiguration.getSimpleName() + " options not configurable via " + + starterProperties.getSimpleName() + " (add the missing properties): " + missing); + } + +} diff --git a/pom.xml b/pom.xml index 395156c1d1ff..0482504ebdb6 100644 --- a/pom.xml +++ b/pom.xml @@ -172,6 +172,10 @@ ${jdk.version} 512M ${compiler.fork} + + full