This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 2519284a33197f5a8c41669e48bbee16d20045fb Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sat Mar 14 16:05:31 2020 +0100 CAMEL-14598: camel-main configuring components now support wildcard in key to configure multiple components with the same values. --- .../org/apache/camel/main/BaseMainSupport.java | 112 +++++++++++++++------ .../apache/camel/main/MainSedaWildcardTest.java | 64 ++++++++++++ 2 files changed, 146 insertions(+), 30 deletions(-) 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 cf846f8..7519f52 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 @@ -21,7 +21,6 @@ import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -33,8 +32,6 @@ import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.camel.CamelContext; import org.apache.camel.Component; @@ -43,6 +40,7 @@ import org.apache.camel.NoSuchLanguageException; import org.apache.camel.ProducerTemplate; import org.apache.camel.PropertyBindingException; import org.apache.camel.RoutesBuilder; +import org.apache.camel.RuntimeCamelException; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.HystrixConfigurationDefinition; import org.apache.camel.model.Model; @@ -55,11 +53,8 @@ import org.apache.camel.spi.Language; import org.apache.camel.spi.PropertiesComponent; import org.apache.camel.spi.PropertyConfigurer; import org.apache.camel.spi.RestConfiguration; -import org.apache.camel.support.EndpointHelper; import org.apache.camel.support.LifecycleStrategySupport; -import org.apache.camel.support.PatternHelper; import org.apache.camel.support.PropertyBindingSupport; -import org.apache.camel.support.ResourceHelper; import org.apache.camel.support.service.BaseService; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.util.FileUtil; @@ -91,6 +86,7 @@ public abstract class BaseMainSupport extends BaseService { protected final List<MainListener> listeners = new ArrayList<>(); protected final MainConfigurationProperties mainConfigurationProperties = new MainConfigurationProperties(); + protected final Properties wildcardProperties = new OrderedProperties(); protected RoutesCollector routesCollector = new DefaultRoutesCollector(); protected List<RoutesBuilder> routeBuilders = new ArrayList<>(); protected String routeBuilderClasses; @@ -552,6 +548,9 @@ public abstract class BaseMainSupport extends BaseService { if (mainConfigurationProperties.isAutoConfigurationEnabled()) { autoConfigurationFromProperties(camelContext, autoConfiguredProperties); } + if (mainConfigurationProperties.isAutowireComponentProperties() || mainConfigurationProperties.isAutowireComponentPropertiesDeep()) { + autowireWildcardProperties(camelContext); + } // tracing may be enabled by some other property (i.e. camel.context.tracer.exchange-formatter.show-headers) if (camelContext.isTracing() && !mainConfigurationProperties.isTracing()) { @@ -958,31 +957,26 @@ public abstract class BaseMainSupport extends BaseService { Map<PropertyOptionKey, Map<String, Object>> properties = new LinkedHashMap<>(); + // filter out wildcard properties for (String key : prop.stringPropertyNames()) { - computeProperties("camel.component.", key, prop, properties, name -> { - List<Object> targets = new ArrayList<>(); - - if (name.endsWith("*")) { - // its a wildcard so match any existing component and what we can discover - List<String> names = camelContext.getComponentNames(); - Set<String> resolved = camelContext.adapt(ExtendedCamelContext.class).getComponentNameResolver().resolveNames(camelContext); + if (key.contains("*")) { + wildcardProperties.put(key, prop.getProperty(key)); + } + } + // and remove wildcards + for (String key : wildcardProperties.stringPropertyNames()) { + prop.remove(key); + } - Stream.of(names, resolved).flatMap(Collection::stream).forEach(n -> { - if (PatternHelper.matchPattern(n, name)) { - Component target = camelContext.getComponent(n); - targets.add(target); - } - }); - } else { - // its an existing component name - Component target = camelContext.getComponent(name); - if (target == null) { - throw new IllegalArgumentException("Error configuring property: " + key + " because cannot find component with name " + name - + ". Make sure you have the component on the classpath"); - } + for (String key : prop.stringPropertyNames()) { + computeProperties("camel.component.", key, prop, properties, name -> { + // its an existing component name + Component target = camelContext.getComponent(name); + if (target == null) { + throw new IllegalArgumentException("Error configuring property: " + key + " because cannot find component with name " + name + + ". Make sure you have the component on the classpath"); } - - return targets; + return Collections.singleton(target); }); computeProperties("camel.dataformat.", key, prop, properties, name -> { DataFormat target = camelContext.resolveDataFormat(name); @@ -1034,8 +1028,6 @@ public abstract class BaseMainSupport extends BaseService { } } - // TODO: Lets use this to configure components also when using wildcards - // eg put wildcards into a special properties and then map them here protected void autowireConfigurationFromRegistry(CamelContext camelContext, boolean bindNullOnly, boolean deepNesting) throws Exception { camelContext.addLifecycleStrategy(new LifecycleStrategySupport() { @Override @@ -1048,6 +1040,66 @@ public abstract class BaseMainSupport extends BaseService { }); } + protected void autowireWildcardProperties(CamelContext camelContext) { + if (wildcardProperties.isEmpty()) { + return; + } + + // autowire any pre-existing components as they have been added before we are invoked + for (String name : camelContext.getComponentNames()) { + Component comp = camelContext.getComponent(name); + doAutowireWildcardProperties(name, comp); + } + + // and autowire any new components that may be added in the future + camelContext.addLifecycleStrategy(new LifecycleStrategySupport() { + @Override + public void onComponentAdd(String name, Component component) { + doAutowireWildcardProperties(name, component); + } + }); + } + + protected void doAutowireWildcardProperties(String name, Component component) { + Map<PropertyOptionKey, Map<String, Object>> properties = new LinkedHashMap<>(); + Map<String, String> autoConfiguredProperties = new LinkedHashMap<>(); + String match = ("camel.component." + name).toLowerCase(Locale.US); + + for (String key : wildcardProperties.stringPropertyNames()) { + String mKey = key.substring(0, key.indexOf('*')).toLowerCase(Locale.US); + if (match.startsWith(mKey)) { + computeProperties("camel.component.", key, wildcardProperties, properties, s -> Collections.singleton(component)); + } + } + + try { + for (Map.Entry<PropertyOptionKey, Map<String, Object>> entry : properties.entrySet()) { + setPropertiesOnTarget( + camelContext, + entry.getKey().getInstance(), + entry.getValue(), + entry.getKey().getOptionPrefix(), + mainConfigurationProperties.isAutoConfigurationFailFast(), + true, + autoConfiguredProperties); + } + // log summary of configurations + if (mainConfigurationProperties.isAutoConfigurationLogSummary() && !autoConfiguredProperties.isEmpty()) { + LOG.info("Auto-configuration component {} summary:", name); + autoConfiguredProperties.forEach((k, v) -> { + boolean sensitive = SENSITIVE_KEYS.contains(k.toLowerCase(Locale.US)); + if (sensitive) { + LOG.info("\t{}=xxxxxx", k); + } else { + LOG.info("\t{}={}", k, v); + } + }); + } + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeException(e); + } + } + protected static void validateOptionAndValue(String key, String option, String value) { if (ObjectHelper.isEmpty(option)) { throw new IllegalArgumentException("Error configuring property: " + key + " because option is empty"); diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainSedaWildcardTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainSedaWildcardTest.java new file mode 100644 index 0000000..bbb7f1b --- /dev/null +++ b/core/camel-main/src/test/java/org/apache/camel/main/MainSedaWildcardTest.java @@ -0,0 +1,64 @@ +/* + * 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.main; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.seda.SedaComponent; +import org.junit.Assert; +import org.junit.Test; + +public class MainSedaWildcardTest extends Assert { + + @Test + public void testSedaWildcardMain() throws Exception { + Main main = new Main(); + main.addRoutesBuilder(new MyRouteBuilder()); + main.addProperty("camel.component.seda*.defaultQueueFactory", "#class:org.apache.camel.main.MySedaBlockingQueueFactory"); + main.addProperty("camel.component.seda*.defaultQueueFactory.counter", "123"); + main.bind("seda2", new SedaComponent()); + + main.start(); + + CamelContext camelContext = main.getCamelContext(); + assertNotNull(camelContext); + + SedaComponent seda = camelContext.getComponent("seda", SedaComponent.class); + assertNotNull(seda); + assertTrue(seda.getDefaultQueueFactory() instanceof MySedaBlockingQueueFactory); + MySedaBlockingQueueFactory myBQF = (MySedaBlockingQueueFactory) seda.getDefaultQueueFactory(); + assertEquals(123, myBQF.getCounter()); + + SedaComponent seda2 = camelContext.getComponent("seda", SedaComponent.class); + assertNotNull(seda2); + assertTrue(seda2.getDefaultQueueFactory() instanceof MySedaBlockingQueueFactory); + myBQF = (MySedaBlockingQueueFactory) seda2.getDefaultQueueFactory(); + assertEquals(123, myBQF.getCounter()); + + main.stop(); + } + + public static class MyRouteBuilder extends RouteBuilder { + @Override + public void configure() throws Exception { + from("direct:start").to("seda:foo"); + + from("direct:hello").to("seda2:bar"); + } + } + +}