You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2021/02/03 12:14:24 UTC

[camel] 02/04: CAMEL-15560: generic route loader (split route loader from language loader)

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

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

commit 97cd7552a922f510dc7fc4565e3558d2f419d283
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Wed Feb 3 07:56:53 2021 +0100

    CAMEL-15560: generic route loader (split route loader from language loader)
---
 .../org/apache/camel/ExtendedCamelContext.java     | 12 ++--
 .../org/apache/camel/spi/RoutesBuilderLoader.java  |  7 +-
 .../java/org/apache/camel/spi/RoutesLoader.java    | 75 ++++++++++++++++++++++
 .../camel/spi/XMLRoutesDefinitionLoader.java       |  2 +-
 .../services/org/apache/camel/routes-loader        |  2 +
 .../camel/impl/engine/AbstractCamelContext.java    | 20 +++---
 ...BuilderLoader.java => DefaultRoutesLoader.java} | 36 +++++++----
 .../camel/impl/engine/SimpleCamelContext.java      | 17 ++++-
 .../camel/impl/ExtendedCamelContextConfigurer.java | 20 ++----
 .../camel/impl/lw/LightweightCamelContext.java     | 10 +--
 .../impl/lw/LightweightRuntimeCamelContext.java    |  6 +-
 .../DefaultPackageScanResourceResolverTest.java    |  6 +-
 .../apache/camel/model/LoadRestFromXmlTest.java    |  4 +-
 .../apache/camel/model/LoadRouteFromXmlTest.java   |  5 +-
 .../apache/camel/main/DefaultRoutesCollector.java  | 12 ++--
 .../camel/xml/in/XmlRoutesBuilderLoader.java       |  2 +-
 .../services/org/apache/camel/routes-loader/xml    |  2 +
 .../camel/xml/jaxb/JaxbXmlRoutesBuilderLoader.java |  2 +-
 18 files changed, 166 insertions(+), 74 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 6934821..94b7b13 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
@@ -59,7 +59,7 @@ import org.apache.camel.spi.RestBindingJaxbDataFormatFactory;
 import org.apache.camel.spi.RouteController;
 import org.apache.camel.spi.RouteFactory;
 import org.apache.camel.spi.RouteStartupOrder;
-import org.apache.camel.spi.RoutesBuilderLoader;
+import org.apache.camel.spi.RoutesLoader;
 import org.apache.camel.spi.StartupStepRecorder;
 import org.apache.camel.spi.UnitOfWorkFactory;
 import org.apache.camel.spi.UriFactoryResolver;
