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.git
commit d2eb4972d0bbf2fcf7f0d5fecd680247a6044e77 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sat Mar 19 00:27:52 2022 +0100 CAMEL-17815: camel-jbang - In modeline mode then eager discover routes and pre-load modeline to allow properties to be used during bootstrap. --- .../camel/impl/engine/DefaultRoutesLoader.java | 6 + .../org/apache/camel/main/BaseMainSupport.java | 124 ++++++++++++++++++++- .../org/apache/camel/main/RoutesConfigurer.java | 71 +++++++----- .../apache/camel/dsl/modeline/PropertyTrait.java | 14 ++- .../java/org/apache/camel/main/KameletMain.java | 2 +- 5 files changed, 186 insertions(+), 31 deletions(-) diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java index f06701f..1d134e3 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java @@ -101,6 +101,12 @@ public class DefaultRoutesLoader extends ServiceSupport implements RoutesLoader, "Cannot find RoutesBuilderLoader in classpath supporting file extension: " + extension); } + if (camelContext.isModeline()) { + ModelineFactory factory = camelContext.adapt(ExtendedCamelContext.class).getModelineFactory(); + // gather resources for modeline + factory.parseModeline(resource); + } + RoutesBuilder builder = loader.loadRoutesBuilder(resource); if (builder != null) { answer.add(builder); diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java index 5004766..0675f31 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java @@ -383,6 +383,13 @@ public abstract class BaseMainSupport extends BaseService { if (mainConfigurationProperties.isAutoConfigurationEnabled()) { autoConfigurationFailFast(camelContext, autoConfiguredProperties); autoConfigurationPropertiesComponent(camelContext, autoConfiguredProperties); + + // eager load properties from modeline by scanning DSL sources and gather properties for auto configuration + if (camelContext.isModeline() || configure().isModeline()) { + autoConfigurationRoutesIncludePattern(camelContext, autoConfiguredProperties); + modelineRoutes(camelContext); + } + autoConfigurationMainConfiguration(camelContext, mainConfigurationProperties, autoConfiguredProperties); } @@ -490,10 +497,32 @@ public abstract class BaseMainSupport extends BaseService { } } + protected void modelineRoutes(CamelContext camelContext) throws Exception { + // then configure and add the routes + RoutesConfigurer configurer = new RoutesConfigurer(); + + if (mainConfigurationProperties.isRoutesCollectorEnabled()) { + configurer.setRoutesCollector(routesCollector); + } + + configurer.setBeanPostProcessor(camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor()); + configurer.setRoutesBuilders(mainConfigurationProperties.getRoutesBuilders()); + configurer.setRoutesBuilderClasses(mainConfigurationProperties.getRoutesBuilderClasses()); + if (mainConfigurationProperties.isBasePackageScanEnabled()) { + // only set the base package if enabled + configurer.setBasePackageScan(mainConfigurationProperties.getBasePackageScan()); + } + configurer.setJavaRoutesExcludePattern(mainConfigurationProperties.getJavaRoutesExcludePattern()); + configurer.setJavaRoutesIncludePattern(mainConfigurationProperties.getJavaRoutesIncludePattern()); + configurer.setRoutesExcludePattern(mainConfigurationProperties.getRoutesExcludePattern()); + configurer.setRoutesIncludePattern(mainConfigurationProperties.getRoutesIncludePattern()); + + configurer.configureModeline(camelContext); + } + protected void configureRoutes(CamelContext camelContext) throws Exception { // then configure and add the routes RoutesConfigurer configurer = new RoutesConfigurer(); - configurer.setmodeline(camelContext.isModeline()); if (mainConfigurationProperties.isRoutesCollectorEnabled()) { configurer.setRoutesCollector(routesCollector); @@ -510,6 +539,7 @@ public abstract class BaseMainSupport extends BaseService { configurer.setJavaRoutesIncludePattern(mainConfigurationProperties.getJavaRoutesIncludePattern()); configurer.setRoutesExcludePattern(mainConfigurationProperties.getRoutesExcludePattern()); configurer.setRoutesIncludePattern(mainConfigurationProperties.getRoutesIncludePattern()); + configurer.configureRoutes(camelContext); } @@ -649,6 +679,96 @@ public abstract class BaseMainSupport extends BaseService { } } + protected void autoConfigurationRoutesIncludePattern( + CamelContext camelContext, Map<String, String> autoConfiguredProperties) + throws Exception { + + Object pattern = getInitialProperties().getProperty("camel.main.routesIncludePattern"); + if (pattern != null) { + mainConfigurationProperties + .setRoutesIncludePattern(CamelContextHelper.parseText(camelContext, pattern.toString())); + autoConfiguredProperties.put("camel.main.routes-include-pattern", pattern.toString()); + } + + // load properties + Properties prop = camelContext.getPropertiesComponent().loadProperties(name -> name.startsWith("camel.")); + LOG.debug("Properties from Camel properties component:"); + for (String key : prop.stringPropertyNames()) { + LOG.debug(" {}={}", key, prop.getProperty(key)); + } + + // special for environment-variable-enabled as we need to know this early before we set all the other options + pattern = prop.remove("camel.main.routesIncludePattern"); + if (pattern == null) { + pattern = prop.remove("camel.main.routes-include-pattern"); + if (pattern != null) { + mainConfigurationProperties.setRoutesIncludePattern( + CamelContextHelper.parseText(camelContext, pattern.toString())); + autoConfiguredProperties.put("camel.main.auto-configuration-environment-variables-enabled", + pattern.toString()); + } + } + // special for system-properties-enabled as we need to know this early before we set all the other options + Object jvmEnabled = prop.remove("camel.main.routesIncludePattern"); + if (jvmEnabled == null) { + jvmEnabled = prop.remove("camel.main.routes-include-pattern"); + if (jvmEnabled != null) { + mainConfigurationProperties.setRoutesIncludePattern( + CamelContextHelper.parseText(camelContext, jvmEnabled.toString())); + autoConfiguredProperties.put("camel.main.routes-include-pattern", + jvmEnabled.toString()); + } + } + + // load properties from ENV (override existing) + Properties propENV = null; + if (mainConfigurationProperties.isAutoConfigurationEnvironmentVariablesEnabled()) { + propENV = helper.loadEnvironmentVariablesAsProperties(new String[] { "camel.main." }); + if (!propENV.isEmpty()) { + prop.putAll(propENV); + LOG.debug("Properties from OS environment variables:"); + for (String key : propENV.stringPropertyNames()) { + LOG.debug(" {}={}", key, propENV.getProperty(key)); + } + } + } + // load properties from JVM (override existing) + Properties propJVM = null; + if (mainConfigurationProperties.isAutoConfigurationSystemPropertiesEnabled()) { + propJVM = helper.loadJvmSystemPropertiesAsProperties(new String[] { "camel.main." }); + if (!propJVM.isEmpty()) { + prop.putAll(propJVM); + LOG.debug("Properties from JVM system properties:"); + for (String key : propJVM.stringPropertyNames()) { + LOG.debug(" {}={}", key, propJVM.getProperty(key)); + } + } + } + + // special for fail-fast as we need to know this early before we set all the other options + pattern = propENV != null ? propENV.remove("camel.main.routesincludepattern") : null; + if (propJVM != null) { + Object val = propJVM.remove("camel.main.routesincludepattern"); + if (val != null) { + pattern = val; + } + } + if (pattern != null) { + mainConfigurationProperties + .setRoutesIncludePattern(CamelContextHelper.parseText(camelContext, pattern.toString())); + } else { + pattern = prop.remove("camel.main.routesIncludePattern"); + if (pattern == null) { + pattern = prop.remove("camel.main.routes-include-pattern"); + } + if (pattern != null) { + mainConfigurationProperties + .setRoutesIncludePattern(CamelContextHelper.parseText(camelContext, pattern.toString())); + autoConfiguredProperties.put("camel.main.routes-include-pattern", pattern.toString()); + } + } + } + /** * Configures CamelContext from the {@link MainConfigurationProperties} properties. */ @@ -1087,11 +1207,9 @@ public abstract class BaseMainSupport extends BaseService { for (String key : keys) { String name = StringHelper.before(key, "."); if ("aws".equalsIgnoreCase(name)) { - // TODO: add more vault providers here target = target.aws(); } if ("gcp".equalsIgnoreCase(name)) { - // TODO: add more vault providers here target = target.gcp(); } // configure all the properties on the vault at once (to ensure they are configured in right order) diff --git a/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java index aad2a68..9e979ef 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java @@ -46,7 +46,6 @@ public class RoutesConfigurer { private CamelBeanPostProcessor beanPostProcessor; private List<RoutesBuilder> routesBuilders; private String basePackageScan; - private boolean modeline; private String routesBuilderClasses; private String javaRoutesExcludePattern; private String javaRoutesIncludePattern; @@ -69,14 +68,6 @@ public class RoutesConfigurer { this.basePackageScan = basePackageScan; } - public boolean ismodeline() { - return modeline; - } - - public void setmodeline(boolean modeline) { - this.modeline = modeline; - } - public String getRoutesBuilderClasses() { return routesBuilderClasses; } @@ -232,22 +223,6 @@ public class RoutesConfigurer { // sort routes according to ordered routes.sort(OrderedComparator.get()); - if (modeline) { - ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class); - ModelineFactory factory = ecc.getModelineFactory(); - List<Resource> resources = new ArrayList<>(); - // gather resources for modeline - for (RoutesBuilder builder : routes) { - if (builder instanceof RouteBuilder) { - resources.add(((RouteBuilder) builder).getResource()); - } - } - for (Resource resource : resources) { - LOG.debug("Parsing modeline: {}", resource); - factory.parseModeline(resource); - } - } - // first add the routes configurations as they are globally for all routes for (RoutesBuilder builder : routes) { if (builder instanceof RouteConfigurationsBuilder) { @@ -263,4 +238,50 @@ public class RoutesConfigurer { } } + /** + * Discover routes and rests from directories and scan for modeline present in their source code, which is then + * parsed using {@link ModelineFactory}. + * + * @param camelContext the Camel context + */ + public void configureModeline(CamelContext camelContext) throws Exception { + final List<RoutesBuilder> routes = new ArrayList<>(); + + if (getRoutesCollector() != null) { + try { + LOG.debug("RoutesCollectorEnabled: {}", getRoutesCollector()); + + // add discovered routes from directories + StopWatch watch = new StopWatch(); + Collection<RoutesBuilder> routesFromDirectory = getRoutesCollector().collectRoutesFromDirectory( + camelContext, + getRoutesExcludePattern(), + getRoutesIncludePattern()); + routes.addAll(routesFromDirectory); + + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeException(e); + } + } + + // sort routes according to ordered + routes.sort(OrderedComparator.get()); + + ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class); + ModelineFactory factory = ecc.getModelineFactory(); + List<Resource> resources = new ArrayList<>(); + // gather resources for modeline + for (RoutesBuilder builder : routes) { + if (builder instanceof RouteBuilder) { + resources.add(((RouteBuilder) builder).getResource()); + } + } + LOG.debug("Discovered {} resources with potential modeline", resources.size()); + + for (Resource resource : resources) { + LOG.debug("Parsing modeline: {}", resource); + factory.parseModeline(resource); + } + } + } diff --git a/dsl/camel-dsl-modeline/src/main/java/org/apache/camel/dsl/modeline/PropertyTrait.java b/dsl/camel-dsl-modeline/src/main/java/org/apache/camel/dsl/modeline/PropertyTrait.java index 02dbbba..68f2f49 100644 --- a/dsl/camel-dsl-modeline/src/main/java/org/apache/camel/dsl/modeline/PropertyTrait.java +++ b/dsl/camel-dsl-modeline/src/main/java/org/apache/camel/dsl/modeline/PropertyTrait.java @@ -22,6 +22,7 @@ import java.util.Properties; import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; import org.apache.camel.spi.CamelContextCustomizer; +import org.apache.camel.spi.PropertiesComponent; import org.apache.camel.spi.PropertiesSource; import org.apache.camel.spi.annotations.JdkService; import org.apache.camel.support.ResourceHelper; @@ -37,6 +38,7 @@ public class PropertyTrait implements Trait, PropertiesSource, CamelContextAware private final Properties properties = new OrderedProperties(); private CamelContext camelContext; + private PropertiesComponent pc; @Override public CamelContext getCamelContext() { @@ -63,7 +65,7 @@ public class PropertyTrait implements Trait, PropertiesSource, CamelContextAware if (trait.contains("=")) { String key = StringHelper.before(trait, "=").trim(); String value = StringHelper.after(trait, "=").trim(); - properties.setProperty(key, value); + setProperty(key, value); } else { if (ResourceHelper.hasScheme(trait)) { // it is a properties file so load resource @@ -74,7 +76,7 @@ public class PropertyTrait implements Trait, PropertiesSource, CamelContextAware String v = prop.getProperty(k); String key = k.trim(); String value = v.trim(); - properties.setProperty(key, value); + setProperty(key, value); } } catch (Exception e) { // ignore @@ -84,6 +86,14 @@ public class PropertyTrait implements Trait, PropertiesSource, CamelContextAware return null; } + protected void setProperty(String key, String value) { + properties.setProperty(key, value); + if (!camelContext.isStarted()) { + // if we are bootstrapping then also set as initial property, so it can be used there as well + camelContext.getPropertiesComponent().addInitialProperty(key, value); + } + } + @Override public String toString() { return "camel-dsl-modeline"; diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java index 48a7167..a5ef447 100644 --- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java +++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java @@ -183,6 +183,7 @@ public class KameletMain extends MainCommandLineSupport { VertxHttpServer.registerConsole(answer); } configure().withLoadHealthChecks(true); + configure().withModeline(true); boolean health = "true".equals(getInitialProperties().get("camel.jbang.health")); if (health && port == null) { @@ -190,7 +191,6 @@ public class KameletMain extends MainCommandLineSupport { VertxHttpServer.registerServer(answer, 8080); } if (health) { - configure().withLoadHealthChecks(true); VertxHttpServer.registerHealthCheck(answer); }