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 2023/08/21 13:01:11 UTC

[camel] branch main updated: dump route strategy (#11159)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new c806dd89d93 dump route strategy (#11159)
c806dd89d93 is described below

commit c806dd89d93f952b94e50d54faf5d9f50f74d680
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Aug 21 15:01:05 2023 +0200

    dump route strategy (#11159)
    
    CAMEL-19765: camel-core - SPI for DumpRouteStrategy.
---
 .../main/camel-main-configuration-metadata.json    |   5 +
 .../test/junit5/params/ParameterizedExtension.java |   3 +-
 .../main/java/org/apache/camel/CamelContext.java   |   3 +-
 .../org/apache/camel/spi/DumpRoutesStrategy.java   |  77 ++++
 .../camel/impl/engine/AbstractCamelContext.java    |   4 +
 .../impl/engine/BaseExecutorServiceManager.java    |   4 +-
 .../camel/impl/engine/SimpleCamelContext.java      |  32 ++
 core/camel-core-engine/pom.xml                     |   1 +
 .../impl/DefaultDumpRoutesStrategyConfigurer.java  |  79 ++++
 ...org.apache.camel.impl.DefaultDumpRoutesStrategy |   2 +
 .../services/org/apache/camel/default-dump-routes  |   2 +
 .../org/apache/camel/impl/DefaultCamelContext.java | 118 +-----
 .../camel/impl/DefaultDumpRoutesStrategy.java      | 418 +++++++++++++++++++++
 .../org/apache/camel/builder/RouteBuilder.java     |   9 +-
 .../camel/model/OptionalIdentifiedDefinition.java  |   2 +-
 .../apache/camel/model/RouteDefinitionHelper.java  |   3 +-
 .../camel/model/RouteTemplateDefinition.java       |  14 +-
 .../camel/model/RouteTemplatesDefinition.java      |  18 +-
 .../apache/camel/model/rest/RestDefinition.java    |  15 +-
 .../apache/camel/model/rest/RestsDefinition.java   |  21 +-
 .../camel/builder/FluentProducerTemplateTest.java  |   4 +-
 .../apache/camel/builder/NotifyBuilderTest.java    |   3 +-
 .../catalog/CustomEndpointUriFactoryTest.java      |   3 +-
 .../bean/BeanInfoAMoreComplexOverloadedTest.java   |   1 -
 .../bean/BeanInfoWithBridgedMethodTest.java        |   9 +-
 .../component/bean/BeanProxyNoBindingTest.java     |   2 +-
 .../component/bean/BeanRefMethodNotFoundTest.java  |   2 +-
 .../camel/processor/async/MyAsyncComponent.java    |   1 -
 .../MainConfigurationPropertiesConfigurer.java     |  30 ++
 .../camel-main-configuration-metadata.json         |   5 +
 core/camel-main/src/main/docs/main.adoc            |   7 +-
 .../camel/main/DefaultConfigurationConfigurer.java |   9 +
 .../camel/main/DefaultConfigurationProperties.java | 108 ++++++
 .../mbean/ManagedDumpRoutesStrategyMBean.java      |  63 ++++
 .../DefaultManagementObjectNameStrategy.java       |   4 +
 .../management/JmxManagementLifecycleStrategy.java |   6 +
 .../management/mbean/ManagedDumpRouteStrategy.java | 112 ++++++
 .../management/ManagedRouteDumpStrategyTest.java   | 103 +++++
 .../java/org/apache/camel/util/ObjectHelper.java   |   1 -
 .../java/org/apache/camel/util/StringHelper.java   |   7 +-
 .../java/org/apache/camel/xml/jaxb/JaxbHelper.java |  34 ++
 .../camel/xml/jaxb/JaxbModelToXMLDumper.java       |   3 +
 .../org/apache/camel/tooling/util/Strings.java     |   4 +-
 43 files changed, 1203 insertions(+), 148 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 7e4a2e04b05..e49a846be05 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -39,6 +39,11 @@
     { "name": "camel.main.description", "description": "Sets the description (intended for humans) of the Camel application.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
     { "name": "camel.main.devConsoleEnabled", "description": "Whether to enable developer console (requires camel-console on classpath). The developer console is only for assisting during development. This is NOT for production usage.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.dumpRoutes", "description": "If dumping is enabled then Camel will during startup dump all loaded routes (incl rests and route templates) represented as XML\/YAML DSL into the log. This is intended for trouble shooting or to assist during development. Sensitive information that may be configured in the route endpoints could potentially be included in the dump output and is therefore not recommended being used for production usage. This requires to have camel-xml [...]
+    { "name": "camel.main.dumpRoutesDirectory", "description": "Whether to save route dumps to files in the given directory. The name of the files are based on original loaded resource, or an autogenerated name.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
+    { "name": "camel.main.dumpRoutesInclude", "description": "Controls what to include in output for route dumping. Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "routes" },
+    { "name": "camel.main.dumpRoutesLog", "description": "Whether to log route dumps to Logger", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true },
+    { "name": "camel.main.dumpRoutesResolvePlaceholders", "description": "Whether to resolve property placeholders in the dumped output. Default is true.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true },
+    { "name": "camel.main.dumpRoutesUriAsParameters", "description": "When dumping routes to YAML format, then this option controls whether endpoint URIs should be expanded into a key\/value parameters.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.durationHitExitCode", "description": "Sets the exit code for the application if duration was hit", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "integer", "javaType": "int" },
     { "name": "camel.main.durationMaxAction", "description": "Controls whether the Camel application should shutdown the JVM, or stop all routes, when duration max is triggered.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "shutdown", "enum": [ "shutdown", "stop" ] },
     { "name": "camel.main.durationMaxIdleSeconds", "description": "To specify for how long time in seconds Camel can be idle before automatic terminating the JVM. You can use this to run Camel for a short while.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int" },
diff --git a/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/params/ParameterizedExtension.java b/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/params/ParameterizedExtension.java
index 4751276be23..ee2fc3006cf 100644
--- a/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/params/ParameterizedExtension.java
+++ b/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/params/ParameterizedExtension.java
@@ -144,8 +144,7 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv
         }
 
         private ParameterContext getContext() throws NoSuchMethodException {
-            Executable executable =
-                    this.getClass().getConstructor(Object[].class).getParameters()[0].getDeclaringExecutable();
+            Executable executable = this.getClass().getConstructor(Object[].class).getParameters()[0].getDeclaringExecutable();
             ParameterContext parameterContext = mock(ParameterContext.class);
             when(parameterContext.getDeclaringExecutable()).thenReturn(executable);
             return parameterContext;
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 0a7464354ec..041bb697acf 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -1401,7 +1401,8 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
      *
      * This requires to have camel-xml-io/camel-yaml-io on the classpath to be able to dump the routes as XML/YAML.
      *
-     * @param format xml or yaml
+     * @param format xml or yaml (additional configuration can be specified using query parameters, eg
+     *               ?include=all&uriAsParameters=true)
      */
     void setDumpRoutes(String format);
 
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/DumpRoutesStrategy.java b/core/camel-api/src/main/java/org/apache/camel/spi/DumpRoutesStrategy.java
new file mode 100644
index 00000000000..a9c3e04691d
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/DumpRoutesStrategy.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.apache.camel.StaticService;
+
+/**
+ * Strategy for dumping routes during startup dump all loaded routes (incl rests and route templates).
+ */
+public interface DumpRoutesStrategy extends StaticService {
+
+    /**
+     * Service factory key.
+     */
+    String FACTORY = "dump-routes";
+
+    /**
+     * Dump routes
+     *
+     * @param format xml or yaml
+     */
+    void dumpRoutes(String format);
+
+    String getInclude();
+
+    /**
+     * Controls what to include in output.
+     *
+     * Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes.
+     */
+    void setInclude(String include);
+
+    boolean isResolvePlaceholders();
+
+    /**
+     * Whether to resolve property placeholders in the dumped output. Default is true.
+     */
+    void setResolvePlaceholders(boolean resolvePlaceholders);
+
+    boolean isUriAsParameters();
+
+    /**
+     * When dumping to YAML format, then this option controls whether endpoint URIs should be expanded into a key/value
+     * parameters.
+     */
+    void setUriAsParameters(boolean uriAsParameters);
+
+    boolean isLog();
+
+    /**
+     * Whether to log route dumps to Logger
+     */
+    void setLog(boolean log);
+
+    String getDirectory();
+
+    /**
+     * Whether to save route dumps to files in the given directory. The name of the files are based on original loaded
+     * resource, or an autogenerated name.
+     */
+    void setDirectory(String directory);
+
+}
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 c92234628a6..1b18b86631e 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
@@ -101,6 +101,7 @@ import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.Debugger;
 import org.apache.camel.spi.DebuggerFactory;
 import org.apache.camel.spi.DeferServiceFactory;
+import org.apache.camel.spi.DumpRoutesStrategy;
 import org.apache.camel.spi.EndpointRegistry;
 import org.apache.camel.spi.EndpointStrategy;
 import org.apache.camel.spi.EventNotifier;
@@ -385,6 +386,7 @@ public abstract class AbstractCamelContext extends BaseService
         camelContextExtension.lazyAddContextPlugin(DeferServiceFactory.class, this::createDeferServiceFactory);
         camelContextExtension.lazyAddContextPlugin(AnnotationBasedProcessorFactory.class,
                 this::createAnnotationBasedProcessorFactory);
+        camelContextExtension.lazyAddContextPlugin(DumpRoutesStrategy.class, this::createDumpRoutesStrategy);
     }
 
     protected static <T> T lookup(CamelContext context, String ref, Class<T> type) {
@@ -4064,6 +4066,8 @@ public abstract class AbstractCamelContext extends BaseService
 
     protected abstract RuntimeCamelCatalog createRuntimeCamelCatalog();
 
+    protected abstract DumpRoutesStrategy createDumpRoutesStrategy();
+
     protected abstract Tracer createTracer();
 
     protected abstract LanguageResolver createLanguageResolver();
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/BaseExecutorServiceManager.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/BaseExecutorServiceManager.java
index ea7f8c8a482..529483f5ba0 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/BaseExecutorServiceManager.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/BaseExecutorServiceManager.java
@@ -476,8 +476,8 @@ public class BaseExecutorServiceManager extends ServiceSupport implements Execut
                     }
                 } catch (Exception e) {
                     // only log if something goes wrong as we want to shutdown them all
-                    LOG.warn("Error occurred during shutdown of ExecutorService: {}. This exception will be ignored.", 
-                          executorService, e);
+                    LOG.warn("Error occurred during shutdown of ExecutorService: {}. This exception will be ignored.",
+                            executorService, e);
                 }
             }
         }
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 6bc6a1437a8..49ca74f5a37 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
@@ -47,6 +47,7 @@ import org.apache.camel.spi.ComponentResolver;
 import org.apache.camel.spi.ConfigurerResolver;
 import org.apache.camel.spi.DataFormatResolver;
 import org.apache.camel.spi.DeferServiceFactory;
+import org.apache.camel.spi.DumpRoutesStrategy;
 import org.apache.camel.spi.EndpointRegistry;
 import org.apache.camel.spi.ExchangeFactory;
 import org.apache.camel.spi.ExchangeFactoryManager;
@@ -410,6 +411,37 @@ public class SimpleCamelContext extends AbstractCamelContext {
         }
     }
 
+    @Override
+    protected DumpRoutesStrategy createDumpRoutesStrategy() {
+        DumpRoutesStrategy answer = getCamelContextReference().hasService(DumpRoutesStrategy.class);
+        if (answer != null) {
+            return answer;
+        }
+
+        // is there any custom which we prioritize over default
+        Optional<DumpRoutesStrategy> result = ResolverHelper.resolveService(
+                getCamelContextReference(),
+                getBootstrapFactoryFinder(),
+                DumpRoutesStrategy.FACTORY,
+                DumpRoutesStrategy.class);
+
+        if (result.isEmpty()) {
+            // lookup default factory
+            result = ResolverHelper.resolveService(
+                    getCamelContextReference(),
+                    getBootstrapFactoryFinder(),
+                    "default-" + DumpRoutesStrategy.FACTORY,
+                    DumpRoutesStrategy.class);
+        }
+
+        if (result.isPresent()) {
+            return result.get();
+        } else {
+            throw new IllegalArgumentException(
+                    "Cannot find DumpRoutesStrategy on classpath. Add camel-core-engine to classpath.");
+        }
+    }
+
     @Override
     protected CamelContextNameStrategy createCamelContextNameStrategy() {
         return new DefaultCamelContextNameStrategy();
diff --git a/core/camel-core-engine/pom.xml b/core/camel-core-engine/pom.xml
index f24bd548d79..324277ca937 100644
--- a/core/camel-core-engine/pom.xml
+++ b/core/camel-core-engine/pom.xml
@@ -128,6 +128,7 @@
                                 <!-- we want to have configurer for RestConfiguration in camel-core-engine -->
                                 <class>org.apache.camel.spi.RestConfiguration=org.apache.camel.impl.RestConfiguration</class>
                                 <class>org.apache.camel.CamelContext=org.apache.camel.impl.CamelContext</class>
+                                <class>org.apache.camel.impl.DefaultDumpRoutesStrategy</class>
                             </classes>
                         </configuration>
                     </execution>
diff --git a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/DefaultDumpRoutesStrategyConfigurer.java b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/DefaultDumpRoutesStrategyConfigurer.java
new file mode 100644
index 00000000000..69ed6aad744
--- /dev/null
+++ b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/DefaultDumpRoutesStrategyConfigurer.java
@@ -0,0 +1,79 @@
+/* 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.impl.DefaultDumpRoutesStrategy;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class DefaultDumpRoutesStrategyConfigurer extends org.apache.camel.support.component.PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        org.apache.camel.impl.DefaultDumpRoutesStrategy target = (org.apache.camel.impl.DefaultDumpRoutesStrategy) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": target.setCamelContext(property(camelContext, org.apache.camel.CamelContext.class, value)); return true;
+        case "directory":
+        case "Directory": target.setDirectory(property(camelContext, java.lang.String.class, value)); return true;
+        case "include":
+        case "Include": target.setInclude(property(camelContext, java.lang.String.class, value)); return true;
+        case "log":
+        case "Log": target.setLog(property(camelContext, boolean.class, value)); return true;
+        case "resolveplaceholders":
+        case "ResolvePlaceholders": target.setResolvePlaceholders(property(camelContext, boolean.class, value)); return true;
+        case "uriasparameters":
+        case "UriAsParameters": target.setUriAsParameters(property(camelContext, boolean.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": return org.apache.camel.CamelContext.class;
+        case "directory":
+        case "Directory": return java.lang.String.class;
+        case "include":
+        case "Include": return java.lang.String.class;
+        case "log":
+        case "Log": return boolean.class;
+        case "resolveplaceholders":
+        case "ResolvePlaceholders": return boolean.class;
+        case "uriasparameters":
+        case "UriAsParameters": return boolean.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.impl.DefaultDumpRoutesStrategy target = (org.apache.camel.impl.DefaultDumpRoutesStrategy) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "CamelContext": return target.getCamelContext();
+        case "directory":
+        case "Directory": return target.getDirectory();
+        case "include":
+        case "Include": return target.getInclude();
+        case "log":
+        case "Log": return target.isLog();
+        case "resolveplaceholders":
+        case "ResolvePlaceholders": return target.isResolvePlaceholders();
+        case "uriasparameters":
+        case "UriAsParameters": return target.isUriAsParameters();
+        default: return null;
+        }
+    }
+}
+
diff --git a/core/camel-core-engine/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.DefaultDumpRoutesStrategy b/core/camel-core-engine/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.DefaultDumpRoutesStrategy
new file mode 100644
index 00000000000..cf99a6b5c02
--- /dev/null
+++ b/core/camel-core-engine/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.DefaultDumpRoutesStrategy
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.DefaultDumpRoutesStrategyConfigurer
diff --git a/core/camel-core-engine/src/generated/resources/META-INF/services/org/apache/camel/default-dump-routes b/core/camel-core-engine/src/generated/resources/META-INF/services/org/apache/camel/default-dump-routes
new file mode 100644
index 00000000000..336d9abf4a8
--- /dev/null
+++ b/core/camel-core-engine/src/generated/resources/META-INF/services/org/apache/camel/default-dump-routes
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.DefaultDumpRoutesStrategy
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index 15a4a6165bb..582c9848026 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -55,23 +55,19 @@ import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.RouteTemplateDefinition;
-import org.apache.camel.model.RouteTemplatesDefinition;
-import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.TemplatedRouteDefinition;
 import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.language.ExpressionDefinition;
 import org.apache.camel.model.rest.RestDefinition;
-import org.apache.camel.model.rest.RestsDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.model.validator.ValidatorDefinition;
 import org.apache.camel.spi.BeanRepository;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DumpRoutesStrategy;
 import org.apache.camel.spi.ExecutorServiceManager;
 import org.apache.camel.spi.LocalBeanRepositoryAware;
 import org.apache.camel.spi.ModelReifierFactory;
-import org.apache.camel.spi.ModelToXMLDumper;
-import org.apache.camel.spi.ModelToYAMLDumper;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.Registry;
@@ -82,12 +78,10 @@ import org.apache.camel.spi.Validator;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.DefaultRegistry;
 import org.apache.camel.support.LocalBeanRegistry;
-import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.SimpleUuidGenerator;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.OrderedLocationProperties;
 import org.apache.camel.util.StopWatch;
-import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.concurrent.NamedThreadLocal;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -154,112 +148,12 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
 
     @Override
     protected void doDumpRoutes() {
-        if ("yaml".equalsIgnoreCase(getDumpRoutes())) {
-            doDumpRoutesAsYaml();
-        } else {
-            // xml is default
-            doDumpRoutesAsXml();
-        }
-    }
-
-    protected void doDumpRoutesAsXml() {
-        final ModelToXMLDumper dumper = PluginHelper.getModelToXMLDumper(this);
-
-        int size = getRouteDefinitions().size();
-        if (size > 0) {
-            LOG.info("Dumping {} routes as XML", size);
-            // for XML to output nicely all routes in one XML then lets put them into <routes>
-            RoutesDefinition def = new RoutesDefinition();
-            def.setRoutes(getRouteDefinitions());
-            try {
-                String xml = dumper.dumpModelAsXml(this, def, true);
-                // lets separate routes with empty line
-                xml = StringHelper.replaceFirst(xml, "xmlns=\"http://camel.apache.org/schema/spring\">",
-                        "xmlns=\"http://camel.apache.org/schema/spring\">\n");
-                xml = xml.replace("</route>", "</route>\n");
-                LOG.info("\n\n{}\n", xml);
-            } catch (Exception e) {
-                LOG.warn("Error dumping routes to XML due to {}. This exception is ignored.", e.getMessage(), e);
-            }
-        }
-
-        size = getRestDefinitions().size();
-        if (size > 0) {
-            LOG.info("Dumping {} rests as XML", size);
-            // for XML to output nicely all routes in one XML then lets put them into <routes>
-            RestsDefinition def = new RestsDefinition();
-            def.setRests(getRestDefinitions());
-            try {
-                String xml = dumper.dumpModelAsXml(this, def, true);
-                // lets separate rests with empty line
-                xml = StringHelper.replaceFirst(xml, "xmlns=\"http://camel.apache.org/schema/spring\">",
-                        "xmlns=\"http://camel.apache.org/schema/spring\">\n");
-                xml = xml.replace("</rest>", "</rest>\n");
-                LOG.info("\n\n{}\n", xml);
-            } catch (Exception e) {
-                LOG.warn("Error dumping rests to XML due to {}. This exception is ignored.", e.getMessage(), e);
-            }
-        }
-
-        size = getRouteTemplateDefinitions().size();
-        if (size > 0) {
-            LOG.info("Dumping {} route templates as XML", size);
-            // for XML to output nicely all routes in one XML then lets put them into <routes>
-            RouteTemplatesDefinition def = new RouteTemplatesDefinition();
-            def.setRouteTemplates(getRouteTemplateDefinitions());
-            try {
-                String xml = dumper.dumpModelAsXml(this, def, true);
-                // lets separate rests with empty line
-                xml = StringHelper.replaceFirst(xml, "xmlns=\"http://camel.apache.org/schema/spring\">",
-                        "xmlns=\"http://camel.apache.org/schema/spring\">\n");
-                xml = xml.replace("</routeTemplate>", "</routeTemplate>\n");
-                LOG.info("\n\n{}\n", xml);
-            } catch (Exception e) {
-                LOG.warn("Error dumping route-templates to XML due to {}. This exception is ignored.", e.getMessage(), e);
-            }
+        DumpRoutesStrategy strategy = CamelContextHelper.findSingleByType(this, DumpRoutesStrategy.class);
+        if (strategy == null) {
+            strategy = getCamelContextExtension().getContextPlugin(DumpRoutesStrategy.class);
         }
-    }
-
-    protected void doDumpRoutesAsYaml() {
-        final ModelToYAMLDumper dumper = PluginHelper.getModelToYAMLDumper(this);
-
-        int size = getRouteDefinitions().size();
-        if (size > 0) {
-            LOG.info("Dumping {} routes as YAML", size);
-            RoutesDefinition def = new RoutesDefinition();
-            def.setRoutes(getRouteDefinitions());
-            try {
-                String yaml = dumper.dumpModelAsYaml(this, def, true, false);
-                LOG.info("\n\n{}\n", yaml);
-            } catch (Exception e) {
-                LOG.warn("Error dumping routes to YAML due to {}. This exception is ignored.", e.getMessage(), e);
-            }
-        }
-
-        size = getRestDefinitions().size();
-        if (size > 0) {
-            LOG.info("Dumping {} rests as YAML", size);
-            RestsDefinition def = new RestsDefinition();
-            def.setRests(getRestDefinitions());
-            try {
-                String taml = dumper.dumpModelAsYaml(this, def, true, false);
-                LOG.info("\n\n{}\n", taml);
-            } catch (Exception e) {
-                LOG.warn("Error dumping rests to YAML due to {}. This exception is ignored.", e.getMessage(), e);
-            }
-        }
-
-        size = getRouteTemplateDefinitions().size();
-        if (size > 0) {
-            LOG.info("Dumping {} route templates as YAML", size);
-            RouteTemplatesDefinition def = new RouteTemplatesDefinition();
-            def.setRouteTemplates(getRouteTemplateDefinitions());
-            try {
-                String yaml = dumper.dumpModelAsYaml(this, def, true, false);
-                LOG.info("\n\n{}\n", yaml);
-            } catch (Exception e) {
-                LOG.warn("Error dumping route-templates to YAML due to {}. This exception is ignored.", e.getMessage(), e);
-            }
+        if (strategy != null) {
+            strategy.dumpRoutes(getDumpRoutes());
         }
     }
 
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultDumpRoutesStrategy.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultDumpRoutesStrategy.java
new file mode 100644
index 00000000000..b002b0211ca
--- /dev/null
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultDumpRoutesStrategy.java
@@ -0,0 +1,418 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.NamedNode;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.RouteTemplateDefinition;
+import org.apache.camel.model.RouteTemplatesDefinition;
+import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.model.rest.RestDefinition;
+import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.spi.DumpRoutesStrategy;
+import org.apache.camel.spi.ModelToXMLDumper;
+import org.apache.camel.spi.ModelToYAMLDumper;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.annotations.ServiceFactory;
+import org.apache.camel.support.PluginHelper;
+import org.apache.camel.support.ResourceSupport;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.support.LoggerHelper.stripSourceLocationLineNumber;
+
+/**
+ * Default {@link DumpRoutesStrategy} that dumps the routes to standard logger.
+ */
+@ServiceFactory("default-" + DumpRoutesStrategy.FACTORY)
+public class DefaultDumpRoutesStrategy extends ServiceSupport implements DumpRoutesStrategy, CamelContextAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultDumpRoutesStrategy.class);
+    private static final String DIVIDER = "--------------------------------------------------------------------------------";
+
+    private final AtomicInteger counter = new AtomicInteger();
+    private CamelContext camelContext;
+
+    private String include = "routes";
+    private boolean resolvePlaceholders = true;
+    private boolean uriAsParameters;
+    private boolean log = true;
+    private String directory;
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    public String getInclude() {
+        return include;
+    }
+
+    public void setInclude(String include) {
+        this.include = include;
+    }
+
+    public boolean isResolvePlaceholders() {
+        return resolvePlaceholders;
+    }
+
+    public void setResolvePlaceholders(boolean resolvePlaceholders) {
+        this.resolvePlaceholders = resolvePlaceholders;
+    }
+
+    public boolean isLog() {
+        return log;
+    }
+
+    public void setLog(boolean log) {
+        this.log = log;
+    }
+
+    public String getDirectory() {
+        return directory;
+    }
+
+    public void setDirectory(String directory) {
+        this.directory = directory;
+    }
+
+    public boolean isUriAsParameters() {
+        return uriAsParameters;
+    }
+
+    public void setUriAsParameters(boolean uriAsParameters) {
+        this.uriAsParameters = uriAsParameters;
+    }
+
+    @Override
+    public void dumpRoutes(String format) {
+        if ("yaml".equalsIgnoreCase(format)) {
+            doDumpRoutesAsYaml(camelContext);
+        } else if ("xml".equalsIgnoreCase(format)) {
+            doDumpRoutesAsXml(camelContext);
+        }
+    }
+
+    protected void doDumpRoutesAsYaml(CamelContext camelContext) {
+        final ModelToYAMLDumper dumper = PluginHelper.getModelToYAMLDumper(camelContext);
+        final Model model = camelContext.getCamelContextExtension().getContextPlugin(Model.class);
+        final DummyResource dummy = new DummyResource(null, null);
+
+        if (include.contains("*") || include.contains("all") || include.contains("routes")) {
+            int size = model.getRouteDefinitions().size();
+            if (size > 0) {
+                Map<Resource, RoutesDefinition> groups = new LinkedHashMap<>();
+                for (RouteDefinition route : model.getRouteDefinitions()) {
+                    Resource res = route.getResource();
+                    if (res == null) {
+                        res = dummy;
+                    }
+                    RoutesDefinition routes = groups.computeIfAbsent(res, resource -> new RoutesDefinition());
+                    routes.getRoutes().add(route);
+                }
+                StringBuilder sbLog = new StringBuilder();
+                for (Map.Entry<Resource, RoutesDefinition> entry : groups.entrySet()) {
+                    RoutesDefinition def = entry.getValue();
+                    Resource resource = entry.getKey();
+
+                    StringBuilder sbLocal = new StringBuilder();
+                    doDumpYaml(camelContext, def, resource == dummy ? null : resource, dumper, "routes", sbLocal, sbLog);
+                    // dump each resource into its own file
+                    doDumpToDirectory(resource, sbLocal, "routes", "yaml");
+                }
+                if (!sbLog.isEmpty() && log) {
+                    LOG.info("Dumping {} routes as YAML", size);
+                    LOG.info("{}", sbLog);
+                }
+            }
+        }
+
+        if (include.contains("*") || include.contains("all") || include.contains("rests")) {
+            int size = model.getRestDefinitions().size();
+            if (size > 0) {
+                Map<Resource, RestsDefinition> groups = new LinkedHashMap<>();
+                for (RestDefinition rest : model.getRestDefinitions()) {
+                    Resource res = rest.getResource();
+                    if (res == null) {
+                        res = dummy;
+                    }
+                    RestsDefinition rests = groups.computeIfAbsent(res, resource -> new RestsDefinition());
+                    rests.getRests().add(rest);
+                }
+                StringBuilder sbLog = new StringBuilder();
+                for (Map.Entry<Resource, RestsDefinition> entry : groups.entrySet()) {
+                    RestsDefinition def = entry.getValue();
+                    Resource resource = entry.getKey();
+
+                    StringBuilder sbLocal = new StringBuilder();
+                    doDumpYaml(camelContext, def, resource == dummy ? null : resource, dumper, "rests", sbLocal, sbLog);
+                    // dump each resource into its own file
+                    doDumpToDirectory(resource, sbLocal, "rests", "yaml");
+                }
+                if (!sbLog.isEmpty() && log) {
+                    LOG.info("Dumping {} rests as YAML", size);
+                    LOG.info("{}", sbLog);
+                }
+            }
+        }
+
+        if (include.contains("*") || include.contains("all") || include.contains("routeTemplates")
+                || include.contains("route-templates")) {
+            int size = model.getRouteTemplateDefinitions().size();
+            if (size > 0) {
+                Map<Resource, RouteTemplatesDefinition> groups = new LinkedHashMap<>();
+                for (RouteTemplateDefinition rt : model.getRouteTemplateDefinitions()) {
+                    Resource res = rt.getResource();
+                    if (res == null) {
+                        res = dummy;
+                    }
+                    RouteTemplatesDefinition rests = groups.computeIfAbsent(res, resource -> new RouteTemplatesDefinition());
+                    rests.getRouteTemplates().add(rt);
+                }
+                StringBuilder sbLog = new StringBuilder();
+                for (Map.Entry<Resource, RouteTemplatesDefinition> entry : groups.entrySet()) {
+                    RouteTemplatesDefinition def = entry.getValue();
+                    Resource resource = entry.getKey();
+
+                    StringBuilder sbLocal = new StringBuilder();
+                    doDumpYaml(camelContext, def, resource == dummy ? null : resource, dumper, "route-templates", sbLocal,
+                            sbLog);
+                    // dump each resource into its own file
+                    doDumpToDirectory(resource, sbLocal, "route-templates", "yaml");
+                }
+                if (!sbLog.isEmpty() && log) {
+                    LOG.info("Dumping {} route-templates as YAML", size);
+                    LOG.info("{}", sbLog);
+                }
+            }
+        }
+    }
+
+    protected void doDumpYaml(
+            CamelContext camelContext, NamedNode def, Resource resource,
+            ModelToYAMLDumper dumper, String kind, StringBuilder sbLocal, StringBuilder sbLog) {
+        try {
+            String dump = dumper.dumpModelAsYaml(camelContext, def, resolvePlaceholders, uriAsParameters);
+            sbLocal.append(dump);
+            appendLogDump(resource, dump, sbLog);
+        } catch (Exception e) {
+            LOG.warn("Error dumping {}} to YAML due to {}. This exception is ignored.", kind, e.getMessage(), e);
+        }
+    }
+
+    protected void doDumpRoutesAsXml(CamelContext camelContext) {
+        final ModelToXMLDumper dumper = PluginHelper.getModelToXMLDumper(camelContext);
+        final Model model = camelContext.getCamelContextExtension().getContextPlugin(Model.class);
+        final DummyResource dummy = new DummyResource(null, null);
+
+        if (include.contains("*") || include.contains("all") || include.contains("routes")) {
+            int size = model.getRouteDefinitions().size();
+            if (size > 0) {
+                Map<Resource, RoutesDefinition> groups = new LinkedHashMap<>();
+                for (RouteDefinition route : model.getRouteDefinitions()) {
+                    Resource res = route.getResource();
+                    if (res == null) {
+                        res = dummy;
+                    }
+                    RoutesDefinition routes = groups.computeIfAbsent(res, resource -> new RoutesDefinition());
+                    routes.getRoutes().add(route);
+                }
+                StringBuilder sbLog = new StringBuilder();
+                for (Map.Entry<Resource, RoutesDefinition> entry : groups.entrySet()) {
+                    RoutesDefinition def = entry.getValue();
+                    Resource resource = entry.getKey();
+
+                    StringBuilder sbLocal = new StringBuilder();
+                    doDumpXml(camelContext, def, resource == dummy ? null : resource, dumper, "route", "routes", sbLocal,
+                            sbLog);
+                    // dump each resource into its own file
+                    doDumpToDirectory(resource, sbLocal, "routes", "xml");
+                }
+                if (!sbLog.isEmpty() && log) {
+                    LOG.info("Dumping {} routes as XML", size);
+                    LOG.info("{}", sbLog);
+                }
+            }
+        }
+
+        if (include.contains("*") || include.contains("all") || include.contains("rests")) {
+            int size = model.getRestDefinitions().size();
+            if (size > 0) {
+                Map<Resource, RestsDefinition> groups = new LinkedHashMap<>();
+                for (RestDefinition rest : model.getRestDefinitions()) {
+                    Resource res = rest.getResource();
+                    if (res == null) {
+                        res = dummy;
+                    }
+                    RestsDefinition routes = groups.computeIfAbsent(res, resource -> new RestsDefinition());
+                    routes.getRests().add(rest);
+                }
+                StringBuilder sbLog = new StringBuilder();
+                for (Map.Entry<Resource, RestsDefinition> entry : groups.entrySet()) {
+                    RestsDefinition def = entry.getValue();
+                    Resource resource = entry.getKey();
+
+                    StringBuilder sbLocal = new StringBuilder();
+                    doDumpXml(camelContext, def, resource == dummy ? null : resource, dumper, "rest", "rests", sbLocal, sbLog);
+                    // dump each resource into its own file
+                    doDumpToDirectory(resource, sbLocal, "rests", "xml");
+                }
+                if (!sbLog.isEmpty() && log) {
+                    LOG.info("Dumping {} rests as XML", size);
+                    LOG.info("{}", sbLog);
+                }
+            }
+        }
+
+        if (include.contains("*") || include.contains("all") || include.contains("routeTemplates")
+                || include.contains("route-templates")) {
+            int size = model.getRouteTemplateDefinitions().size();
+            if (size > 0) {
+                Map<Resource, RouteTemplatesDefinition> groups = new LinkedHashMap<>();
+                for (RouteTemplateDefinition rt : model.getRouteTemplateDefinitions()) {
+                    Resource res = rt.getResource();
+                    if (res == null) {
+                        res = dummy;
+                    }
+                    RouteTemplatesDefinition routes = groups.computeIfAbsent(res, resource -> new RouteTemplatesDefinition());
+                    routes.getRouteTemplates().add(rt);
+                }
+                StringBuilder sbLog = new StringBuilder();
+                for (Map.Entry<Resource, RouteTemplatesDefinition> entry : groups.entrySet()) {
+                    RouteTemplatesDefinition def = entry.getValue();
+                    Resource resource = entry.getKey();
+
+                    StringBuilder sbLocal = new StringBuilder();
+                    doDumpXml(camelContext, def, resource == dummy ? null : resource, dumper, "routeTemplate",
+                            "route-templates", sbLocal, sbLog);
+                    // dump each resource into its own file
+                    doDumpToDirectory(resource, sbLocal, "route-templates", "xml");
+                }
+                if (!sbLog.isEmpty() && log) {
+                    LOG.info("Dumping {} route-templates as XML", size);
+                    LOG.info("{}", sbLog);
+                }
+            }
+        }
+    }
+
+    protected void doDumpXml(
+            CamelContext camelContext, NamedNode def, Resource resource,
+            ModelToXMLDumper dumper, String replace, String kind, StringBuilder sbLocal, StringBuilder sbLog) {
+        try {
+            String xml = dumper.dumpModelAsXml(camelContext, def, resolvePlaceholders);
+            // lets separate with empty line
+            xml = StringHelper.replaceFirst(xml, "xmlns=\"http://camel.apache.org/schema/spring\">",
+                    "xmlns=\"http://camel.apache.org/schema/spring\">\n");
+            xml = xml.replace("</" + replace + ">", "</" + replace + ">\n");
+            sbLocal.append(xml);
+            appendLogDump(resource, xml, sbLog);
+        } catch (Exception e) {
+            LOG.warn("Error dumping {}} to XML due to {}. This exception is ignored.", kind, e.getMessage(), e);
+        }
+    }
+
+    protected void doDumpToDirectory(Resource resource, StringBuilder sbLocal, String kind, String ext) {
+        if (directory != null && !sbLocal.isEmpty()) {
+            // make sure directory exists
+            File dir = new File(directory);
+            dir.mkdirs();
+
+            String name = resource != null ? resource.getLocation() : null;
+            if (name == null) {
+                name = "dump" + counter.incrementAndGet();
+            }
+            // strip scheme
+            if (name.contains(":")) {
+                name = StringHelper.after(name, ":");
+            }
+            name = FileUtil.onlyName(name) + "." + ext;
+            File target = new File(directory, name);
+            try {
+                IOHelper.writeText(sbLocal.toString(), target);
+                LOG.info("Dumped {} to file: {}", kind, target);
+            } catch (IOException e) {
+                throw new RuntimeException("Error dumping " + kind + " to file: " + target, e);
+            }
+        }
+    }
+
+    protected void appendLogDump(Resource resource, String dump, StringBuilder sbLog) {
+        String loc = null;
+        if (resource != null) {
+            loc = extractLocationName(resource.getLocation());
+        }
+        if (loc != null) {
+            sbLog.append(String.format("\nSource: %s%n%s%n%s%n", loc, DIVIDER, dump));
+        } else {
+            sbLog.append(String.format("%n%n%s%n", dump));
+        }
+    }
+
+    private static final class DummyResource extends ResourceSupport {
+
+        private DummyResource(String scheme, String location) {
+            super(scheme, location);
+        }
+
+        @Override
+        public boolean exists() {
+            return true;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return null; // not in use
+        }
+    }
+
+    private static String extractLocationName(String loc) {
+        if (loc == null) {
+            return null;
+        }
+        loc = stripSourceLocationLineNumber(loc);
+        if (loc != null) {
+            if (loc.contains(":")) {
+                // strip prefix
+                loc = loc.substring(loc.indexOf(':') + 1);
+                // file based such as xml and yaml
+                loc = FileUtil.stripPath(loc);
+            }
+        }
+        return loc;
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
index aef44851022..3c99c0c385a 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
@@ -273,7 +273,6 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
         if (restConfiguration == null) {
             restConfiguration = new RestConfigurationDefinition();
         }
-
         return restConfiguration;
     }
 
@@ -308,6 +307,9 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
      */
     public RestDefinition rest() {
         getRestCollection().setCamelContext(getContext());
+        if (resource != null) {
+            getRestCollection().setResource(resource);
+        }
         RestDefinition answer = getRestCollection().rest();
         configureRest(answer);
         return answer;
@@ -321,6 +323,9 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
      */
     public RestDefinition rest(String path) {
         getRestCollection().setCamelContext(getContext());
+        if (resource != null) {
+            getRestCollection().setResource(resource);
+        }
         RestDefinition answer = getRestCollection().rest(path);
         configureRest(answer);
         return answer;
@@ -724,6 +729,8 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
 
             // remember the source resource
             getRouteCollection().setResource(getResource());
+            getRestCollection().setResource(getResource());
+            getRouteTemplateCollection().setResource(getResource());
 
             for (RouteDefinition route : getRouteCollection().getRoutes()) {
                 // ensure the route is prepared after configure method is complete
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java
index cbc6f1a6e9e..eef35ec6d1c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java
@@ -68,7 +68,7 @@ public abstract class OptionalIdentifiedDefinition<T extends OptionalIdentifiedD
     @Metadata(description = "The id of this node")
     public void setId(String id) {
         this.id = id;
-        customId = true;
+        customId = id != null ? true : null;
     }
 
     @Override
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
index 4200fbd4e01..d803efc03ad 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinitionHelper.java
@@ -189,8 +189,7 @@ public final class RouteDefinitionHelper {
                 if (!done) {
                     throw new IllegalArgumentException("Cannot auto assign id to route: " + route);
                 }
-                route.setId(id);
-                route.setCustomId(false);
+                route.setGeneratedId(id);
                 customIds.add(route.getId());
             }
             RestDefinition rest = route.getRestDefinition();
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
index 0addb6dc7f4..320b3a11267 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateDefinition.java
@@ -34,6 +34,8 @@ import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.builder.EndpointConsumerBuilder;
 import org.apache.camel.spi.AsEndpointUri;
 import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 
 /**
  * Defines a route template (parameterized routes)
@@ -42,7 +44,7 @@ import org.apache.camel.spi.Metadata;
 @XmlRootElement(name = "routeTemplate")
 @XmlType(propOrder = { "templateParameters", "templateBeans", "route" })
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RouteTemplateDefinition extends OptionalIdentifiedDefinition<RouteTemplateDefinition> {
+public class RouteTemplateDefinition extends OptionalIdentifiedDefinition<RouteTemplateDefinition> implements ResourceAware {
 
     @XmlTransient
     private Consumer<RouteTemplateContext> configurer;
@@ -55,6 +57,8 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition<RouteT
     private List<RouteTemplateBeanDefinition> templateBeans;
     @XmlElement(name = "route", required = true)
     private RouteDefinition route = new RouteDefinition();
+    @XmlTransient
+    private Resource resource;
 
     public List<RouteTemplateParameterDefinition> getTemplateParameters() {
         return templateParameters;
@@ -88,6 +92,14 @@ public class RouteTemplateDefinition extends OptionalIdentifiedDefinition<RouteT
         return configurer;
     }
 
+    public Resource getResource() {
+        return resource;
+    }
+
+    public void setResource(Resource resource) {
+        this.resource = resource;
+    }
+
     // Fluent API
     // -------------------------------------------------------------------------
 
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
index 2ef67a3d694..a50d583b3eb 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
@@ -29,6 +29,8 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.ErrorHandlerFactory;
 import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 
 /**
  * A series of route templates
@@ -37,12 +39,14 @@ import org.apache.camel.spi.Metadata;
 @XmlRootElement(name = "routeTemplates")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class RouteTemplatesDefinition extends OptionalIdentifiedDefinition<RouteTemplatesDefinition>
-        implements RouteTemplateContainer, CamelContextAware {
+        implements RouteTemplateContainer, CamelContextAware, ResourceAware {
 
     @XmlTransient
     private CamelContext camelContext;
     @XmlTransient
     private ErrorHandlerFactory errorHandlerFactory;
+    @XmlTransient
+    private Resource resource;
 
     @XmlElementRef
     private List<RouteTemplateDefinition> routeTemplates = new ArrayList<>();
@@ -98,6 +102,14 @@ public class RouteTemplatesDefinition extends OptionalIdentifiedDefinition<Route
         this.errorHandlerFactory = errorHandlerFactory;
     }
 
+    public Resource getResource() {
+        return resource;
+    }
+
+    public void setResource(Resource resource) {
+        this.resource = resource;
+    }
+
     // Fluent API
     // -------------------------------------------------------------------------
 
@@ -129,7 +141,9 @@ public class RouteTemplatesDefinition extends OptionalIdentifiedDefinition<Route
         if (handler != null) {
             template.getRoute().setErrorHandlerFactoryIfNull(handler);
         }
-
+        if (resource != null) {
+            template.setResource(resource);
+        }
         return template;
     }
 
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java
index ae020ff6614..50f62993466 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java
@@ -31,6 +31,7 @@ import jakarta.xml.bind.annotation.XmlAttribute;
 import jakarta.xml.bind.annotation.XmlElement;
 import jakarta.xml.bind.annotation.XmlElementRef;
 import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.RuntimeCamelException;
@@ -39,6 +40,8 @@ import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.ToDefinition;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.NodeIdFactory;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.util.FileUtil;
@@ -52,7 +55,7 @@ import org.apache.camel.util.URISupport;
 @Metadata(label = "rest")
 @XmlRootElement(name = "rest")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> {
+public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> implements ResourceAware {
 
     @XmlAttribute
     private String path;
@@ -89,6 +92,8 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
     private List<SecurityDefinition> securityRequirements = new ArrayList<>();
     @XmlElementRef
     private List<VerbDefinition> verbs = new ArrayList<>();
+    @XmlTransient
+    private Resource resource;
 
     @Override
     public String getShortName() {
@@ -261,6 +266,14 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
         this.apiDocs = apiDocs;
     }
 
+    public Resource getResource() {
+        return resource;
+    }
+
+    public void setResource(Resource resource) {
+        this.resource = resource;
+    }
+
     // Fluent API
     // -------------------------------------------------------------------------
 
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
index 3e4a4a39523..96fd21ca7d1 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
@@ -23,9 +23,12 @@ import jakarta.xml.bind.annotation.XmlAccessType;
 import jakarta.xml.bind.annotation.XmlAccessorType;
 import jakarta.xml.bind.annotation.XmlElementRef;
 import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.model.OptionalIdentifiedDefinition;
 import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceAware;
 
 /**
  * A series of rest services defined using the rest-dsl
@@ -33,10 +36,12 @@ import org.apache.camel.spi.Metadata;
 @Metadata(label = "rest")
 @XmlRootElement(name = "rests")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer {
+public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer, ResourceAware {
 
     @XmlElementRef
     private List<RestDefinition> rests = new ArrayList<>();
+    @XmlTransient
+    private Resource resource;
 
     public RestsDefinition() {
     }
@@ -72,6 +77,14 @@ public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinitio
         this.rests = rests;
     }
 
+    public Resource getResource() {
+        return resource;
+    }
+
+    public void setResource(Resource resource) {
+        this.resource = resource;
+    }
+
     // Fluent API
     // -------------------------------------------------------------------------
 
@@ -106,7 +119,11 @@ public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinitio
     // -------------------------------------------------------------------------
 
     protected RestDefinition createRest() {
-        return new RestDefinition();
+        RestDefinition rest = new RestDefinition();
+        if (resource != null) {
+            rest.setResource(resource);
+        }
+        return rest;
     }
 
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/FluentProducerTemplateTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/FluentProducerTemplateTest.java
index 692ee12ee40..7ef05345095 100644
--- a/core/camel-core/src/test/java/org/apache/camel/builder/FluentProducerTemplateTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/FluentProducerTemplateTest.java
@@ -236,9 +236,7 @@ public class FluentProducerTemplateTest extends ContextTestSupport {
     public void testExceptionUsingProcessorAndBody() {
         assertThrows(IllegalArgumentException.class, () -> DefaultFluentProducerTemplate.on(context)
                 .withBody("World")
-                .withProcessor(exchange -> exchange.getIn().setHeader("foo", 123)).
-                to("direct:async").
-                send(), "");
+                .withProcessor(exchange -> exchange.getIn().setHeader("foo", 123)).to("direct:async").send(), "");
     }
 
     @Test
diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/NotifyBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/NotifyBuilderTest.java
index c1ff1606d00..07e71dd95fc 100644
--- a/core/camel-core/src/test/java/org/apache/camel/builder/NotifyBuilderTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/NotifyBuilderTest.java
@@ -978,7 +978,8 @@ public class NotifyBuilderTest extends ContextTestSupport {
         template.sendBody("direct:foo", "Hello World");
         assertFalse(notify.matches());
 
-        assertThrows(CamelExecutionException.class, () -> template.sendBody("direct:fail", "Bye World"), "Should have thrown exception");
+        assertThrows(CamelExecutionException.class, () -> template.sendBody("direct:fail", "Bye World"),
+                "Should have thrown exception");
         assertTrue(notify.matches());
     }
 
diff --git a/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java b/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java
index 577c7b96646..2edb143851b 100644
--- a/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriFactoryTest.java
@@ -92,7 +92,8 @@ public class CustomEndpointUriFactoryTest extends ContextTestSupport {
         IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
                 () -> assembler.buildUri("acme", params),
                 "Should have thrown an exception");
-        Assertions.assertEquals("Option name is required when creating endpoint uri with syntax acme:name:port", e.getMessage());
+        Assertions.assertEquals("Option name is required when creating endpoint uri with syntax acme:name:port",
+                e.getMessage());
     }
 
     @Test
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoAMoreComplexOverloadedTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoAMoreComplexOverloadedTest.java
index 4aebec30b77..b82e65bfda1 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoAMoreComplexOverloadedTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoAMoreComplexOverloadedTest.java
@@ -73,7 +73,6 @@ public class BeanInfoAMoreComplexOverloadedTest extends ContextTestSupport {
         Exchange exchange = new DefaultExchange(context);
         exchange.setIn(message);
 
-
         AmbiguousMethodCallException e = assertThrows(AmbiguousMethodCallException.class,
                 () -> beanInfo.createInvocation(new Bean(), exchange),
                 "Should have thrown an exception");
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoWithBridgedMethodTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoWithBridgedMethodTest.java
index 2eb151b0473..9f630da42dc 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoWithBridgedMethodTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoWithBridgedMethodTest.java
@@ -50,10 +50,11 @@ public class BeanInfoWithBridgedMethodTest extends ContextTestSupport {
         DefaultExchange exchange = new DefaultExchange(context);
         exchange.getIn().setBody(new Request(1));
 
-        assertDoesNotThrow(() -> {MyPackagePrivateService myService = new MyPackagePrivateService();
-        MethodInvocation mi = beanInfo.createInvocation(null, exchange);
-        assertEquals("Service", mi.getMethod().getDeclaringClass().getSimpleName());
-        assertEquals(4, mi.getMethod().invoke(myService, new Request(2)));
+        assertDoesNotThrow(() -> {
+            MyPackagePrivateService myService = new MyPackagePrivateService();
+            MethodInvocation mi = beanInfo.createInvocation(null, exchange);
+            assertEquals("Service", mi.getMethod().getDeclaringClass().getSimpleName());
+            assertEquals(4, mi.getMethod().invoke(myService, new Request(2)));
         }, "This should not be ambiguous!");
     }
 
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java
index ac4e774e40c..d39956a72f5 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanProxyNoBindingTest.java
@@ -111,7 +111,7 @@ public class BeanProxyNoBindingTest extends ContextTestSupport {
         Endpoint endpoint = context.getEndpoint("direct:start");
         OrderService service = ProxyHelper.createProxy(endpoint, false, OrderService.class);
 
-/*        try {
+        /*        try {
             service.invalidReturnType("<order type=\"beer\">Carlsberg</order>");
             fail("Should have thrown exception");
         } catch (Exception e) {
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanRefMethodNotFoundTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanRefMethodNotFoundTest.java
index 7595a00a362..1525c738ca2 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanRefMethodNotFoundTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanRefMethodNotFoundTest.java
@@ -46,7 +46,7 @@ public class BeanRefMethodNotFoundTest extends ContextTestSupport {
         });
 
         Exception e = assertThrows(Exception.class,
-                () ->  context.start(),
+                () -> context.start(),
                 "Should have thrown exception");
 
         FailedToCreateRouteException failed = assertIsInstanceOf(FailedToCreateRouteException.class, e);
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/async/MyAsyncComponent.java b/core/camel-core/src/test/java/org/apache/camel/processor/async/MyAsyncComponent.java
index 2c2dadc3e83..f18f826f088 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/async/MyAsyncComponent.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/async/MyAsyncComponent.java
@@ -16,7 +16,6 @@
  */
 package org.apache.camel.processor.async;
 
-import java.util.Locale;
 import java.util.Map;
 
 import org.apache.camel.Endpoint;
diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
index a135eac6123..288a99df147 100644
--- a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
+++ b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
@@ -73,6 +73,16 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp
         case "DevConsoleEnabled": target.setDevConsoleEnabled(property(camelContext, boolean.class, value)); return true;
         case "dumproutes":
         case "DumpRoutes": target.setDumpRoutes(property(camelContext, java.lang.String.class, value)); return true;
+        case "dumproutesdirectory":
+        case "DumpRoutesDirectory": target.setDumpRoutesDirectory(property(camelContext, java.lang.String.class, value)); return true;
+        case "dumproutesinclude":
+        case "DumpRoutesInclude": target.setDumpRoutesInclude(property(camelContext, java.lang.String.class, value)); return true;
+        case "dumprouteslog":
+        case "DumpRoutesLog": target.setDumpRoutesLog(property(camelContext, boolean.class, value)); return true;
+        case "dumproutesresolveplaceholders":
+        case "DumpRoutesResolvePlaceholders": target.setDumpRoutesResolvePlaceholders(property(camelContext, boolean.class, value)); return true;
+        case "dumproutesuriasparameters":
+        case "DumpRoutesUriAsParameters": target.setDumpRoutesUriAsParameters(property(camelContext, boolean.class, value)); return true;
         case "durationhitexitcode":
         case "DurationHitExitCode": target.setDurationHitExitCode(property(camelContext, int.class, value)); return true;
         case "durationmaxaction":
@@ -320,6 +330,16 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp
         case "DevConsoleEnabled": return boolean.class;
         case "dumproutes":
         case "DumpRoutes": return java.lang.String.class;
+        case "dumproutesdirectory":
+        case "DumpRoutesDirectory": return java.lang.String.class;
+        case "dumproutesinclude":
+        case "DumpRoutesInclude": return java.lang.String.class;
+        case "dumprouteslog":
+        case "DumpRoutesLog": return boolean.class;
+        case "dumproutesresolveplaceholders":
+        case "DumpRoutesResolvePlaceholders": return boolean.class;
+        case "dumproutesuriasparameters":
+        case "DumpRoutesUriAsParameters": return boolean.class;
         case "durationhitexitcode":
         case "DurationHitExitCode": return int.class;
         case "durationmaxaction":
@@ -568,6 +588,16 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp
         case "DevConsoleEnabled": return target.isDevConsoleEnabled();
         case "dumproutes":
         case "DumpRoutes": return target.getDumpRoutes();
+        case "dumproutesdirectory":
+        case "DumpRoutesDirectory": return target.getDumpRoutesDirectory();
+        case "dumproutesinclude":
+        case "DumpRoutesInclude": return target.getDumpRoutesInclude();
+        case "dumprouteslog":
+        case "DumpRoutesLog": return target.isDumpRoutesLog();
+        case "dumproutesresolveplaceholders":
+        case "DumpRoutesResolvePlaceholders": return target.isDumpRoutesResolvePlaceholders();
+        case "dumproutesuriasparameters":
+        case "DumpRoutesUriAsParameters": return target.isDumpRoutesUriAsParameters();
         case "durationhitexitcode":
         case "DurationHitExitCode": return target.getDurationHitExitCode();
         case "durationmaxaction":
diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 7e4a2e04b05..e49a846be05 100644
--- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -39,6 +39,11 @@
     { "name": "camel.main.description", "description": "Sets the description (intended for humans) of the Camel application.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
     { "name": "camel.main.devConsoleEnabled", "description": "Whether to enable developer console (requires camel-console on classpath). The developer console is only for assisting during development. This is NOT for production usage.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.dumpRoutes", "description": "If dumping is enabled then Camel will during startup dump all loaded routes (incl rests and route templates) represented as XML\/YAML DSL into the log. This is intended for trouble shooting or to assist during development. Sensitive information that may be configured in the route endpoints could potentially be included in the dump output and is therefore not recommended being used for production usage. This requires to have camel-xml [...]
+    { "name": "camel.main.dumpRoutesDirectory", "description": "Whether to save route dumps to files in the given directory. The name of the files are based on original loaded resource, or an autogenerated name.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
+    { "name": "camel.main.dumpRoutesInclude", "description": "Controls what to include in output for route dumping. Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "routes" },
+    { "name": "camel.main.dumpRoutesLog", "description": "Whether to log route dumps to Logger", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true },
+    { "name": "camel.main.dumpRoutesResolvePlaceholders", "description": "Whether to resolve property placeholders in the dumped output. Default is true.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true },
+    { "name": "camel.main.dumpRoutesUriAsParameters", "description": "When dumping routes to YAML format, then this option controls whether endpoint URIs should be expanded into a key\/value parameters.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.main.durationHitExitCode", "description": "Sets the exit code for the application if duration was hit", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "integer", "javaType": "int" },
     { "name": "camel.main.durationMaxAction", "description": "Controls whether the Camel application should shutdown the JVM, or stop all routes, when duration max is triggered.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "shutdown", "enum": [ "shutdown", "stop" ] },
     { "name": "camel.main.durationMaxIdleSeconds", "description": "To specify for how long time in seconds Camel can be idle before automatic terminating the JVM. You can use this to run Camel for a short while.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int" },
diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc
index fff84225c33..1764d645f0d 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -19,7 +19,7 @@ The following tables lists all the options:
 
 // main options: START
 === Camel Main configurations
-The camel.main supports 120 options, which are listed below.
+The camel.main supports 125 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -50,6 +50,11 @@ The camel.main supports 120 options, which are listed below.
 | *camel.main.description* | Sets the description (intended for humans) of the Camel application. |  | String
 | *camel.main.devConsoleEnabled* | Whether to enable developer console (requires camel-console on classpath). The developer console is only for assisting during development. This is NOT for production usage. | false | boolean
 | *camel.main.dumpRoutes* | If dumping is enabled then Camel will during startup dump all loaded routes (incl rests and route templates) represented as XML/YAML DSL into the log. This is intended for trouble shooting or to assist during development. Sensitive information that may be configured in the route endpoints could potentially be included in the dump output and is therefore not recommended being used for production usage. This requires to have camel-xml-io/camel-yaml-io on the cla [...]
+| *camel.main.dumpRoutesDirectory* | Whether to save route dumps to files in the given directory. The name of the files are based on original loaded resource, or an autogenerated name. |  | String
+| *camel.main.dumpRoutesInclude* | Controls what to include in output for route dumping. Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes. | routes | String
+| *camel.main.dumpRoutesLog* | Whether to log route dumps to Logger | true | boolean
+| *camel.main.dumpRoutesResolve{zwsp}Placeholders* | Whether to resolve property placeholders in the dumped output. Default is true. | true | boolean
+| *camel.main.dumpRoutesUriAs{zwsp}Parameters* | When dumping routes to YAML format, then this option controls whether endpoint URIs should be expanded into a key/value parameters. | false | boolean
 | *camel.main.durationHitExitCode* | Sets the exit code for the application if duration was hit |  | int
 | *camel.main.durationMaxAction* | Controls whether the Camel application should shutdown the JVM, or stop all routes, when duration max is triggered. | shutdown | String
 | *camel.main.durationMaxIdle{zwsp}Seconds* | To specify for how long time in seconds Camel can be idle before automatic terminating the JVM. You can use this to run Camel for a short while. |  | int
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
index 28e9254e496..f55b933bc1a 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
@@ -48,6 +48,7 @@ import org.apache.camel.spi.ClassResolver;
 import org.apache.camel.spi.CliConnectorFactory;
 import org.apache.camel.spi.ContextReloadStrategy;
 import org.apache.camel.spi.Debugger;
+import org.apache.camel.spi.DumpRoutesStrategy;
 import org.apache.camel.spi.EndpointStrategy;
 import org.apache.camel.spi.EventFactory;
 import org.apache.camel.spi.EventNotifier;
@@ -258,6 +259,14 @@ public final class DefaultConfigurationConfigurer {
             reloader.setRemoveAllRoutes(config.isRoutesReloadRemoveAllRoutes());
             camelContext.addService(reloader);
         }
+        if (config.getDumpRoutes() != null) {
+            DumpRoutesStrategy drs = camelContext.getCamelContextExtension().getContextPlugin(DumpRoutesStrategy.class);
+            drs.setInclude(config.getDumpRoutesInclude());
+            drs.setLog(config.isDumpRoutesLog());
+            drs.setUriAsParameters(config.isDumpRoutesUriAsParameters());
+            drs.setResolvePlaceholders(config.isDumpRoutesResolvePlaceholders());
+            drs.setDirectory(config.getDumpRoutesDirectory());
+        }
         if (config.isContextReloadEnabled() && camelContext.hasService(ContextReloadStrategy.class) == null) {
             ContextReloadStrategy reloader = new DefaultContextReloadStrategy();
             camelContext.addService(reloader);
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
index ee44283e346..c6272f5056d 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
@@ -131,6 +131,11 @@ public abstract class DefaultConfigurationProperties<T> {
     private boolean exchangeFactoryStatisticsEnabled;
     @Metadata(enums = "xml,yaml")
     private String dumpRoutes;
+    private String dumpRoutesInclude = "routes";
+    private boolean dumpRoutesLog = true;
+    private boolean dumpRoutesResolvePlaceholders = true;
+    private boolean dumpRoutesUriAsParameters;
+    private String dumpRoutesDirectory;
     private Map<String, String> globalOptions;
     // route controller
     private boolean routeControllerSuperviseEnabled;
@@ -1386,6 +1391,65 @@ public abstract class DefaultConfigurationProperties<T> {
         this.dumpRoutes = dumpRoutes;
     }
 
+    public String getDumpRoutesInclude() {
+        return dumpRoutesInclude;
+    }
+
+    /**
+     * Controls what to include in output for route dumping.
+     *
+     * Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes.
+     */
+    public void setDumpRoutesInclude(String dumpRoutesInclude) {
+        this.dumpRoutesInclude = dumpRoutesInclude;
+    }
+
+    public boolean isDumpRoutesLog() {
+        return dumpRoutesLog;
+    }
+
+    /**
+     * Whether to log route dumps to Logger
+     */
+    public void setDumpRoutesLog(boolean dumpRoutesLog) {
+        this.dumpRoutesLog = dumpRoutesLog;
+    }
+
+    public boolean isDumpRoutesResolvePlaceholders() {
+        return dumpRoutesResolvePlaceholders;
+    }
+
+    /**
+     * Whether to resolve property placeholders in the dumped output. Default is true.
+     */
+    public void setDumpRoutesResolvePlaceholders(boolean dumpRoutesResolvePlaceholders) {
+        this.dumpRoutesResolvePlaceholders = dumpRoutesResolvePlaceholders;
+    }
+
+    public boolean isDumpRoutesUriAsParameters() {
+        return dumpRoutesUriAsParameters;
+    }
+
+    /**
+     * When dumping routes to YAML format, then this option controls whether endpoint URIs should be expanded into a
+     * key/value parameters.
+     */
+    public void setDumpRoutesUriAsParameters(boolean dumpRoutesUriAsParameters) {
+        this.dumpRoutesUriAsParameters = dumpRoutesUriAsParameters;
+    }
+
+    public String getDumpRoutesDirectory() {
+        return dumpRoutesDirectory;
+    }
+
+    /**
+     * Whether to save route dumps to files in the given directory. The name of the files are based on original loaded
+     * resource, or an autogenerated name.
+     */
+    public void setDumpRoutesDirectory(String dumpRoutesDirectory) {
+        this.dumpRoutesDirectory = dumpRoutesDirectory;
+    }
+
     public Map<String, String> getGlobalOptions() {
         return globalOptions;
     }
@@ -2578,6 +2642,50 @@ public abstract class DefaultConfigurationProperties<T> {
         return (T) this;
     }
 
+    /**
+     * Controls what to include in output for route dumping.
+     *
+     * Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes.
+     */
+    public T withDumpRoutesInclude(String dumpRoutesInclude) {
+        this.dumpRoutesInclude = dumpRoutesInclude;
+        return (T) this;
+    }
+
+    /**
+     * Whether to log route dumps to Logger
+     */
+    public T withDumpRoutesLog(boolean dumpRoutesLog) {
+        this.dumpRoutesLog = dumpRoutesLog;
+        return (T) this;
+    }
+
+    /**
+     * Whether to resolve property placeholders in the dumped output. Default is true.
+     */
+    public T withDumpRoutesResolvePlaceholders(boolean dumpRoutesResolvePlaceholders) {
+        this.dumpRoutesResolvePlaceholders = dumpRoutesResolvePlaceholders;
+        return (T) this;
+    }
+
+    /**
+     * When dumping routes to YAML format, then this option controls whether endpoint URIs should be expanded into a
+     * key/value parameters.
+     */
+    public T withDumpRoutesUriAsParameters(boolean dumpRoutesUriAsParameters) {
+        this.dumpRoutesUriAsParameters = dumpRoutesUriAsParameters;
+        return (T) this;
+    }
+
+    /**
+     * Whether to save route dumps to files in the given directory. The name of the files are based on original loaded
+     * resource, or an autogenerated name.
+     */
+    public T withDumpRoutesDirectory(String dumpRoutesDirectory) {
+        this.dumpRoutesDirectory = dumpRoutesDirectory;
+        return (T) this;
+    }
+
     /**
      * Sets global options that can be referenced in the camel context
      * <p/>
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedDumpRoutesStrategyMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedDumpRoutesStrategyMBean.java
new file mode 100644
index 00000000000..94e9aafd6c3
--- /dev/null
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedDumpRoutesStrategyMBean.java
@@ -0,0 +1,63 @@
+/*
+ * 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.api.management.mbean;
+
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedOperation;
+
+public interface ManagedDumpRoutesStrategyMBean {
+
+    @ManagedOperation(description = "Dump routes in YAML or XML format.")
+    void dumpRoutes(String format);
+
+    @ManagedAttribute(description = "Camel ID")
+    String getCamelId();
+
+    @ManagedAttribute(description = "Camel ManagementName")
+    String getCamelManagementName();
+
+    @ManagedAttribute(description = "Controls what to include in output. Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes.")
+    String getInclude();
+
+    @ManagedAttribute(description = "Controls what to include in output. Possible values: routes, rests, routeTemplates. Multiple values can be separated by comma. Default is routes.")
+    void setInclude(String include);
+
+    @ManagedAttribute(description = "Whether to log route dumps to Logger")
+    boolean isLog();
+
+    @ManagedAttribute(description = "Whether to log route dumps to Logger")
+    void setLog(boolean log);
+
+    @ManagedAttribute(description = "Whether to save route dumps to files in the given directory. The name of the files are based on ids (route ids, etc.). Existing files will be overwritten.")
+    String getDirectory();
+
+    @ManagedAttribute(description = "Whether to save route dumps to files in the given directory. The name of the files are based on ids (route ids, etc.). Existing files will be overwritten.")
+    void setDirectory(String directory);
+
+    @ManagedAttribute(description = "When dumping to YAML format, then this option controls whether endpoint URIs should be expanded into a key/value parameters")
+    boolean isUriAsParameters();
+
+    @ManagedAttribute(description = "When dumping to YAML format, then this option controls whether endpoint URIs should be expanded into a key/value parameters")
+    void setUriAsParameters(boolean uriAsParameters);
+
+    @ManagedAttribute(description = "")
+    boolean isResolvePlaceholders();
+
+    @ManagedAttribute(description = "Whether to resolve property placeholders in the dumped output. Default is true.")
+    void setResolvePlaceholders(boolean resolvePlaceholders);
+
+}
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectNameStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectNameStrategy.java
index 123929ca105..5d6aae5d2bc 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectNameStrategy.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectNameStrategy.java
@@ -41,6 +41,7 @@ import org.apache.camel.management.mbean.ManagedClusterService;
 import org.apache.camel.management.mbean.ManagedComponent;
 import org.apache.camel.management.mbean.ManagedConsumer;
 import org.apache.camel.management.mbean.ManagedDataFormat;
+import org.apache.camel.management.mbean.ManagedDumpRouteStrategy;
 import org.apache.camel.management.mbean.ManagedEndpoint;
 import org.apache.camel.management.mbean.ManagedEventNotifier;
 import org.apache.camel.management.mbean.ManagedProcessor;
@@ -162,6 +163,9 @@ public class DefaultManagementObjectNameStrategy implements ManagementObjectName
         } else if (managedObject instanceof ManagedBacklogDebugger) {
             ManagedBacklogDebugger md = (ManagedBacklogDebugger) managedObject;
             objectName = getObjectNameForTracer(md.getContext(), md.getBacklogDebugger());
+        } else if (managedObject instanceof ManagedDumpRouteStrategy) {
+            ManagedDumpRouteStrategy md = (ManagedDumpRouteStrategy) managedObject;
+            objectName = getObjectNameForService(md.getContext(), md.getDumpRoutesStrategy());
         } else if (managedObject instanceof ManagedEventNotifier) {
             ManagedEventNotifier men = (ManagedEventNotifier) managedObject;
             objectName = getObjectNameForEventNotifier(men.getContext(), men.getEventNotifier());
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
index e8e01ef30a3..fd8e138db50 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
@@ -57,6 +57,7 @@ import org.apache.camel.management.mbean.ManagedBacklogTracer;
 import org.apache.camel.management.mbean.ManagedBeanIntrospection;
 import org.apache.camel.management.mbean.ManagedCamelContext;
 import org.apache.camel.management.mbean.ManagedConsumerCache;
+import org.apache.camel.management.mbean.ManagedDumpRouteStrategy;
 import org.apache.camel.management.mbean.ManagedEndpoint;
 import org.apache.camel.management.mbean.ManagedEndpointRegistry;
 import org.apache.camel.management.mbean.ManagedExchangeFactoryManager;
@@ -84,6 +85,7 @@ import org.apache.camel.spi.AsyncProcessorAwaitManager;
 import org.apache.camel.spi.BeanIntrospection;
 import org.apache.camel.spi.ConsumerCache;
 import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DumpRoutesStrategy;
 import org.apache.camel.spi.EndpointRegistry;
 import org.apache.camel.spi.EventNotifier;
 import org.apache.camel.spi.ExchangeFactoryManager;
@@ -518,6 +520,10 @@ public class JmxManagementLifecycleStrategy extends ServiceSupport implements Li
             ManagedTracer mt = new ManagedTracer(camelContext, (Tracer) service);
             mt.init(getManagementStrategy());
             answer = mt;
+        } else if (service instanceof DumpRoutesStrategy) {
+            ManagedDumpRouteStrategy mdrs = new ManagedDumpRouteStrategy(camelContext, (DumpRoutesStrategy) service);
+            mdrs.init(getManagementStrategy());
+            answer = mdrs;
         } else if (service instanceof DataFormat) {
             answer = getManagementObjectStrategy().getManagedObjectForDataFormat(context, (DataFormat) service);
         } else if (service instanceof Producer) {
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDumpRouteStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDumpRouteStrategy.java
new file mode 100644
index 00000000000..8cf89153560
--- /dev/null
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedDumpRouteStrategy.java
@@ -0,0 +1,112 @@
+/*
+ * 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.management.mbean;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.api.management.mbean.ManagedDumpRoutesStrategyMBean;
+import org.apache.camel.spi.DumpRoutesStrategy;
+import org.apache.camel.spi.ManagementStrategy;
+
+@ManagedResource(description = "Managed DumpRouteStrategyMBean")
+public class ManagedDumpRouteStrategy implements ManagedDumpRoutesStrategyMBean {
+
+    private final CamelContext camelContext;
+    private final DumpRoutesStrategy dumpRoutesStrategy;
+
+    public ManagedDumpRouteStrategy(CamelContext camelContext, DumpRoutesStrategy dumpRoutesStrategy) {
+        this.camelContext = camelContext;
+        this.dumpRoutesStrategy = dumpRoutesStrategy;
+    }
+
+    public void init(ManagementStrategy strategy) {
+        // do nothing
+    }
+
+    public CamelContext getContext() {
+        return camelContext;
+    }
+
+    public DumpRoutesStrategy getDumpRoutesStrategy() {
+        return dumpRoutesStrategy;
+    }
+
+    @Override
+    public void dumpRoutes(String format) {
+        dumpRoutesStrategy.dumpRoutes(format);
+    }
+
+    @Override
+    public String getCamelId() {
+        return camelContext.getName();
+    }
+
+    @Override
+    public String getCamelManagementName() {
+        return camelContext.getManagementName();
+    }
+
+    @Override
+    public String getInclude() {
+        return dumpRoutesStrategy.getInclude();
+    }
+
+    @Override
+    public void setInclude(String include) {
+        dumpRoutesStrategy.setInclude(include);
+    }
+
+    @Override
+    public boolean isLog() {
+        return dumpRoutesStrategy.isLog();
+    }
+
+    @Override
+    public void setLog(boolean log) {
+        dumpRoutesStrategy.setLog(log);
+    }
+
+    @Override
+    public String getDirectory() {
+        return dumpRoutesStrategy.getDirectory();
+    }
+
+    @Override
+    public void setDirectory(String directory) {
+        dumpRoutesStrategy.setDirectory(directory);
+    }
+
+    @Override
+    public boolean isUriAsParameters() {
+        return dumpRoutesStrategy.isUriAsParameters();
+    }
+
+    @Override
+    public void setUriAsParameters(boolean uriAsParameters) {
+        dumpRoutesStrategy.setUriAsParameters(uriAsParameters);
+    }
+
+    @Override
+    public boolean isResolvePlaceholders() {
+        return dumpRoutesStrategy.isResolvePlaceholders();
+    }
+
+    @Override
+    public void setResolvePlaceholders(boolean resolvePlaceholders) {
+        dumpRoutesStrategy.setResolvePlaceholders(resolvePlaceholders);
+    }
+}
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteDumpStrategyTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteDumpStrategyTest.java
new file mode 100644
index 00000000000..6ed5443f28a
--- /dev/null
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteDumpStrategyTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.management;
+
+import java.io.File;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultDumpRoutesStrategy;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedRouteDumpStrategyTest extends ManagementTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        testDirectory(true);
+        String dir = testDirectory().toString();
+
+        CamelContext context = super.createCamelContext();
+        context.setDumpRoutes("xml");
+
+        DefaultDumpRoutesStrategy drd = new DefaultDumpRoutesStrategy();
+        drd.setInclude("all");
+        drd.setLog(false);
+        drd.setDirectory(dir);
+        drd.setResolvePlaceholders(false);
+        context.addService(drd);
+
+        return context;
+    }
+
+    @Test
+    public void testDumpStrategy() throws Exception {
+        MBeanServer mbeanServer = getMBeanServer();
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        String mbeanName
+                = String.format("org.apache.camel:context=" + context.getManagementName() + ",name=%s,type=services",
+                        DefaultDumpRoutesStrategy.class.getSimpleName());
+        Set<ObjectName> set = mbeanServer.queryNames(new ObjectName(mbeanName), null);
+        assertEquals(1, set.size());
+        ObjectName on = set.iterator().next();
+        assertTrue(mbeanServer.isRegistered(on));
+
+        String include = (String) mbeanServer.getAttribute(on, "Include");
+        assertEquals("all", include);
+        Boolean log = (Boolean) mbeanServer.getAttribute(on, "Log");
+        assertFalse(log);
+        Boolean rp = (Boolean) mbeanServer.getAttribute(on, "ResolvePlaceholders");
+        assertFalse(rp);
+
+        // dump should pre-exist
+        File dir = testDirectory().toFile();
+        String[] files = dir.list();
+        assertEquals(1, files.length);
+        assertEquals("dump1.xml", files[0]);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("myRoute")
+                        .log("Got ${body}")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java
index b3cee67a36a..fadc1ea22aa 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java
@@ -34,7 +34,6 @@ import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
index 768676a5300..6ceb325801e 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
@@ -253,7 +253,7 @@ public final class StringHelper {
                 return false;
             }
 
-             return Character.isUpperCase(text.charAt(lastIndexOf + 1));
+            return Character.isUpperCase(text.charAt(lastIndexOf + 1));
         }
 
         return false;
@@ -508,8 +508,8 @@ public final class StringHelper {
     /**
      * De-capitalize the string (lower case first character)
      *
-     * @param  text            the string
-     * @return                 the string decapitalized (lower case first character)
+     * @param  text the string
+     * @return      the string decapitalized (lower case first character)
      */
     public static String decapitalize(final String text) {
         if (text == null) {
@@ -1048,7 +1048,6 @@ public final class StringHelper {
             prev = ch;
         }
 
-
         return answer.toString();
     }
 
diff --git a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java
index 5ca7e650c3f..07d77c7a422 100644
--- a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java
+++ b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java
@@ -496,4 +496,38 @@ public final class JaxbHelper {
         }
     }
 
+    public static void removeAutoAssignedIds(Element element) {
+        final NamedNodeMap attrs = element.getAttributes();
+
+        Attr id = null;
+        Attr customId = null;
+        for (int index = 0; index < attrs.getLength(); index++) {
+            final Attr attr = (Attr) attrs.item(index);
+            final String attName = attr.getName();
+
+            if (attName.equals("id")) {
+                id = attr;
+            } else if (attName.equals("customId")) {
+                customId = attr;
+            }
+        }
+
+        // remove auto-assigned id
+        if (id != null && customId == null) {
+            attrs.removeNamedItem("id");
+        }
+        // remove customId as its noisy
+        if (customId != null) {
+            attrs.removeNamedItem("customId");
+        }
+
+        final NodeList children = element.getChildNodes();
+        for (int index = 0; index < children.getLength(); index++) {
+            final Node child = children.item(index);
+            if (child.getNodeType() == Node.ELEMENT_NODE) {
+                removeAutoAssignedIds((Element) child);
+            }
+        }
+    }
+
 }
diff --git a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
index 4495e74b37a..3bf298e862e 100644
--- a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
+++ b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
@@ -60,6 +60,7 @@ import static org.apache.camel.xml.jaxb.JaxbHelper.extractSourceLocations;
 import static org.apache.camel.xml.jaxb.JaxbHelper.getJAXBContext;
 import static org.apache.camel.xml.jaxb.JaxbHelper.modelToXml;
 import static org.apache.camel.xml.jaxb.JaxbHelper.newXmlConverter;
+import static org.apache.camel.xml.jaxb.JaxbHelper.removeAutoAssignedIds;
 import static org.apache.camel.xml.jaxb.JaxbHelper.resolveEndpointDslUris;
 
 /**
@@ -204,6 +205,8 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper {
             // okay there were some property placeholder or delegate endpoints
             // replaced so re-create the model
             if (changed.get()) {
+                // remove all generated ID from dom, as we do not want to copy those over
+                removeAutoAssignedIds(dom.getDocumentElement());
                 xml = context.getTypeConverter().mandatoryConvertTo(String.class, dom);
                 NamedNode copy = modelToXml(context, xml, NamedNode.class);
                 xml = PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, copy);
diff --git a/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
index e5bb748b333..2827cdaf0ef 100644
--- a/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
+++ b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
@@ -237,8 +237,8 @@ public final class Strings {
     /**
      * A simpler version of StringHelper#capitlize for usage in the tooling code
      *
-     * @param  text            the string
-     * @return                 the string capitalized (upper case first character) or null if the input is null
+     * @param  text the string
+     * @return      the string capitalized (upper case first character) or null if the input is null
      */
     public static String capitalize(final String text) {
         if (text == null) {