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

Croway 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 197e70656a41 CAMEL-25490: camel-yaml-io - dump a top-level onException 
as top-level, not as a step of every route (#27609)
197e70656a41 is described below

commit 197e70656a413ec5aa9e0f8dd35fdd383e843312
Author: Federico Mariani <[email protected]>
AuthorDate: Sun Oct 11 10:30:22 2026 +0200

    CAMEL-25490: camel-yaml-io - dump a top-level onException as top-level, not 
as a step of every route (#27609)
    
    * CAMEL-25490: camel-yaml-io - dump a top-level onException as top-level, 
not as a step of every route
    
    When routes are prepared, the context scoped onExceptions (the top-level
    onException of a YAML file, the onException of a RouteBuilder, and those
    of the route configurations that apply) are added to the outputs of each
    route. The YAML dumper wrote them as steps of every route, which the YAML
    DSL schema rejects, so camel validate normalize turned a valid file into
    an invalid one.
    
    The YAML dumper now leaves the context scoped onExceptions out of the
    route steps, and writes those that do not belong to a route configuration
    once, as top-level onException entries before the routes.
    
    * CAMEL-25490: camel-core-engine - dump the routes of all the files 
together when they go into one YAML file
    
    When the routes are dumped into a single file (dumpRoutesOutput is a file,
    as camel validate normalize does), the routes of each source file were
    dumped separately and appended, so the top-level onException of a second
    file came after the routes of the first file, which the YAML DSL loader
    rejects. The routes of all the files are now dumped together, so every
    top-level onException comes before the first route.
    
    * CAMEL-25490: camel-yaml-io - guard against a null onException list of a 
route configuration
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    
    * CAMEL-25490: camel-core-engine - dump the routes of one file into a file 
with their source, and warn when a top-level onException applies to the routes 
of other files
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    
    * CAMEL-25490: upgrade guide entries for the YAML dump of a top-level 
onException
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    
    * CAMEL-25490: trim overlapping test assertions
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 .../camel/impl/DefaultDumpRoutesStrategy.java      |  60 ++++-
 .../org/apache/camel/yaml/LwModelToYAMLDumper.java |  63 ++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    |  12 +
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  11 +
 .../camel/dsl/yaml/OnExceptionYamlDumpTest.java    | 252 +++++++++++++++++++++
 5 files changed, 396 insertions(+), 2 deletions(-)

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
index fc7a187c317a..8a8103adf340 100644
--- 
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
@@ -23,6 +23,7 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -34,6 +35,8 @@ import org.apache.camel.NamedNode;
 import org.apache.camel.model.BeanFactoryDefinition;
 import org.apache.camel.model.DataFormatDefinition;
 import org.apache.camel.model.Model;
+import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteConfigurationsDefinition;
 import org.apache.camel.model.RouteDefinition;
@@ -516,14 +519,24 @@ public class DefaultDumpRoutesStrategy extends 
ServiceSupport implements DumpRou
         if (include.contains("*") || include.contains("all") || 
include.contains("routes")) {
             int size = model.getRouteDefinitions().size();
             if (size > 0) {
-                Map<Resource, RoutesDefinition> groups = new LinkedHashMap<>();
+                List<RouteDefinition> eligible = new ArrayList<>();
                 for (RouteDefinition route : model.getRouteDefinitions()) {
                     if ((route.isRest() != null && route.isRest()) || 
(route.isTemplate() != null && route.isTemplate())) {
                         // skip routes that are rest/templates
                         continue;
                     }
+                    eligible.add(route);
+                }
+                // the routes of several resources dumped into the same file 
are dumped together, so the top-level
+                // elements of the resources (such as onException) come before 
the first route
+                boolean merge = outputFileName != null && 
countResources(eligible) > 1;
+                if (merge) {
+                    warnIfOnExceptionScopeWidens(model, eligible);
+                }
+                Map<Resource, RoutesDefinition> groups = new LinkedHashMap<>();
+                for (RouteDefinition route : eligible) {
                     Resource res = route.getResource();
-                    if (res == null) {
+                    if (res == null || merge) {
                         res = dummy;
                     }
                     RoutesDefinition routes = groups.computeIfAbsent(res, 
resource -> new RoutesDefinition());
@@ -548,6 +561,49 @@ public class DefaultDumpRoutesStrategy extends 
ServiceSupport implements DumpRou
 
     }
 
+    private static int countResources(List<RouteDefinition> routes) {
+        Set<Resource> resources = new HashSet<>();
+        for (RouteDefinition route : routes) {
+            resources.add(route.getResource());
+        }
+        return resources.size();
+    }
+
+    /**
+     * A top-level onException applies only to the routes of its own resource, 
but once the routes of several resources
+     * are dumped into the same file, it applies to all the routes of the file 
when the file is loaded.
+     */
+    private void warnIfOnExceptionScopeWidens(Model model, 
List<RouteDefinition> routes) {
+        Set<String> locations = new LinkedHashSet<>();
+        for (RouteDefinition route : routes) {
+            for (ProcessorDefinition<?> output : route.getOutputs()) {
+                if (output instanceof OnExceptionDefinition oe && 
!oe.isRouteScoped()
+                        && !isInRouteConfiguration(model, oe)) {
+                    Resource res = route.getResource();
+                    locations.add(res != null && res.getLocation() != null ? 
res.getLocation() : "routes without a source");
+                }
+            }
+        }
+        if (!locations.isEmpty()) {
+            LOG.warn("The routes of several resources are dumped together into 
{}: the top-level onException of {}"
+                     + " applies to all the routes of the dump when it is 
loaded",
+                    outputFileName, String.join(", ", locations));
+        }
+    }
+
+    private static boolean isInRouteConfiguration(Model model, 
OnExceptionDefinition oe) {
+        for (RouteConfigurationDefinition config : 
model.getRouteConfigurationDefinitions()) {
+            if (config.getOnExceptions() != null) {
+                for (OnExceptionDefinition o : config.getOnExceptions()) {
+                    if (o == oe) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     protected void doDumpRoutesAsJava(CamelContext camelContext) {
         final ModelToJavaDumper dumper = 
PluginHelper.getModelToJavaDumper(camelContext);
         final Model model = 
camelContext.getCamelContextExtension().getContextPlugin(Model.class);
diff --git 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
index 31424f5136e2..6d6a6441be5e 100644
--- 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
+++ 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
@@ -38,6 +39,8 @@ import org.apache.camel.model.ExpressionNode;
 import org.apache.camel.model.FromDefinition;
 import org.apache.camel.model.InterceptFromDefinition;
 import org.apache.camel.model.InterceptSendToEndpointDefinition;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.OnExceptionDefinition;
 import org.apache.camel.model.OptionalIdentifiedDefinition;
 import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteConfigurationsDefinition;
@@ -108,7 +111,29 @@ public class LwModelToYAMLDumper implements 
ModelToYAMLDumper {
             extractor.accept(route);
         }
 
+        // context scoped onExceptions (a top-level onException in the YAML 
DSL, an onException in the configure method
+        // of a RouteBuilder, or one of a route configuration) are added to 
the outputs of each route when the routes
+        // are prepared, but the YAML DSL does not allow them in the steps of 
a route
+        List<OnExceptionDefinition> contextScoped = new ArrayList<>();
+        if (definition instanceof RoutesDefinition routes) {
+            routes.getRoutes().forEach(route -> 
collectContextScopedOnExceptions(route, contextScoped));
+        } else if (definition instanceof RouteDefinition route) {
+            collectContextScopedOnExceptions(route, contextScoped);
+        }
+        // the onExceptions of a route configuration are dumped with the route 
configuration, the others are dumped
+        // once, as top-level onExceptions before the routes
+        List<OnExceptionDefinition> topLevel = new ArrayList<>(contextScoped);
+        topLevel.removeIf(oe -> isInRouteConfiguration(context, oe));
+
         YamlModelWriter writer = new YamlModelWriter() {
+            @Override
+            protected <T> void doWriteOutputs(JsonObject jo, List<T> list, 
Function<T, JsonObject> writer) {
+                if (list != null && !contextScoped.isEmpty()) {
+                    list = list.stream().filter(o -> 
!containsInstance(contextScoped, o)).toList();
+                }
+                super.doWriteOutputs(jo, list, writer);
+            }
+
             @Override
             protected void doWriteOptionalIdentifiedDefinitionAttributes(
                     JsonObject jo, OptionalIdentifiedDefinition<?> def) {
@@ -200,6 +225,9 @@ public class LwModelToYAMLDumper implements 
ModelToYAMLDumper {
 
         List<JsonObject> roots = new ArrayList<>();
         try {
+            for (OnExceptionDefinition oe : topLevel) {
+                roots.add(writer.writeOnExceptionDefinition(oe));
+            }
             if (definition instanceof RoutesDefinition rd) {
                 for (RouteDefinition route : rd.getRoutes()) {
                     roots.add(writer.writeRouteDefinition(route));
@@ -289,6 +317,41 @@ public class LwModelToYAMLDumper implements 
ModelToYAMLDumper {
         return buffer.toString();
     }
 
+    /**
+     * Collects the context scoped onExceptions that were added to the outputs 
of the route when it was prepared
+     */
+    private static void collectContextScopedOnExceptions(RouteDefinition 
route, List<OnExceptionDefinition> answer) {
+        for (var output : route.getOutputs()) {
+            if (output instanceof OnExceptionDefinition oe && 
!oe.isRouteScoped() && !containsInstance(answer, oe)) {
+                answer.add(oe);
+            }
+        }
+    }
+
+    private static boolean isInRouteConfiguration(CamelContext context, 
OnExceptionDefinition oe) {
+        Model model = context != null ? 
context.getCamelContextExtension().getContextPlugin(Model.class) : null;
+        if (model != null) {
+            for (RouteConfigurationDefinition config : 
model.getRouteConfigurationDefinitions()) {
+                if (containsInstance(config.getOnExceptions(), oe)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static boolean containsInstance(List<?> list, Object instance) {
+        if (list == null) {
+            return false;
+        }
+        for (Object o : list) {
+            if (o == instance) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Extract all XML namespaces from the expressions in the route
      *
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index 5b8d13eebf62..13d53b9a17f2 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -20,6 +20,18 @@ counted each exchange once per member route instead of once 
per entry into the g
 unintended side effect of CAMEL-24590. The counters now count each exchange 
once per entry into the
 group again, as in 4.22.0: calls nested inside another route of the same group 
are not counted again.
 
+=== Route dumps as YAML - top-level onException
+
+A top-level `onException` (of a YAML file, or in the `configure` method of a 
`RouteBuilder`) is now dumped as YAML
+(`camel.main.dumpRoutes=yaml`, `camel validate normalize`) once as a top-level 
`onException` before the routes, instead
+of as a step of every route, and the `onException` of a route configuration is 
only dumped with the route
+configuration, no longer in the routes. Before, such a dump did not load in 
the YAML DSL.
+
+When `camel.main.dumpRoutesOutput` is a file and the routes come from several 
files, they are now dumped together, so a
+top-level `onException` comes before the first route. When the dump is loaded, 
such an `onException` applies to the
+routes of all the files, not only to those of its own file, and a WARN is 
logged when the routes are dumped. Dump into
+a directory to keep one file per source file.
+
 === camel-pqc - Bouncy Castle 1.86 (Breaking change)
 
 Camel 4.22.2 uses Bouncy Castle 1.86, which removes the legacy implementations 
of several post-quantum
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 943563d8329e..36733808a431 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -5211,6 +5211,17 @@ as Java, the error handler of an XML or YAML route is 
now `.errorHandler(...)` o
 The `timeout(long)` of the Resequencer EIP in Java keeps the millis as given 
(`2000`), instead of a duration
 (`2s0ms`).
 
+A top-level `onException` (of a YAML file, or in the `configure` method of a 
`RouteBuilder`) is now dumped once as a
+top-level `onException` before the routes, instead of as a step of every 
route, and the `onException` of a route
+configuration is only dumped with the route configuration, no longer in the 
routes. This also applies to the dump of a
+single route (JMX `dumpRouteAsYaml`, the `route-dump` developer console). 
Before, such a dump did not load in the YAML
+DSL.
+
+When `camel.main.dumpRoutesOutput` is a file and the routes come from several 
files, they are now dumped together, so a
+top-level `onException` comes before the first route. When the dump is loaded, 
such an `onException` applies to the
+routes of all the files, not only to those of its own file, and a WARN is 
logged when the routes are dumped. Dump into
+a directory to keep one file per source file.
+
 === camel-jbang-mcp - camel_transform_route
 
 The `camel_transform_route` tool now converts with the same route DSL 
converter as `camel transform route
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/OnExceptionYamlDumpTest.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/OnExceptionYamlDumpTest.java
new file mode 100644
index 000000000000..4aae60a0d887
--- /dev/null
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/OnExceptionYamlDumpTest.java
@@ -0,0 +1,252 @@
+/*
+ * 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.dsl.yaml;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.NamedNode;
+import org.apache.camel.dsl.yaml.support.YamlTestSupport;
+import org.apache.camel.impl.DefaultDumpRoutesStrategy;
+import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.spi.ModelToYAMLDumper;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.yaml.LwModelToYAMLDumper;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class OnExceptionYamlDumpTest extends YamlTestSupport {
+
+    @ParameterizedTest
+    @ValueSource(booleans = { false, true })
+    void topLevelOnExceptionIsDumpedAsTopLevel(boolean started) throws 
Exception {
+        loadRoutes("""
+                - onException:
+                    exception:
+                      - java.lang.Exception
+                    handled:
+                      constant:
+                        expression: "true"
+                    steps:
+                      - to: mock:error
+                - route:
+                    id: first
+                    from:
+                      uri: direct:first
+                      steps:
+                        - to: mock:first
+                - route:
+                    id: second
+                    from:
+                      uri: direct:second
+                      steps:
+                        - to: mock:second
+                """);
+        if (started) {
+            context.start();
+        }
+        String yaml = dumpRoutes();
+        // a route dumped alone (JMX dumpRouteAsYaml, the route-dump dev 
console)
+        String single = new LwModelToYAMLDumper()
+                .dumpModelAsYaml(context, context.getRouteDefinition("first"), 
false, true, false, false);
+        if (started) {
+            context.stop();
+        }
+
+        // written once, before the routes, and not in the steps of each route
+        assertThat(yaml).startsWith("- onException:");
+        assertThat(yaml.split("onException:", -1)).hasSize(2);
+        // also before a route dumped alone
+        assertThat(single).startsWith("- onException:").contains("id: 
first").doesNotContain("id: second");
+
+        // the dump is valid for the YAML DSL schema, and the onException 
still applies to all the routes
+        
context.removeRouteDefinitions(List.copyOf(context.getRouteDefinitions()));
+        loadRoutes(yaml);
+        for (String id : List.of("first", "second")) {
+            OnExceptionDefinition oe = (OnExceptionDefinition) 
context.getRouteDefinition(id).getOutputs().get(0);
+            assertThat(oe.isRouteScoped()).isFalse();
+            
assertThat(oe.getExceptions()).containsExactly("java.lang.Exception");
+        }
+    }
+
+    @Test
+    void routeConfigurationOnExceptionIsNotDumpedInTheRoutes() throws 
Exception {
+        loadRoutes("""
+                - routeConfiguration:
+                    onException:
+                      - onException:
+                          exception:
+                            - java.lang.Exception
+                          handled:
+                            constant:
+                              expression: "true"
+                          steps:
+                            - to: mock:error
+                """);
+        loadRoutes("""
+                - route:
+                    id: myRoute
+                    from:
+                      uri: direct:start
+                      steps:
+                        - to: mock:result
+                """);
+        
assertThat(context.getRouteDefinition("myRoute").getOutputs().get(0)).isInstanceOf(OnExceptionDefinition.class);
+
+        // the onException is dumped with the route configuration
+        String yaml = dumpRoutes();
+        assertThat(yaml).doesNotContain("onException").contains("id: myRoute");
+        context.removeRouteDefinition(context.getRouteDefinition("myRoute"));
+        loadRoutes(yaml);
+    }
+
+    @Test
+    void onExceptionOfAnotherFileIsDumpedBeforeTheRoutesInOneFile(@TempDir 
Path dir) throws Exception {
+        // two files normalized into one, as camel validate normalize a.yaml 
b.yaml does: the onException of the
+        // second file must come before the route of the first one, or the 
dump does not load
+        loadRoutes("""
+                - route:
+                    id: first
+                    from:
+                      uri: direct:first
+                      steps:
+                        - to: mock:first
+                """, """
+                - onException:
+                    exception:
+                      - java.lang.Exception
+                    handled:
+                      constant:
+                        expression: "true"
+                    steps:
+                      - to: mock:error
+                - route:
+                    id: second
+                    from:
+                      uri: direct:second
+                      steps:
+                        - to: mock:second
+                """);
+
+        Path output = dir.resolve("normalized.yaml");
+        List<String> warnings = new ArrayList<>();
+        dumpRoutesToFile(output, new ArrayList<>(), warnings);
+        String yaml = Files.readString(output);
+
+        assertThat(yaml).startsWith("- onException:");
+        assertThat(yaml.split("onException:", -1)).hasSize(2);
+        assertThat(yaml).contains("id: first", "id: second");
+
+        // the user is told that the onException of the second file applies to 
the route of the first file as well
+        
assertThat(warnings).singleElement().asString().contains("route-1.yaml").doesNotContain("route-0.yaml");
+
+        // the combined dump is valid for the YAML DSL schema and loads
+        
assertThat(context.getRouteDefinition("first").getOutputs()).noneMatch(OnExceptionDefinition.class::isInstance);
+        
context.removeRouteDefinitions(List.copyOf(context.getRouteDefinitions()));
+        loadRoutes(yaml);
+        assertThat(context.getRouteDefinitions()).hasSize(2);
+        // the top-level onException of the second file now applies to the 
route of the first file as well
+        
assertThat(context.getRouteDefinition("first").getOutputs().get(0)).isInstanceOf(OnExceptionDefinition.class);
+    }
+
+    @Test
+    void routesOfOneFileDumpedIntoOneFileKeepTheirSource(@TempDir Path dir) 
throws Exception {
+        loadRoutes("""
+                - onException:
+                    exception:
+                      - java.lang.Exception
+                    handled:
+                      constant:
+                        expression: "true"
+                    steps:
+                      - to: mock:error
+                - route:
+                    id: first
+                    from:
+                      uri: direct:first
+                      steps:
+                        - to: mock:first
+                """);
+
+        Path output = dir.resolve("normalized.yaml");
+        List<Resource> resources = new ArrayList<>();
+        List<String> warnings = new ArrayList<>();
+        dumpRoutesToFile(output, resources, warnings);
+
+        // the routes are dumped with their resource, so the log shows its 
source, and there is no scope to warn about
+        
assertThat(resources).singleElement().extracting(Resource::getLocation).isEqualTo("route-0.yaml");
+        assertThat(warnings).isEmpty();
+    }
+
+    private void dumpRoutesToFile(Path output, List<Resource> resources, 
List<String> warnings) {
+        AbstractAppender appender = new AbstractAppender("dump-routes", null, 
null, false, Property.EMPTY_ARRAY) {
+            @Override
+            public void append(LogEvent event) {
+                if (event.getLevel() == Level.WARN) {
+                    warnings.add(event.getMessage().getFormattedMessage());
+                }
+            }
+        };
+        appender.start();
+        Logger logger = (Logger) 
LogManager.getLogger(DefaultDumpRoutesStrategy.class);
+        logger.addAppender(appender);
+        try {
+            DefaultDumpRoutesStrategy dump = new DefaultDumpRoutesStrategy() {
+                @Override
+                protected void doDumpYaml(
+                        CamelContext camelContext, NamedNode def, Resource 
resource, ModelToYAMLDumper dumper,
+                        String kind, StringBuilder sbLocal, StringBuilder 
sbLog) {
+                    resources.add(resource);
+                    super.doDumpYaml(camelContext, def, resource, dumper, 
kind, sbLocal, sbLog);
+                }
+            };
+            dump.setCamelContext(context);
+            dump.setInclude("routes");
+            dump.setLog(false);
+            dump.setUriAsParameters(true);
+            dump.setOutput(output.toString());
+            dump.dumpRoutes("yaml");
+        } finally {
+            logger.removeAppender(appender);
+            appender.stop();
+        }
+    }
+
+    private String dumpRoutes() throws Exception {
+        // as the routes are dumped by camel.main.dumpRoutes, which camel 
validate normalize uses
+        RoutesDefinition routes = new RoutesDefinition();
+        for (RouteDefinition route : context.getRouteDefinitions()) {
+            routes.getRoutes().add(route);
+        }
+        return new LwModelToYAMLDumper().dumpModelAsYaml(context, routes, 
false, true, false, false);
+    }
+}

Reply via email to