You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2020/03/14 15:08:47 UTC

[camel] branch master updated (ca9f978 -> 1a1ba5a)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git.


    from ca9f978  Upgrade Jgit to version 5.7.0.202003110725-r
     new 2e57fd7  CAMEL-14598: Add ComponentNameResolver to discover components on the classpath.
     new 68c082e  CAMEL-14598: camel-main configuring components now support wildcard in key to configure multiple components with the same values.
     new 2519284  CAMEL-14598: camel-main configuring components now support wildcard in key to configure multiple components with the same values.
     new 1a1ba5a  Fixed compiler warning

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/camel/ExtendedCamelContext.java     |  11 +++
 ...amelContext.java => ComponentNameResolver.java} |  13 ++-
 .../camel/spi/PackageScanResourceResolver.java     |  17 ++++
 .../camel/impl/engine/AbstractCamelContext.java    |  20 ++++
 .../impl/engine/DefaultComponentNameResolver.java} |  41 ++++----
 .../engine/DefaultPackageScanResourceResolver.java |  40 +++++---
 .../camel/impl/engine/SimpleCamelContext.java      |   6 ++
 .../camel/impl/lw/ImmutableCamelContext.java       |  11 +++
 .../impl/lw/RuntimeImmutableCamelContext.java      |  13 +++
 .../engine/DefaultComponentNameResolverTest.java}  |  40 ++++----
 .../org/apache/camel/main/BaseMainSupport.java     | 105 ++++++++++++++++++---
 ...MainSedaTest.java => MainSedaWildcardTest.java} |  38 +++-----
 .../java/org/apache/camel/xml/io/MXParser.java     |   4 +-
 13 files changed, 260 insertions(+), 99 deletions(-)
 copy core/camel-api/src/main/java/org/apache/camel/spi/{HasCamelContext.java => ComponentNameResolver.java} (72%)
 copy core/{camel-core/src/test/java/org/apache/camel/processor/OnCompletionInvalidConfiguredTest.java => camel-base/src/main/java/org/apache/camel/impl/engine/DefaultComponentNameResolver.java} (51%)
 copy core/camel-core/src/test/java/org/apache/camel/{component/stub/StubAwsTest.java => impl/engine/DefaultComponentNameResolverTest.java} (52%)
 copy core/camel-main/src/test/java/org/apache/camel/main/{MainSedaTest.java => MainSedaWildcardTest.java} (59%)


[camel] 04/04: Fixed compiler warning

Posted by da...@apache.org.
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 1a1ba5acd9785a7b165854576b8a25a0c67e4f37
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Mar 14 16:08:22 2020 +0100

    Fixed compiler warning
---
 core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java b/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java
index c71ceab..ca0c13f 100644
--- a/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java
+++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java
@@ -2528,11 +2528,11 @@ public class MXParser implements XmlPullParser {
             if (ch == 'y') {
                 ch = requireInput(ch, YES);
                 // Boolean standalone = new Boolean(true);
-                xmlDeclStandalone = new Boolean(true);
+                xmlDeclStandalone = Boolean.TRUE;
             } else if (ch == 'n') {
                 ch = requireInput(ch, NO);
                 // Boolean standalone = new Boolean(false);
-                xmlDeclStandalone = new Boolean(false);
+                xmlDeclStandalone = Boolean.FALSE;
             } else {
                 throw new XmlPullParserException("expected 'yes' or 'no' after standalone and not " + printable(ch), this, null);
             }


[camel] 03/04: CAMEL-14598: camel-main configuring components now support wildcard in key to configure multiple components with the same values.

Posted by da...@apache.org.
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 <cl...@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");
+        }
+    }
+
+}


[camel] 02/04: CAMEL-14598: camel-main configuring components now support wildcard in key to configure multiple components with the same values.

