diff --git a/camel-k-runtime-core/src/main/java/org/apache/camel/k/Constants.java b/camel-k-runtime-core/src/main/java/org/apache/camel/k/Constants.java index d9d2d9d45..083e1c45d 100644 --- a/camel-k-runtime-core/src/main/java/org/apache/camel/k/Constants.java +++ b/camel-k-runtime-core/src/main/java/org/apache/camel/k/Constants.java @@ -28,6 +28,7 @@ public final class Constants { public static final String ROUTES_LOADER_RESOURCE_PATH = "META-INF/services/org/apache/camel/k/loader/"; public static final String CONTEXT_CUSTOMIZER_RESOURCE_PATH = "META-INF/services/org/apache/camel/k/customizer/"; public static final String PROPERTY_CAMEL_K_CUSTOMIZER = "camel.k.customizer"; + public static final String ENABLE_CUSTOMIZER_PATTERN = "customizer.([\\w][\\w-]*).enabled"; private Constants() { } diff --git a/camel-k-runtime-core/src/main/java/org/apache/camel/k/ContextCustomizer.java b/camel-k-runtime-core/src/main/java/org/apache/camel/k/ContextCustomizer.java index c6d6b1dbe..e0bf62150 100644 --- a/camel-k-runtime-core/src/main/java/org/apache/camel/k/ContextCustomizer.java +++ b/camel-k-runtime-core/src/main/java/org/apache/camel/k/ContextCustomizer.java @@ -17,9 +17,10 @@ package org.apache.camel.k; import org.apache.camel.CamelContext; +import org.apache.camel.Ordered; @FunctionalInterface -public interface ContextCustomizer { +public interface ContextCustomizer extends Ordered, Comparable{ /** * Perform CamelContext customization. * @@ -27,4 +28,14 @@ public interface ContextCustomizer { * @param registry the runtime registry. */ void apply(CamelContext camelContext, Runtime.Registry registry); + + @Override + default int getOrder() { + return Ordered.LOWEST; + } + + @Override + default int compareTo(ContextCustomizer o) { + return Integer.compare(getOrder(), o.getOrder()); + } } diff --git a/camel-k-runtime-core/src/main/java/org/apache/camel/k/support/RuntimeSupport.java b/camel-k-runtime-core/src/main/java/org/apache/camel/k/support/RuntimeSupport.java index 597b9ccb4..9a4023a8c 100644 --- a/camel-k-runtime-core/src/main/java/org/apache/camel/k/support/RuntimeSupport.java +++ b/camel-k-runtime-core/src/main/java/org/apache/camel/k/support/RuntimeSupport.java @@ -30,9 +30,10 @@ import java.util.Map; import java.util.Objects; import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.camel.CamelContext; import org.apache.camel.NoFactoryAvailableException; @@ -46,7 +47,6 @@ import org.apache.camel.spi.FactoryFinder; import org.apache.camel.spi.RestConfiguration; import org.apache.camel.util.ObjectHelper; -import org.apache.camel.util.StringHelper; import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,29 +60,21 @@ private RuntimeSupport() { public static List configureContext(CamelContext context, Runtime.Registry registry) { List appliedCustomizers = new ArrayList<>(); - Set customizers = lookupCustomizerIDs(context); - // this is to initialize all customizers that might be already present in - // the context injected by other means. - for (Map.Entry entry: context.getRegistry().findByTypeWithName(ContextCustomizer.class).entrySet()) { - if (!customizers.remove(entry.getKey())) { - continue; - } - - applyCustomizer(context, entry.getKey(), entry.getValue(), registry); + try { + Map customizers = lookupCustomizers(context); - appliedCustomizers.add(entry.getValue()); - } + customizers.entrySet().stream() + .sorted(Map.Entry.comparingByValue()) + .forEach(e -> { + LOGGER.info("Apply ContextCustomizer with id={} and type={}", e.getKey(), e.getValue().getClass().getName()); - try { - FactoryFinder finder = context.getFactoryFinder(Constants.CONTEXT_CUSTOMIZER_RESOURCE_PATH); + bindProperties(context, e.getValue(), "customizer." + e.getKey() + "."); + e.getValue().apply(context, registry); - for (String customizerId : customizers) { - ContextCustomizer customizer = (ContextCustomizer) finder.newInstance(customizerId); - applyCustomizer(context, customizerId, customizer, registry); + appliedCustomizers.add(e.getValue()); + }); - appliedCustomizers.add(customizer); - } } catch (NoFactoryAvailableException e) { throw new RuntimeException(e); } @@ -90,33 +82,53 @@ public static List configureContext(CamelContext context, Run return appliedCustomizers; } - public static void applyCustomizer(CamelContext context, String customizerId, ContextCustomizer customizer, Runtime.Registry registry) { - ObjectHelper.notNull(customizer, "customizer"); - StringHelper.notEmpty(customizerId, "customizerId"); - - LOGGER.info("Apply ContextCustomizer with id={} and type={}", customizerId, customizer.getClass().getName()); - - bindProperties(context, customizer, "customizer." + customizerId + "."); - customizer.apply(context, registry); - } - public static Set lookupCustomizerIDs(CamelContext context) { - Set customizers = new TreeSet<>(); + public static Map lookupCustomizers(CamelContext context) throws NoFactoryAvailableException { + Map customizers = new ConcurrentHashMap<>(); - String customizerIDs = System.getenv().getOrDefault(Constants.ENV_CAMEL_K_CUSTOMIZERS, ""); - if (ObjectHelper.isEmpty(customizerIDs)) { - PropertiesComponent component = context.getComponent("properties", PropertiesComponent.class); - Properties properties = component.getInitialProperties(); + PropertiesComponent component = context.getComponent("properties", PropertiesComponent.class); + Properties properties = component.getInitialProperties(); - if (properties != null) { - customizerIDs = properties.getProperty(Constants.PROPERTY_CAMEL_K_CUSTOMIZER, ""); + if (properties != null) { + // + // Filter out customizers available on the registry + // but not enabled + // + for (Map.Entry entry: context.getRegistry().findByTypeWithName(ContextCustomizer.class).entrySet()) { + String enabled = properties.getProperty("customizer." + entry.getKey() + ".enabled"); + if (Boolean.valueOf(enabled)) { + customizers.put(entry.getKey(), entry.getValue()); + } } - } - if (ObjectHelper.isNotEmpty(customizerIDs)) { - for (String customizerId : customizerIDs.split(",", -1)) { - customizers.add(customizerId); - } + final FactoryFinder finder = context.getFactoryFinder(Constants.CONTEXT_CUSTOMIZER_RESOURCE_PATH); + final Pattern pattern = Pattern.compile(Constants.ENABLE_CUSTOMIZER_PATTERN); + + properties.entrySet().stream() + .filter(entry -> entry.getKey() instanceof String) + .filter(entry -> entry.getValue() != null) + .forEach(entry -> { + final String key = (String)entry.getKey(); + final Object val = entry.getValue(); + final Matcher matcher = pattern.matcher(key); + + if (matcher.matches() && matcher.groupCount() == 1) { + if (Boolean.valueOf(String.valueOf(val))) { + // + // Do not override customizers eventually found + // in the registry + // + customizers.computeIfAbsent(matcher.group(1), customizerId -> { + try { + return (ContextCustomizer) finder.newInstance(customizerId); + } catch (NoFactoryAvailableException e) { + throw new RuntimeException(e); + } + }); + } + } + } + ); } return customizers; diff --git a/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/NameCustomizer.java b/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/NameCustomizer.java index 38bad6493..0c19cba88 100644 --- a/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/NameCustomizer.java +++ b/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/NameCustomizer.java @@ -17,6 +17,7 @@ package org.apache.camel.k.support; import org.apache.camel.CamelContext; +import org.apache.camel.Ordered; import org.apache.camel.impl.ExplicitCamelContextNameStrategy; import org.apache.camel.k.ContextCustomizer; import org.apache.camel.k.Runtime; @@ -32,6 +33,11 @@ public NameCustomizer(String name) { this.name = name; } + @Override + public int getOrder() { + return Ordered.HIGHEST; + } + @Override public void apply(CamelContext camelContext, Runtime.Registry registry) { camelContext.setNameStrategy(new ExplicitCamelContextNameStrategy(name)); diff --git a/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/RuntimeSupportTest.java b/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/RuntimeSupportTest.java index 592d633fc..31c34846a 100644 --- a/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/RuntimeSupportTest.java +++ b/camel-k-runtime-core/src/test/java/org/apache/camel/k/support/RuntimeSupportTest.java @@ -22,7 +22,6 @@ import org.apache.camel.CamelContext; import org.apache.camel.component.properties.PropertiesComponent; import org.apache.camel.impl.DefaultCamelContext; -import org.apache.camel.k.Constants; import org.apache.camel.k.ContextCustomizer; import org.apache.camel.k.InMemoryRegistry; import org.apache.camel.k.Runtime; @@ -48,7 +47,7 @@ public void testLoadCustomizers() { assertThat(customizers).hasSize(0); Properties properties = new Properties(); - properties.setProperty(Constants.PROPERTY_CAMEL_K_CUSTOMIZER, "name"); + properties.setProperty("customizer.name.enabled", "true"); pc.setInitialProperties(properties); customizers = RuntimeSupport.configureContext(context, registry); @@ -64,7 +63,7 @@ public void testLoadCustomizersOrdering() { context.addComponent("properties", pc); Properties properties = new Properties(); - properties.setProperty(Constants.PROPERTY_CAMEL_K_CUSTOMIZER, "name"); + properties.setProperty("customizer.name.enabled", "true"); pc.setInitialProperties(properties); List customizers = RuntimeSupport.configureContext(context, registry); diff --git a/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java b/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java index cd82ef740..65916a71d 100644 --- a/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java +++ b/camel-k-runtime-jvm/src/test/java/org/apache/camel/k/jvm/PropertiesTest.java @@ -21,7 +21,6 @@ import org.apache.camel.CamelContext; import org.apache.camel.component.seda.SedaComponent; -import org.apache.camel.k.Constants; import org.apache.camel.k.ContextCustomizer; import org.apache.camel.k.Runtime; import org.apache.camel.k.listener.ContextConfigurer; @@ -130,11 +129,12 @@ public void testContextConfiguration() throws Exception { @Test public void testContextCustomizerFromProperty() throws Exception { - System.setProperty(Constants.PROPERTY_CAMEL_K_CUSTOMIZER, "test"); - System.setProperty("customizer.test.messageHistory", "false"); + Properties properties = new Properties(); + properties.setProperty("customizer.test.enabled", "true"); + properties.setProperty("customizer.test.messageHistory", "false"); ApplicationRuntime runtime = new ApplicationRuntime(); - runtime.setProperties(System.getProperties()); + runtime.setProperties(properties); runtime.addListener(new ContextConfigurer()); runtime.addListener(new ContextLifecycleConfigurer()); runtime.addListener(Runtime.Phase.Started, r -> { @@ -149,8 +149,11 @@ public void testContextCustomizerFromProperty() throws Exception { @Test public void testContextCustomizerFromRegistry() throws Exception { + Properties properties = new Properties(); + properties.setProperty("customizer.c1.enabled", "true"); + ApplicationRuntime runtime = new ApplicationRuntime(); - runtime.setProperties(System.getProperties()); + runtime.setProperties(properties); runtime.addListener(new ContextConfigurer()); runtime.addListener(new ContextLifecycleConfigurer()); runtime.getRegistry().bind("c1", (ContextCustomizer) (camelContext, registry) -> {