@@ -601,20 +601,20 @@ public interface ExtendedCamelContext extends CamelContext {
     /**
      * Gets the {@link XMLRoutesDefinitionLoader} to be used.
      *
-     * @deprecated use {@link #getRoutesBuilderLoader()}
+     * @deprecated use {@link #getRoutesLoader()}
      */
     @Deprecated
     XMLRoutesDefinitionLoader getXMLRoutesDefinitionLoader();
 
     /**
-     * Sets a custom {@link RoutesBuilderLoader} to be used.
+     * Sets a custom {@link RoutesLoader} to be used.
      */
-    void setRoutesBuilderLoader(RoutesBuilderLoader routesBuilderLoader);
+    void setRoutesLoader(RoutesLoader routesLoader);
 
     /**
-     * Gets the {@link RoutesBuilderLoader} to be used.
+     * Gets the {@link RoutesLoader} to be used.
      */
-    RoutesBuilderLoader getRoutesBuilderLoader();
+    RoutesLoader getRoutesLoader();
 
     /**
      * Sets a custom {@link ModelToXMLDumper} to be used.
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java
index 0f844bc..be17fc7 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesBuilderLoader.java
@@ -25,7 +25,12 @@ public interface RoutesBuilderLoader {
     /**
      * Service factory base path for language specific loaders.
      */
-    String LOADERS_FACTORY_PATH = "META-INF/services/org/apache/camel/routes-loaders/";
+    String FACTORY_PATH = "META-INF/services/org/apache/camel/routes-loader/";
+
+    /**
+     * Service factory group.
+     */
+    String FACTORY_GROUP = "routes-loader";
 
     /**
      * Loads {@link RoutesBuilder} from {@link Resource}.
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
new file mode 100644
index 0000000..84fa7f1
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
@@ -0,0 +1,75 @@
+/*
+ * 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.Arrays;
+import java.util.Collection;
+
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.RoutesBuilder;
+
+/**
+ * SPI for loading {@link RoutesBuilder} from a list of {@link Resource}.
+ */
+public interface RoutesLoader extends CamelContextAware {
+    /**
+     * Service factory key.
+     */
+    String FACTORY = "routes-loader";
+
+    /**
+     * Loads {@link RoutesBuilder} from the give list of {@link Resource} into the current
+     * {@link org.apache.camel.CamelContext}.
+     *
+     * @param resources the resources to be loaded.
+     */
+    default void loadRoutes(Collection<Resource> resources) throws Exception {
+        for (RoutesBuilder builder : findRoutesBuilders(resources)) {
+            getCamelContext().addRoutes(builder);
+        }
+    }
+
+    /**
+     * Loads {@link RoutesBuilder} from the give list of {@link Resource} into the current
+     * {@link org.apache.camel.CamelContext}.
+     *
+     * @param resources the resources to be loaded.
+     */
+    default void loadRoutes(Resource... resources) throws Exception {
+        for (RoutesBuilder builder : findRoutesBuilders(resources)) {
+            getCamelContext().addRoutes(builder);
+        }
+    }
+
+    /**
+     * Find {@link RoutesBuilder} from the give list of {@link Resource}.
+     *
+     * @param  resources the resource to be loaded.
+     * @return           a {@link RoutesBuilder}
+     */
+    default Collection<RoutesBuilder> findRoutesBuilders(Resource... resources) throws Exception {
+        return findRoutesBuilders(Arrays.asList(resources));
+    }
+
+    /**
+     * Find {@link RoutesBuilder} from the give list of {@link Resource}.
+     *
+     * @param  resources the resource to be loaded.
+     * @return           a {@link RoutesBuilder}
+     */
+    Collection<RoutesBuilder> findRoutesBuilders(Collection<Resource> resources) throws Exception;
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/XMLRoutesDefinitionLoader.java b/core/camel-api/src/main/java/org/apache/camel/spi/XMLRoutesDefinitionLoader.java
index ab3f1e8..812cce9 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/XMLRoutesDefinitionLoader.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/XMLRoutesDefinitionLoader.java
@@ -23,7 +23,7 @@ import org.apache.camel.CamelContext;
 /**
  * SPI for loading routes/rests from XML input streams and parsing this to model definition classes.
  *
- * @deprecated sue {@link RoutesBuilderLoader}
+ * @deprecated sue {@link RoutesLoader}
  */
 @Deprecated
 public interface XMLRoutesDefinitionLoader {
diff --git a/core/camel-base-engine/src/generated/resources/META-INF/services/org/apache/camel/routes-loader b/core/camel-base-engine/src/generated/resources/META-INF/services/org/apache/camel/routes-loader
new file mode 100644
index 0000000..ce58158
--- /dev/null
+++ b/core/camel-base-engine/src/generated/resources/META-INF/services/org/apache/camel/routes-loader
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.engine.DefaultRoutesLoader
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 89d3828..79cf81d 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -141,7 +141,7 @@ import org.apache.camel.spi.RouteFactory;
 import org.apache.camel.spi.RoutePolicyFactory;
 import org.apache.camel.spi.RouteStartupOrder;
 import org.apache.camel.spi.RouteTemplateParameterSource;
-import org.apache.camel.spi.RoutesBuilderLoader;
+import org.apache.camel.spi.RoutesLoader;
 import org.apache.camel.spi.RuntimeEndpointRegistry;
 import org.apache.camel.spi.ShutdownStrategy;
 import org.apache.camel.spi.StartupStepRecorder;
@@ -284,7 +284,7 @@ public abstract class AbstractCamelContext extends BaseService
     private volatile BeanProxyFactory beanProxyFactory;
     private volatile BeanProcessorFactory beanProcessorFactory;
     private volatile XMLRoutesDefinitionLoader xmlRoutesDefinitionLoader;
-    private volatile RoutesBuilderLoader routesBuilderLoader;
+    private volatile RoutesLoader routesLoader;
     private volatile ModelToXMLDumper modelToXMLDumper;
     private volatile RestBindingJaxbDataFormatFactory restBindingJaxbDataFormatFactory;
     private volatile RuntimeCamelCatalog runtimeCamelCatalog;
@@ -4556,20 +4556,20 @@ public abstract class AbstractCamelContext extends BaseService
     }
 
     @Override
-    public RoutesBuilderLoader getRoutesBuilderLoader() {
-        if (routesBuilderLoader == null) {
+    public RoutesLoader getRoutesLoader() {
+        if (routesLoader == null) {
             synchronized (lock) {
-                if (routesBuilderLoader == null) {
-                    setRoutesBuilderLoader(createRoutesBuilderLoader());
+                if (routesLoader == null) {
+                    setRoutesLoader(createRoutesLoader());
                 }
             }
         }
-        return routesBuilderLoader;
+        return routesLoader;
     }
 
     @Override
-    public void setRoutesBuilderLoader(RoutesBuilderLoader routesBuilderLoader) {
-        this.routesBuilderLoader = doAddService(routesBuilderLoader);
+    public void setRoutesLoader(RoutesLoader routesLoader) {
+        this.routesLoader = doAddService(routesLoader);
     }
 
     public ModelToXMLDumper getModelToXMLDumper() {
@@ -4789,7 +4789,7 @@ public abstract class AbstractCamelContext extends BaseService
 
     protected abstract XMLRoutesDefinitionLoader createXMLRoutesDefinitionLoader();
 
-    protected abstract RoutesBuilderLoader createRoutesBuilderLoader();
+    protected abstract RoutesLoader createRoutesLoader();
 
     protected abstract ModelToXMLDumper createModelToXMLDumper();
 
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesBuilderLoader.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
similarity index 69%
rename from core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesBuilderLoader.java
rename to core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
index 007ec35..227d743 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesBuilderLoader.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
@@ -16,27 +16,31 @@
  */
 package org.apache.camel.impl.engine;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.Optional;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.RoutesBuilder;
-import org.apache.camel.spi.ClassResolver;
 import org.apache.camel.spi.FactoryFinder;
-import org.apache.camel.spi.FactoryFinderResolver;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.RoutesBuilderLoader;
+import org.apache.camel.spi.RoutesLoader;
+import org.apache.camel.spi.annotations.JdkService;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.ObjectHelper;
 
-public class DefaultRoutesBuilderLoader implements RoutesBuilderLoader, CamelContextAware {
+@JdkService(RoutesLoader.FACTORY)
+public class DefaultRoutesLoader implements RoutesLoader {
     private CamelContext camelContext;
 
-    public DefaultRoutesBuilderLoader() {
+    public DefaultRoutesLoader() {
     }
 
-    public DefaultRoutesBuilderLoader(CamelContext camelContext) {
+    public DefaultRoutesLoader(CamelContext camelContext) {
         this.camelContext = camelContext;
     }
 
@@ -51,15 +55,21 @@ public class DefaultRoutesBuilderLoader implements RoutesBuilderLoader, CamelCon
     }
 
     @Override
-    public RoutesBuilder loadRoutesBuilder(Resource resource) throws Exception {
-        // language is derived from the file extension
-        final String language = FileUtil.onlyExt(resource.getLocation(), true);
+    public Collection<RoutesBuilder> findRoutesBuilders(Collection<Resource> resources) throws Exception {
+        List<RoutesBuilder> answer = new ArrayList<>(resources.size());
 
-        if (ObjectHelper.isEmpty(language)) {
-            throw new IllegalArgumentException("Unable to determine language for resource: " + resource.getLocation());
+        for (Resource resource : resources) {
+            // language is derived from the file extension
+            final String language = FileUtil.onlyExt(resource.getLocation(), true);
+
+            if (ObjectHelper.isEmpty(language)) {
+                throw new IllegalArgumentException("Unable to determine language for resource: " + resource.getLocation());
+            }
+
+            answer.add(getLoader(language).loadRoutesBuilder(resource));
         }
 
-        return getLoader(language).loadRoutesBuilder(resource);
+        return answer;
     }
 
     private RoutesBuilderLoader getLoader(String language) {
@@ -67,9 +77,7 @@ public class DefaultRoutesBuilderLoader implements RoutesBuilderLoader, CamelCon
 
         if (answer == null) {
             final ExtendedCamelContext ecc = getCamelContext(ExtendedCamelContext.class);
-            final FactoryFinderResolver ffr = ecc.getFactoryFinderResolver();
-            final ClassResolver cr = ecc.getClassResolver();
-            final FactoryFinder finder = ffr.resolveBootstrapFactoryFinder(cr, RoutesBuilderLoader.LOADERS_FACTORY_PATH);
+            final FactoryFinder finder = ecc.getFactoryFinder(RoutesBuilderLoader.FACTORY_PATH);
 
             final BaseServiceResolver<RoutesBuilderLoader> resolver
                     = new BaseServiceResolver<>(language, RoutesBuilderLoader.class, finder);
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
index c998750..9ca22de 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
@@ -65,7 +65,7 @@ import org.apache.camel.spi.RestBindingJaxbDataFormatFactory;
 import org.apache.camel.spi.RestRegistryFactory;
 import org.apache.camel.spi.RouteController;
 import org.apache.camel.spi.RouteFactory;
-import org.apache.camel.spi.RoutesBuilderLoader;
+import org.apache.camel.spi.RoutesLoader;
 import org.apache.camel.spi.ShutdownStrategy;
 import org.apache.camel.spi.StreamCachingStrategy;
 import org.apache.camel.spi.Tracer;
@@ -412,8 +412,19 @@ public class SimpleCamelContext extends AbstractCamelContext {
     }
 
     @Override
-    protected RoutesBuilderLoader createRoutesBuilderLoader() {
-        return new DefaultRoutesBuilderLoader();
+    protected RoutesLoader createRoutesLoader() {
+        BaseServiceResolver<RoutesLoader> resolver = new BaseServiceResolver<>(
+                RoutesLoader.FACTORY,
+                RoutesLoader.class,
+                getBootstrapFactoryFinder());
+
+        Optional<RoutesLoader> result = resolver.resolve(getCamelContextReference());
+        if (result.isPresent()) {
+            return result.get();
+        } else {
+            throw new IllegalArgumentException(
+                    "Cannot find RoutesLoader on classpath.");
+        }
     }
 
     @Override
diff --git a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
index 43ed602..5e5e2fa 100644
--- a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
+++ b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
@@ -1,15 +1,9 @@
 /* Generated by camel build tools - do NOT edit this file! */
 package org.apache.camel.impl;
 
-import java.util.Map;
-
 import org.apache.camel.CamelContext;
-import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
-import org.apache.camel.spi.PropertyConfigurerGetter;
-import org.apache.camel.spi.ConfigurerStrategy;
 import org.apache.camel.spi.GeneratedPropertyConfigurer;
-import org.apache.camel.util.CaseInsensitiveMap;
-import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.spi.PropertyConfigurerGetter;
 
 /**
  * Generated by camel build tools - do NOT edit this file!
@@ -135,8 +129,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com
         case "RouteController": target.setRouteController(property(camelContext, org.apache.camel.spi.RouteController.class, value)); return true;
         case "routefactory":
         case "RouteFactory": target.setRouteFactory(property(camelContext, org.apache.camel.spi.RouteFactory.class, value)); return true;
-        case "routesbuilderloader":
-        case "RoutesBuilderLoader": target.setRoutesBuilderLoader(property(camelContext, org.apache.camel.spi.RoutesBuilderLoader.class, value)); return true;
+        case "routesloader":
+        case "RoutesLoader": target.setRoutesLoader(property(camelContext, org.apache.camel.spi.RoutesLoader.class, value)); return true;
         case "runtimecamelcatalog":
         case "RuntimeCamelCatalog": target.setRuntimeCamelCatalog(property(camelContext, org.apache.camel.catalog.RuntimeCamelCatalog.class, value)); return true;
         case "runtimeendpointregistry":
@@ -302,8 +296,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com
         case "RouteController": return org.apache.camel.spi.RouteController.class;
         case "routefactory":
         case "RouteFactory": return org.apache.camel.spi.RouteFactory.class;
-        case "routesbuilderloader":
-        case "RoutesBuilderLoader": return org.apache.camel.spi.RoutesBuilderLoader.class;
+        case "routesloader":
+        case "RoutesLoader": return org.apache.camel.spi.RoutesLoader.class;
         case "runtimecamelcatalog":
         case "RuntimeCamelCatalog": return org.apache.camel.catalog.RuntimeCamelCatalog.class;
         case "runtimeendpointregistry":
@@ -470,8 +464,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com
         case "RouteController": return target.getRouteController();
         case "routefactory":
         case "RouteFactory": return target.getRouteFactory();
-        case "routesbuilderloader":
-        case "RoutesBuilderLoader": return target.getRoutesBuilderLoader();
+        case "routesloader":
+        case "RoutesLoader": return target.getRoutesLoader();
         case "runtimecamelcatalog":
         case "RuntimeCamelCatalog": return target.getRuntimeCamelCatalog();
         case "runtimeendpointregistry":
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
index 6cb4d71..1f98975 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
@@ -123,7 +123,7 @@ import org.apache.camel.spi.RouteController;
 import org.apache.camel.spi.RouteFactory;
 import org.apache.camel.spi.RoutePolicyFactory;
 import org.apache.camel.spi.RouteStartupOrder;
-import org.apache.camel.spi.RoutesBuilderLoader;
+import org.apache.camel.spi.RoutesLoader;
 import org.apache.camel.spi.RuntimeEndpointRegistry;
 import org.apache.camel.spi.ShutdownStrategy;
 import org.apache.camel.spi.StartupStepRecorder;
@@ -1466,13 +1466,13 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam
     }
 
     @Override
-    public void setRoutesBuilderLoader(RoutesBuilderLoader routesBuilderLoader) {
-        getExtendedCamelContext().setRoutesBuilderLoader(routesBuilderLoader);
+    public void setRoutesLoader(RoutesLoader routesLoader) {
+        getExtendedCamelContext().setRoutesLoader(routesLoader);
     }
 
     @Override
-    public RoutesBuilderLoader getRoutesBuilderLoader() {
-        return getExtendedCamelContext().getRoutesBuilderLoader();
+    public RoutesLoader getRoutesLoader() {
+        return getExtendedCamelContext().getRoutesLoader();
     }
 
     @Override
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
index f5867e0..31f4bbb 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
@@ -120,7 +120,7 @@ import org.apache.camel.spi.RouteController;
 import org.apache.camel.spi.RouteFactory;
 import org.apache.camel.spi.RoutePolicyFactory;
 import org.apache.camel.spi.RouteStartupOrder;
-import org.apache.camel.spi.RoutesBuilderLoader;
+import org.apache.camel.spi.RoutesLoader;
 import org.apache.camel.spi.RuntimeEndpointRegistry;
 import org.apache.camel.spi.ShutdownStrategy;
 import org.apache.camel.spi.StartupStepRecorder;
@@ -1752,12 +1752,12 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat
     }
 
     @Override
-    public void setRoutesBuilderLoader(RoutesBuilderLoader routesBuilderLoader) {
+    public void setRoutesLoader(RoutesLoader routesLoader) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public RoutesBuilderLoader getRoutesBuilderLoader() {
+    public RoutesLoader getRoutesLoader() {
         throw new UnsupportedOperationException();
     }
 
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolverTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolverTest.java
index 24c08f0..a69224a 100644
--- a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolverTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultPackageScanResourceResolverTest.java
@@ -46,10 +46,8 @@ public class DefaultPackageScanResourceResolverTest {
         ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);
         try {
             for (Resource resource : ecc.getPackageScanResourceResolver().findResources(path)) {
-                RoutesBuilder builder = ecc.getRoutesBuilderLoader().loadRoutesBuilder(resource);
-                if (builder != null) {
-                    answer.add(builder);
-                }
+                answer.addAll(
+                        ecc.getRoutesLoader().findRoutesBuilders(resource));
             }
         } catch (Exception e) {
             throw new RuntimeException(e);
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/LoadRestFromXmlTest.java b/core/camel-core/src/test/java/org/apache/camel/model/LoadRestFromXmlTest.java
index 0700d0d..cb099cf 100644
--- a/core/camel-core/src/test/java/org/apache/camel/model/LoadRestFromXmlTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/model/LoadRestFromXmlTest.java
@@ -20,7 +20,6 @@ import java.io.InputStream;
 
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.rest.DummyRestConsumerFactory;
@@ -86,9 +85,8 @@ public class LoadRestFromXmlTest extends ContextTestSupport {
         // load rest from XML and add them to the existing camel context
         ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);
         Resource resource = Resource.fromClasspath(LoadRouteFromXmlTest.class, "barRest.xml");
-        RoutesBuilder routes = ecc.getRoutesBuilderLoader().loadRoutesBuilder(resource);
 
-        context.addRoutes(routes);
+        ecc.getRoutesLoader().loadRoutes(resource);
 
         assertNotNull(context.getRoute("route1"), "Loaded rest route should be there");
         assertEquals(3, context.getRoutes().size());
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlTest.java b/core/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlTest.java
index 9b49251..d8e47b9 100644
--- a/core/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlTest.java
@@ -20,7 +20,6 @@ import java.io.InputStream;
 
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.spi.Resource;
@@ -75,9 +74,9 @@ public class LoadRouteFromXmlTest extends ContextTestSupport {
         // load route from XML and add them to the existing camel context
         ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);
         Resource resource = Resource.fromClasspath(LoadRouteFromXmlTest.class, "barRoute.xml");
-        RoutesBuilder routes = ecc.getRoutesBuilderLoader().loadRoutesBuilder(resource);
 
-        context.addRoutes(routes);
+        ecc.getRoutesLoader().loadRoutes(resource);
+
         // END SNIPPET: e1
 
         assertNotNull(context.getRoute("bar"), "Loaded bar route should be there");
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultRoutesCollector.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultRoutesCollector.java
index 1dc1522..cbe21d1 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultRoutesCollector.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultRoutesCollector.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
@@ -126,7 +127,7 @@ public class DefaultRoutesCollector implements RoutesCollector {
         }
 
         StopWatch watch = new StopWatch();
-        int count = 0;
+        AtomicInteger count = new AtomicInteger();
 
         for (String include : includes) {
             log.debug("Loading additional RoutesBuilder from: {}", include);
@@ -137,18 +138,17 @@ public class DefaultRoutesCollector implements RoutesCollector {
                     }
 
                     log.debug("Found route builder from location: {}", include);
-                    RoutesBuilder builder = ecc.getRoutesBuilderLoader().loadRoutesBuilder(resource);
-                    if (builder != null) {
+                    ecc.getRoutesLoader().findRoutesBuilders(resource).forEach(builder -> {
                         answer.add(builder);
-                        count++;
-                    }
+                        count.incrementAndGet();
+                    });
                 }
             } catch (FileNotFoundException e) {
                 log.debug("No RoutesBuilder found in {}. Skipping detection.", include);
             } catch (Exception e) {
                 throw RuntimeCamelException.wrapRuntimeException(e);
             }
-            if (count > 0) {
+            if (count.get() > 0) {
                 log.info("Loaded {} ({} millis) additional RoutesBuilder from: {}, pattern: {}", count, watch.taken(), include,
                         includePattern);
             } else {
diff --git a/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/XmlRoutesBuilderLoader.java b/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/XmlRoutesBuilderLoader.java
index 5fc9e16..99457d1 100644
--- a/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/XmlRoutesBuilderLoader.java
+++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/XmlRoutesBuilderLoader.java
@@ -29,7 +29,7 @@ import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.RoutesBuilderLoader;
 import org.apache.camel.spi.annotations.JdkService;
 
-@JdkService("routes-loaders/xml")
+@JdkService(RoutesBuilderLoader.FACTORY_GROUP + "/xml")
 public class XmlRoutesBuilderLoader implements RoutesBuilderLoader, CamelContextAware {
     public static final String NAMESPACE = "http://camel.apache.org/schema/spring";
 
diff --git a/core/camel-xml-jaxb/src/generated/resources/META-INF/services/org/apache/camel/routes-loader/xml b/core/camel-xml-jaxb/src/generated/resources/META-INF/services/org/apache/camel/routes-loader/xml
new file mode 100644
index 0000000..daa444e
--- /dev/null
+++ b/core/camel-xml-jaxb/src/generated/resources/META-INF/services/org/apache/camel/routes-loader/xml
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.xml.jaxb.JaxbXmlRoutesBuilderLoader
diff --git a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbXmlRoutesBuilderLoader.java b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
index df23f47..619ce56 100644
--- a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
+++ b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
@@ -31,7 +31,7 @@ import static org.apache.camel.xml.jaxb.JaxbHelper.loadRestsDefinition;
 import static org.apache.camel.xml.jaxb.JaxbHelper.loadRouteTemplatesDefinition;
 import static org.apache.camel.xml.jaxb.JaxbHelper.loadRoutesDefinition;
 
-@JdkService("routes-loaders/xml")
+@JdkService(RoutesBuilderLoader.FACTORY_GROUP + "/xml")
 public class JaxbXmlRoutesBuilderLoader implements RoutesBuilderLoader, CamelContextAware {
     public static final String NAMESPACE = "http://camel.apache.org/schema/spring";