Posted by da...@apache.org.
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 68c082e3bf810f0168d3f4312bd587365fb28460
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Mar 14 13:29:50 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     | 61 ++++++++++++++++------
 1 file changed, 44 insertions(+), 17 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 b8114a7..cf846f8 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,6 +21,8 @@ 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;
 import java.util.List;
@@ -31,6 +33,8 @@ 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;
@@ -51,8 +55,11 @@ 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;
@@ -64,6 +71,7 @@ import org.apache.camel.util.StringHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 import static org.apache.camel.support.ObjectHelper.invokeMethod;
 import static org.apache.camel.util.ReflectionHelper.findMethod;
 import static org.apache.camel.util.StringHelper.matches;
@@ -952,13 +960,29 @@ public abstract class BaseMainSupport extends BaseService {
 
         for (String key : prop.stringPropertyNames()) {
             computeProperties("camel.component.", key, prop, properties, 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");
+                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);
+
+                    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");
+                    }
                 }
 
-                return target;
+                return targets;
             });
             computeProperties("camel.dataformat.", key, prop, properties, name -> {
                 DataFormat target = camelContext.resolveDataFormat(name);
@@ -967,7 +991,7 @@ public abstract class BaseMainSupport extends BaseService {
                             + ". Make sure you have the dataformat on the classpath");
                 }
 
-                return target;
+                return Collections.singleton(target);
             });
             computeProperties("camel.language.", key, prop, properties, name -> {
                 Language target;
@@ -978,7 +1002,7 @@ public abstract class BaseMainSupport extends BaseService {
                             + ". Make sure you have the language on the classpath");
                 }
 
-                return target;
+                return Collections.singleton(target);
             });
         }
 
@@ -1010,6 +1034,8 @@ 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
@@ -1113,7 +1139,8 @@ public abstract class BaseMainSupport extends BaseService {
         }
     }
 
-    public static void computeProperties(String keyPrefix, String key, Properties prop, Map<PropertyOptionKey, Map<String, Object>> properties, Function<String, Object> supplier) {
+    protected static void computeProperties(String keyPrefix, String key, Properties prop, Map<PropertyOptionKey, Map<String, Object>> properties,
+                                            Function<String, Iterable<Object>> supplier) {
         if (key.startsWith(keyPrefix)) {
             // grab name
             final int dot = key.indexOf(".", keyPrefix.length());
@@ -1143,8 +1170,6 @@ public abstract class BaseMainSupport extends BaseService {
                 return;
             }
 
-
-
             String prefix = dot == -1 ? "" : key.substring(0, dot + 1);
             String option = dot == -1 ? "" : key.substring(dot + 1);
             String value = prop.getProperty(key, "");
@@ -1156,16 +1181,18 @@ public abstract class BaseMainSupport extends BaseService {
 
             validateOptionAndValue(key, option, value);
 
-            Object target = supplier.apply(name);
-            PropertyOptionKey pok = new PropertyOptionKey(target, prefix);
-            Map<String, Object> values = properties.computeIfAbsent(pok, k -> new LinkedHashMap<>());
+            Iterable<Object> targets = supplier.apply(name);
+            for (Object target : targets) {
+                PropertyOptionKey pok = new PropertyOptionKey(target, prefix);
+                Map<String, Object> values = properties.computeIfAbsent(pok, k -> new LinkedHashMap<>());
 
-            // we ignore case for property keys (so we should store them in canonical style
-            values.put(optionKey(option), value);
+                // we ignore case for property keys (so we should store them in canonical style
+                values.put(optionKey(option), value);
+            }
         }
     }
 
-    public static boolean isServiceEnabled(String prefix, String name, Properties properties) {
+    protected static boolean isServiceEnabled(String prefix, String name, Properties properties) {
         ObjectHelper.notNull(prefix, "prefix");
         ObjectHelper.notNull(name, "name");
         ObjectHelper.notNull(properties, "properties");
@@ -1177,6 +1204,6 @@ public abstract class BaseMainSupport extends BaseService {
         final String group = properties.getProperty(prefix + "enabled", "true");
         final String item = properties.getProperty(prefix + name + ".enabled", group);
 
-        return Boolean.valueOf(item);
+        return Boolean.parseBoolean(item);
     }
 }


[camel] 01/04: CAMEL-14598: Add ComponentNameResolver to discover components on the classpath.

Posted by da...@apache.org.
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 2e57fd7f4eadc7f0d6269417ddba8f1bcbdb6a99
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Mar 14 13:04:48 2020 +0100

    CAMEL-14598: Add ComponentNameResolver to discover components on the classpath.
---
 .../org/apache/camel/ExtendedCamelContext.java     | 11 +++++
 .../apache/camel/spi/ComponentNameResolver.java    | 35 ++++++++++++++
 .../camel/spi/PackageScanResourceResolver.java     | 17 +++++++
 .../camel/impl/engine/AbstractCamelContext.java    | 20 ++++++++
 .../impl/engine/DefaultComponentNameResolver.java  | 45 ++++++++++++++++++
 .../engine/DefaultPackageScanResourceResolver.java | 40 ++++++++++------
 .../camel/impl/engine/SimpleCamelContext.java      |  6 +++
 .../camel/impl/lw/ImmutableCamelContext.java       | 11 +++++
 .../impl/lw/RuntimeImmutableCamelContext.java      | 13 ++++++
 .../engine/DefaultComponentNameResolverTest.java   | 54 ++++++++++++++++++++++
 .../org/apache/camel/main/BaseMainSupport.java     |  4 +-
 11 files changed, 241 insertions(+), 15 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
index 55f92bb..8b53752 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
@@ -30,6 +30,7 @@ import org.apache.camel.spi.BeanIntrospection;
 import org.apache.camel.spi.BeanProcessorFactory;
 import org.apache.camel.spi.BeanProxyFactory;
 import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.ComponentNameResolver;
 import org.apache.camel.spi.ComponentResolver;
 import org.apache.camel.spi.ConfigurerResolver;
 import org.apache.camel.spi.DataFormatResolver;
@@ -262,6 +263,16 @@ public interface ExtendedCamelContext extends CamelContext {
     void setComponentResolver(ComponentResolver componentResolver);
 
     /**
+     * Gets the {@link ComponentNameResolver} to use.
+     */
+    ComponentNameResolver getComponentNameResolver();
+
+    /**
+     * Sets a custom {@link ComponentNameResolver} to use.
+     */
+    void setComponentNameResolver(ComponentNameResolver componentNameResolver);
+
+    /**
      * Gets the {@link LanguageResolver} to use.
      */
     LanguageResolver getLanguageResolver();
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/ComponentNameResolver.java b/core/camel-api/src/main/java/org/apache/camel/spi/ComponentNameResolver.java
new file mode 100644
index 0000000..8454bdc
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/ComponentNameResolver.java
@@ -0,0 +1,35 @@
+/*
+ * 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.spi;
+
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+
+/**
+ * Discovers which components are available on the classpath.
+ */
+public interface ComponentNameResolver {
+
+    /**
+     * Discovers which components are available on the classpath.
+     *
+     * @param camelContext the camel context
+     * @return the component names on the classpath
+     */
+    Set<String> resolveNames(CamelContext camelContext);
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/PackageScanResourceResolver.java b/core/camel-api/src/main/java/org/apache/camel/spi/PackageScanResourceResolver.java
index 9052255..db0bc0e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/PackageScanResourceResolver.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PackageScanResourceResolver.java
@@ -74,4 +74,21 @@ public interface PackageScanResourceResolver extends StaticService {
      */
     Set<InputStream> findResources(String location) throws Exception;
 
+    /**
+     * Finds the resource names from the given location.
+     *
+     * The location can be prefixed with either file: or classpath: to look in either file system or classpath.
+     * By default classpath is assumed if no prefix is specified.
+     *
+     * Wildcards is supported using a ANT pattern style paths, such as classpath:&#42;&#42;/&#42;camel&#42;.xml
+     *
+     * Notice when using wildcards, then there is additional overhead as the classpath is scanned, where
+     * as if you specific the exact name for each XML file is faster as no classpath scanning is needed.
+     *
+     * @param location  the location (support ANT style patterns, eg routes/camel-*.xml)
+     * @return the found resource names, or an empty set if no resources found
+     * @throws Exception can be thrown during scanning for resources.
+     */
+    Set<String> findResourceNames(String location) throws Exception;
+
 }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index b32bbc6..c8acf1b 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -91,6 +91,7 @@ import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.CamelContextNameStrategy;
 import org.apache.camel.spi.CamelContextTracker;
 import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.ComponentNameResolver;
 import org.apache.camel.spi.ComponentResolver;
 import org.apache.camel.spi.ConfigurerResolver;
 import org.apache.camel.spi.DataFormat;
@@ -246,6 +247,7 @@ public abstract class AbstractCamelContext extends BaseService
     private volatile Injector injector;
     private volatile CamelBeanPostProcessor beanPostProcessor;
     private volatile ComponentResolver componentResolver;
+    private volatile ComponentNameResolver componentNameResolver;
     private volatile LanguageResolver languageResolver;
     private volatile ConfigurerResolver configurerResolver;
     private volatile DataFormatResolver dataFormatResolver;
@@ -1882,6 +1884,21 @@ public abstract class AbstractCamelContext extends BaseService
         this.componentResolver = doAddService(componentResolver);
     }
 
+    public ComponentNameResolver getComponentNameResolver() {
+        if (componentNameResolver == null) {
+            synchronized (lock) {
+                if (componentNameResolver == null) {
+                    setComponentNameResolver(createComponentNameResolver());
+                }
+            }
+        }
+        return componentNameResolver;
+    }
+
+    public void setComponentNameResolver(ComponentNameResolver componentNameResolver) {
+        this.componentNameResolver = doAddService(componentNameResolver);
+    }
+
     public LanguageResolver getLanguageResolver() {
         if (languageResolver == null) {
             synchronized (lock) {
@@ -3497,6 +3514,7 @@ public abstract class AbstractCamelContext extends BaseService
         getFactoryFinderResolver();
         getDefaultFactoryFinder();
         getComponentResolver();
+        getComponentNameResolver();
         getDataFormatResolver();
         getManagementStrategy();
         getHeadersMapFactory();
@@ -4431,6 +4449,8 @@ public abstract class AbstractCamelContext extends BaseService
 
     protected abstract ComponentResolver createComponentResolver();
 
+    protected abstract ComponentNameResolver createComponentNameResolver();
+
     protected abstract Registry createRegistry();
 
     protected abstract UuidGenerator createUuidGenerator();
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultComponentNameResolver.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultComponentNameResolver.java
new file mode 100644
index 0000000..a3189de
--- /dev/null
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultComponentNameResolver.java
@@ -0,0 +1,45 @@
+/*
+ * 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.impl.engine;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.ComponentNameResolver;
+
+public class DefaultComponentNameResolver implements ComponentNameResolver {
+
+    public static final String RESOURCE_PATH = "META-INF/services/org/apache/camel/component/*";
+
+    @Override
+    public Set<String> resolveNames(CamelContext camelContext) {
+        // remove leading path to only keep name
+        Set<String> sorted = new TreeSet<>();
+
+        try {
+            Set<String> locations = camelContext.adapt(ExtendedCamelContext.class).getPackageScanResourceResolver().findResourceNames(RESOURCE_PATH);
+            locations.forEach(l -> sorted.add(l.substring(l.lastIndexOf('/') + 1)));
+        } catch (Exception e) {
+            throw new RuntimeCamelException(e);
+        }
+
+        return sorted;
+    }
+}
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolver.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolver.java
index a42355d..f814af6 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolver.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolver.java
@@ -34,6 +34,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
+import java.util.stream.Collectors;
 
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.NonManagedService;
@@ -41,6 +42,7 @@ import org.apache.camel.spi.PackageScanResourceResolver;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.AntPathMatcher;
 import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.KeyValueHolder;
 import org.apache.camel.util.ObjectHelper;
 
 /**
@@ -50,9 +52,20 @@ public class DefaultPackageScanResourceResolver extends BasePackageScanResolver
 
     private static final AntPathMatcher PATH_MATCHER = AntPathMatcher.INSTANCE;
 
+    @Override
+    public Set<String> findResourceNames(String location) throws Exception {
+        Set<KeyValueHolder<String, InputStream>> answer = new LinkedHashSet<>();
+        doFindResources(location, answer);
+        return answer.stream().map(KeyValueHolder::getKey).collect(Collectors.toSet());
+    }
+
     public Set<InputStream> findResources(String location) throws Exception {
-        Set<InputStream> answer = new LinkedHashSet<>();
+        Set<KeyValueHolder<String, InputStream>> answer = new LinkedHashSet<>();
+        doFindResources(location, answer);
+        return answer.stream().map(KeyValueHolder::getValue).collect(Collectors.toSet());
+    }
 
+    protected void doFindResources(String location, Set<KeyValueHolder<String, InputStream>> resources) throws Exception {
         // if its a pattern then we need to scan its root path and find
         // all matching resources using the sub pattern
         if (PATH_MATCHER.isPattern(location)) {
@@ -63,34 +76,33 @@ public class DefaultPackageScanResourceResolver extends BasePackageScanResolver
             if ("file:".equals(scheme)) {
                 // file based scanning
                 root = root.substring(scheme.length());
-                findInFileSystem(new File(root), answer, subPattern);
+                findInFileSystem(new File(root), resources, subPattern);
             } else {
                 if ("classpath:".equals(scheme)) {
                     root = root.substring(scheme.length());
                 }
                 // assume classpath based scan from root path and find all resources
-                findInClasspath(root, answer, subPattern);
+                findInClasspath(root, resources, subPattern);
             }
         } else {
             // its a single resource so load it directly
             InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext(), location);
-            answer.add(is);
+            resources.add(new KeyValueHolder<>(location, is));
         }
-
-        return answer;
     }
 
-    protected void findInFileSystem(File dir, Set<InputStream> resources, String subPattern) throws Exception {
+    protected void findInFileSystem(File dir, Set<KeyValueHolder<String, InputStream>> resources, String subPattern) throws Exception {
         ResourceHelper.findInFileSystem(dir.toPath(), subPattern).forEach(f -> {
             try {
-                resources.add(Files.newInputStream(f));
+                String location = f.toString();
+                resources.add(new KeyValueHolder<>(location, Files.newInputStream(f)));
             } catch (IOException e) {
                 // ignore
             }
         });
     }
 
-    protected void findInClasspath(String packageName, Set<InputStream> resources, String subPattern) {
+    protected void findInClasspath(String packageName, Set<KeyValueHolder<String, InputStream>> resources, String subPattern) {
         packageName = packageName.replace('.', '/');
         // If the URL is a jar, the URLClassloader.getResources() seems to require a trailing slash.
         // The trailing slash is harmless for other URLs
@@ -105,7 +117,7 @@ public class DefaultPackageScanResourceResolver extends BasePackageScanResolver
         }
     }
 
-    protected void doFind(String packageName, ClassLoader classLoader, Set<InputStream> resources, String subPattern) {
+    protected void doFind(String packageName, ClassLoader classLoader, Set<KeyValueHolder<String, InputStream>> resources, String subPattern) {
         Enumeration<URL> urls;
         try {
             urls = getResources(classLoader, packageName);
@@ -207,7 +219,7 @@ public class DefaultPackageScanResourceResolver extends BasePackageScanResolver
      * @param urlPath the url of the jar file to be examined for classes
      */
     private void loadImplementationsInJar(String packageName, String subPattern, InputStream stream,
-                                          String urlPath, Set<InputStream> resources) {
+                                          String urlPath, Set<KeyValueHolder<String, InputStream>> resources) {
         List<String> entries = new ArrayList<>();
 
         JarInputStream jarStream = null;
@@ -241,7 +253,7 @@ public class DefaultPackageScanResourceResolver extends BasePackageScanResolver
                 // use fqn name to load resource
                 InputStream is = getCamelContext().getClassResolver().loadResourceAsStream(name);
                 if (is != null) {
-                    resources.add(is);
+                    resources.add(new KeyValueHolder<>(name, is));
                 }
             }
         }
@@ -260,7 +272,7 @@ public class DefaultPackageScanResourceResolver extends BasePackageScanResolver
      *                 <i>parent</i> would be <i>org/apache</i>
      * @param location a File object representing a directory
      */
-    private void loadImplementationsInDirectory(String subPattern, String parent, File location, Set<InputStream> resources) throws FileNotFoundException {
+    private void loadImplementationsInDirectory(String subPattern, String parent, File location, Set<KeyValueHolder<String, InputStream>> resources) throws FileNotFoundException {
         File[] files = location.listFiles();
         if (files == null || files.length == 0) {
             return;
@@ -281,7 +293,7 @@ public class DefaultPackageScanResourceResolver extends BasePackageScanResolver
                 log.debug("Found resource: {} matching pattern: {} -> {}", name, subPattern, match);
                 if (match) {
                     InputStream is = new FileInputStream(file);
-                    resources.add(is);
+                    resources.add(new KeyValueHolder<>(name, is));
                 }
             }
         }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
index db8eed0..e6cd59f 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
@@ -39,6 +39,7 @@ import org.apache.camel.spi.BeanProxyFactory;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.CamelContextNameStrategy;
 import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.ComponentNameResolver;
 import org.apache.camel.spi.ComponentResolver;
 import org.apache.camel.spi.ConfigurerResolver;
 import org.apache.camel.spi.DataFormatResolver;
@@ -155,6 +156,11 @@ public class SimpleCamelContext extends AbstractCamelContext {
     }
 
     @Override
+    protected ComponentNameResolver createComponentNameResolver() {
+        return new DefaultComponentNameResolver();
+    }
+
+    @Override
     protected Registry createRegistry() {
         return new DefaultRegistry();
     }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/ImmutableCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/ImmutableCamelContext.java
index 71ffe85..5d8368e 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/ImmutableCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/ImmutableCamelContext.java
@@ -69,6 +69,7 @@ import org.apache.camel.spi.BeanRepository;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.CamelContextNameStrategy;
 import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.ComponentNameResolver;
 import org.apache.camel.spi.ComponentResolver;
 import org.apache.camel.spi.ConfigurerResolver;
 import org.apache.camel.spi.DataFormat;
@@ -1166,6 +1167,16 @@ public class ImmutableCamelContext implements ExtendedCamelContext, CatalogCamel
     }
 
     @Override
+    public ComponentNameResolver getComponentNameResolver() {
+        return getExtendedCamelContext().getComponentNameResolver();
+    }
+
+    @Override
+    public void setComponentNameResolver(ComponentNameResolver componentNameResolver) {
+        getExtendedCamelContext().setComponentNameResolver(componentNameResolver);
+    }
+
+    @Override
     public LanguageResolver getLanguageResolver() {
         return getExtendedCamelContext().getLanguageResolver();
     }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/RuntimeImmutableCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/RuntimeImmutableCamelContext.java
index d2920b6..0470117 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/RuntimeImmutableCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/RuntimeImmutableCamelContext.java
@@ -72,6 +72,7 @@ import org.apache.camel.spi.BeanProxyFactory;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.CamelContextNameStrategy;
 import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.ComponentNameResolver;
 import org.apache.camel.spi.ComponentResolver;
 import org.apache.camel.spi.ConfigurerResolver;
 import org.apache.camel.spi.DataFormat;
@@ -145,6 +146,7 @@ public class RuntimeImmutableCamelContext implements ExtendedCamelContext, Catal
     private final ModelJAXBContextFactory modelJAXBContextFactory;
     private final RuntimeCamelCatalog camelRuntimeCatalog;
     private final ComponentResolver componentResolver;
+    private final ComponentNameResolver componentNameResolver;
     private final LanguageResolver languageResolver;
     private final DataFormatResolver dataFormatResolver;
     private final UuidGenerator uuidGenerator;
@@ -186,6 +188,7 @@ public class RuntimeImmutableCamelContext implements ExtendedCamelContext, Catal
         routes = Collections.unmodifiableList(context.getRoutes());
         uuidGenerator = context.getUuidGenerator();
         componentResolver = context.adapt(ExtendedCamelContext.class).getComponentResolver();
+        componentNameResolver = context.adapt(ExtendedCamelContext.class).getComponentNameResolver();
         languageResolver = context.adapt(ExtendedCamelContext.class).getLanguageResolver();
         dataFormatResolver = context.adapt(ExtendedCamelContext.class).getDataFormatResolver();
         endpoints = (EndpointRegistry) context.getEndpointRegistry();
@@ -416,6 +419,11 @@ public class RuntimeImmutableCamelContext implements ExtendedCamelContext, Catal
     }
 
     @Override
+    public ComponentNameResolver getComponentNameResolver() {
+        return componentNameResolver;
+    }
+
+    @Override
     public LanguageResolver getLanguageResolver() {
         return languageResolver;
     }
@@ -1414,6 +1422,11 @@ public class RuntimeImmutableCamelContext implements ExtendedCamelContext, Catal
     }
 
     @Override
+    public void setComponentNameResolver(ComponentNameResolver componentResolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void setLanguageResolver(LanguageResolver languageResolver) {
         throw new UnsupportedOperationException();
     }
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultComponentNameResolverTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultComponentNameResolverTest.java
new file mode 100644
index 0000000..c6d5216
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultComponentNameResolverTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.impl.engine;
+
+import java.util.Set;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.spi.ComponentNameResolver;
+import org.junit.Test;
+
+public class DefaultComponentNameResolverTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testDefaultComponentNameResolver() throws Exception {
+        context.start();
+
+        ComponentNameResolver resolver = context.adapt(ExtendedCamelContext.class).getComponentNameResolver();
+        assertNotNull(resolver);
+
+        Set<String> names = resolver.resolveNames(context);
+        assertNotNull(names);
+        assertTrue(names.size() > 20);
+
+        assertTrue(names.contains("bean"));
+        assertTrue(names.contains("direct"));
+        assertTrue(names.contains("file"));
+        assertTrue(names.contains("log"));
+        assertTrue(names.contains("mock"));
+        assertTrue(names.contains("vm"));
+        assertTrue(names.contains("xslt"));
+
+        context.stop();
+    }
+}
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 b7782ee..b8114a7 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
@@ -1143,7 +1143,8 @@ public abstract class BaseMainSupport extends BaseService {
                 return;
             }
 
-            Object target = supplier.apply(name);
+
+
             String prefix = dot == -1 ? "" : key.substring(0, dot + 1);
             String option = dot == -1 ? "" : key.substring(dot + 1);
             String value = prop.getProperty(key, "");
@@ -1155,6 +1156,7 @@ public abstract class BaseMainSupport extends BaseService {
 
             validateOptionAndValue(key, option, value);
 
+            Object target = supplier.apply(name);
             PropertyOptionKey pok = new PropertyOptionKey(target, prefix);
             Map<String, Object> values = properties.computeIfAbsent(pok, k -> new LinkedHashMap<>());