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

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

commit 9838cfff7a8a93a3d98ec98ccefb65371a87874f
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Tue Oct 29 13:15:52 2024 +0100

    CAMEL-21391: Add support for <dataFormats> in model to yaml dumper
---
 .../org/apache/camel/spi/DumpRoutesStrategy.java   |   2 +-
 .../org/apache/camel/spi/ModelToYAMLDumper.java    |  11 +++
 .../camel/impl/DefaultDumpRoutesStrategy.java      |  42 ++++++++
 .../camel-main-configuration-metadata.json         |   2 +-
 core/camel-main/src/main/docs/main.adoc            |   2 +-
 .../camel/main/DefaultConfigurationProperties.java |   4 +-
 .../org/apache/camel/yaml/LwModelToYAMLDumper.java | 108 +++++++++++++++++++++
 .../java/org/apache/camel/yaml/io/YamlWriter.java  |  15 ++-
 .../dsl/jbang/core/commands/TransformRoute.java    |   2 +-
 9 files changed, 181 insertions(+), 7 deletions(-)

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
index 7143fc5f08d..f695c6968bb 100644
--- 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
@@ -40,7 +40,7 @@ public interface DumpRoutesStrategy extends StaticService {
     /**
      * Controls what to include in output.
      *
-     * Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans. Multiple values can be separated
+     * Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans, dataFormats. Multiple values can be separated
      * by comma. Default is routes.
      */
     void setInclude(String include);
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/ModelToYAMLDumper.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/ModelToYAMLDumper.java
index d6bda7e689b..179ed52ff55 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/ModelToYAMLDumper.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/ModelToYAMLDumper.java
@@ -17,6 +17,7 @@
 package org.apache.camel.spi;
 
 import java.util.List;
+import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.NamedNode;
@@ -67,4 +68,14 @@ public interface ModelToYAMLDumper {
      */
     String dumpBeansAsYaml(CamelContext context, List<Object> beans) throws 
Exception;
 
+    /**
+     * Dumps the global data formats as YAML
+     *
+     * @param  context     the CamelContext
+     * @param  dataFormats list of data formats (DataFormatDefinition)
+     * @return             the output in YAML (is formatted)
+     * @throws Exception is throw if error marshalling to YAML
+     */
+    String dumpDataFormatsAsYaml(CamelContext context, Map<String, Object> 
dataFormats) throws Exception;
+
 }
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 2e87a16060d..d3237e4210b 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
@@ -32,6 +32,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 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.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteConfigurationsDefinition;
@@ -192,6 +193,35 @@ public class DefaultDumpRoutesStrategy extends 
ServiceSupport implements DumpRou
             }
         }
 
+        if (include.contains("*") || include.contains("all") || 
include.contains("dataFormats")) {
+            int size = model.getDataFormats().size();
+            if (size > 0) {
+                Map<Resource, Map<String, DataFormatDefinition>> groups = new 
LinkedHashMap<>();
+                for (Map.Entry<String, DataFormatDefinition> entry : 
model.getDataFormats().entrySet()) {
+                    Resource res = entry.getValue().getResource();
+                    if (res == null) {
+                        res = dummy;
+                    }
+                    Map<String, DataFormatDefinition> dfs = 
groups.computeIfAbsent(res, resource -> new LinkedHashMap<>());
+                    dfs.put(entry.getKey(), entry.getValue());
+                }
+                StringBuilder sbLog = new StringBuilder();
+                for (Map.Entry<Resource, Map<String, DataFormatDefinition>> 
entry : groups.entrySet()) {
+                    Map<String, DataFormatDefinition> dfs = entry.getValue();
+                    Resource resource = entry.getKey();
+
+                    StringBuilder sbLocal = new StringBuilder();
+                    doDumpYamlDataFormats(camelContext, dfs, resource == dummy 
? null : resource, dumper, "dataFormats", sbLocal, sbLog);
+                    // dump each resource into its own file
+                    doDumpToDirectory(resource, sbLocal, "dataFormats", 
"yaml", files);
+                }
+                if (!sbLog.isEmpty() && log) {
+                    LOG.info("Dumping {} data formats as YAML", size);
+                    LOG.info("{}", sbLog);
+                }
+            }
+        }
+
         if (include.contains("*") || include.contains("all") || 
include.contains("routes")) {
             int size = model.getRouteDefinitions().size();
             if (size > 0) {
@@ -342,6 +372,18 @@ public class DefaultDumpRoutesStrategy extends 
ServiceSupport implements DumpRou
         }
     }
 
+    protected void doDumpYamlDataFormats(
+            CamelContext camelContext, Map dataFormats, Resource resource,
+            ModelToYAMLDumper dumper, String kind, StringBuilder sbLocal, 
StringBuilder sbLog) {
+        try {
+            String dump = dumper.dumpDataFormatsAsYaml(camelContext, 
dataFormats);
+            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);
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 289eec71365..71c78f669b8 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
@@ -47,7 +47,7 @@
     { "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.dumpRoutesGeneratedIds", "description": "Whether to 
include auto generated IDs in the dumped output. Default is false.", 
"sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
-    { "name": "camel.main.dumpRoutesInclude", "description": "Controls what to 
include in output for route dumping. Possible values: all, routes, rests, 
routeConfigurations, routeTemplates, beans. 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.dumpRoutesInclude", "description": "Controls what to 
include in output for route dumping. Possible values: all, routes, rests, 
routeConfigurations, routeTemplates, beans, dataFormats. 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.dumpRoutesOutput", "description": "Whether to save 
route dumps to an output file. If the output is a filename, then all content is 
saved to this file. If the output is a directory name, then one or more files 
are saved to the directory, where the names are based on the original source 
file names, or auto generated names.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "string", 
"javaType": "java.lang.String" },
     { "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 },
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index e9899e5ae41..13a0bfb2888 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -49,7 +49,7 @@ The camel.main supports 122 options, which are listed below.
 | *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.dumpRoutesGenerated{zwsp}Ids* | Whether to include auto 
generated IDs in the dumped output. Default is false. | false | boolean
-| *camel.main.dumpRoutesInclude* | Controls what to include in output for 
route dumping. Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans. Multiple values can be separated by comma. Default is 
routes. | routes | String
+| *camel.main.dumpRoutesInclude* | Controls what to include in output for 
route dumping. Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans, dataFormats. 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.dumpRoutesOutput* | Whether to save route dumps to an output 
file. If the output is a filename, then all content is saved to this file. If 
the output is a directory name, then one or more files are saved to the 
directory, where the names are based on the original source file names, or auto 
generated names. |  | String
 | *camel.main.dumpRoutesResolve{zwsp}Placeholders* | Whether to resolve 
property placeholders in the dumped output. Default is true. | true | boolean
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 3c66df288e5..e7f13d09341 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
@@ -1450,7 +1450,7 @@ public abstract class DefaultConfigurationProperties<T> {
     /**
      * Controls what to include in output for route dumping.
      *
-     * Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans. Multiple values can be separated
+     * Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans, dataFormats. Multiple values can be separated
      * by comma. Default is routes.
      */
     public void setDumpRoutesInclude(String dumpRoutesInclude) {
@@ -2602,7 +2602,7 @@ public abstract class DefaultConfigurationProperties<T> {
     /**
      * Controls what to include in output for route dumping.
      *
-     * Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans. Multiple values can be separated
+     * Possible values: all, routes, rests, routeConfigurations, 
routeTemplates, beans, dataFormats. Multiple values can be separated
      * by comma. Default is routes.
      */
     public T withDumpRoutesInclude(String dumpRoutesInclude) {
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 add9e92e606..b6069a76388 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
@@ -32,7 +32,9 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Expression;
 import org.apache.camel.NamedNode;
+import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.model.BeanFactoryDefinition;
+import org.apache.camel.model.DataFormatDefinition;
 import org.apache.camel.model.ExpressionNode;
 import org.apache.camel.model.FromDefinition;
 import org.apache.camel.model.OptionalIdentifiedDefinition;
@@ -42,6 +44,8 @@ import org.apache.camel.model.RouteTemplatesDefinition;
 import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.SendDefinition;
 import org.apache.camel.model.ToDynamicDefinition;
+import org.apache.camel.model.dataformat.BeanioDataFormat;
+import org.apache.camel.model.dataformat.DataFormatsDefinition;
 import org.apache.camel.model.language.ExpressionDefinition;
 import org.apache.camel.spi.ModelToYAMLDumper;
 import org.apache.camel.spi.NamespaceAware;
@@ -186,6 +190,36 @@ public class LwModelToYAMLDumper implements 
ModelToYAMLDumper {
         return buffer.toString();
     }
 
+    /**
+     * Dumps the global data formats as YAML
+     *
+     * @param  context     the CamelContext
+     * @param  dataFormats list of data formats (DataFormatDefinition)
+     * @return             the output in YAML (is formatted)
+     * @throws Exception is throw if error marshalling to YAML
+     */
+    @Override
+    public String dumpDataFormatsAsYaml(CamelContext context, Map<String, 
Object> dataFormats) throws Exception {
+        StringWriter buffer = new StringWriter();
+        DataFormatModelWriter writer = new DataFormatModelWriter(buffer);
+
+        Map<String, DataFormatDefinition> map = new LinkedHashMap<>();
+        for (Map.Entry<String, Object> entry : dataFormats.entrySet()) {
+            if (entry.getValue() instanceof DataFormatDefinition def) {
+                map.put(entry.getKey(), def);
+            }
+        }
+        writer.setCamelContext(context);
+        writer.start();
+        try {
+            writer.writeDataFormats(map);
+        } finally {
+            writer.stop();
+        }
+
+        return buffer.toString();
+    }
+
     /**
      * Extract all XML namespaces from the expressions in the route
      *
@@ -362,4 +396,78 @@ public class LwModelToYAMLDumper implements 
ModelToYAMLDumper {
         }
     }
 
+    private static class DataFormatModelWriter implements CamelContextAware {
+
+        private final StringWriter buffer;
+        private CamelContext camelContext;
+
+        public DataFormatModelWriter(StringWriter buffer) {
+            this.buffer = buffer;
+        }
+
+        @Override
+        public CamelContext getCamelContext() {
+            return camelContext;
+        }
+
+        @Override
+        public void setCamelContext(CamelContext camelContext) {
+            this.camelContext = camelContext;
+        }
+
+        public void start() {
+            // noop
+        }
+
+        public void stop() {
+            // noop
+        }
+
+        public void writeDataFormats(Map<String, DataFormatDefinition> 
dataFormats) throws Exception {
+            if (dataFormats.isEmpty()) {
+                return;
+            }
+
+            buffer.write("- dataFormats:\n");
+
+            DataFormatsDefinition def = new DataFormatsDefinition();
+            def.setDataFormats(new ArrayList<>(dataFormats.values()));
+
+            StringWriter tmp = new StringWriter();
+            ModelWriter writer = new ModelWriter(tmp);
+            writer.setCamelContext(camelContext);
+            writer.start();
+            try {
+                writer.writeDataFormatsDefinition(def);
+            } finally {
+                writer.stop();
+            }
+            for (String line : tmp.toString().split("\n")) {
+                buffer.write("    ");
+                buffer.write(line);
+                buffer.write("\n");
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        StringWriter sw = new StringWriter();
+        DataFormatModelWriter w = new DataFormatModelWriter(sw);
+
+        BeanioDataFormat d = new BeanioDataFormat();
+        d.setId("df1");
+        d.setEncoding("abc");
+        d.setIgnoreUnexpectedRecords("true");
+        d.setMapping("myMapping");
+
+        CamelContext context = new DefaultCamelContext();
+        context.start();
+        w.setCamelContext(context);
+        w.start();
+        w.writeDataFormats(Map.of("myDF", d));
+        w.stop();
+
+        System.out.println(sw.toString());
+    }
+
 }
diff --git 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/io/YamlWriter.java 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/io/YamlWriter.java
index f5a95277e89..91c83763bd6 100644
--- a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/io/YamlWriter.java
+++ b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/io/YamlWriter.java
@@ -61,6 +61,7 @@ public class YamlWriter extends ServiceSupport implements 
CamelContextAware {
     private final DefaultRuntimeCamelCatalog catalog;
     private final List<EipModel> roots = new ArrayList<>();
     private boolean routesIsRoot;
+    private boolean dataFormatsIsRoot;
     private final ArrayDeque<EipModel> models = new ArrayDeque<>();
     private String expression;
     private boolean uriAsParameters;
@@ -103,6 +104,10 @@ public class YamlWriter extends ServiceSupport implements 
CamelContextAware {
             routesIsRoot = true;
             return;
         }
+        if ("dataFormats".equals(name)) {
+            dataFormatsIsRoot = true;
+            return;
+        }
 
         EipModel model = catalog.eipModel(name);
         if (model == null) {
@@ -130,7 +135,7 @@ public class YamlWriter extends ServiceSupport implements 
CamelContextAware {
     }
 
     public void endElement(String name) throws IOException {
-        if ("routes".equals(name)) {
+        if ("routes".equals(name) || "dataFormats".equals(name)) {
             // we are done
             writer.write(toYaml());
             return;
@@ -168,6 +173,14 @@ public class YamlWriter extends ServiceSupport implements 
CamelContextAware {
                 if ("from".equals(name) && parent.isInput()) {
                     // only set input once
                     parent.getMetadata().put("_input", last);
+                } else if ("dataFormats".equals(parent.getName())) {
+                    // special for dataFormats
+                    List<EipModel> list = (List<EipModel>) 
parent.getMetadata().get("_output");
+                    if (list == null) {
+                        list = new ArrayList<>();
+                        parent.getMetadata().put("_output", list);
+                    }
+                    list.add(last);
                 } else if ("choice".equals(parent.getName())) {
                     // special for choice/doCatch/doFinally
                     setMetadata(parent, name, last);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
index e45b546307d..586eacdaa7e 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
@@ -86,7 +86,7 @@ public class TransformRoute extends CamelCommand {
             @Override
             protected void doAddInitialProperty(KameletMain main) {
                 main.addInitialProperty("camel.main.dumpRoutes", format);
-                main.addInitialProperty("camel.main.dumpRoutesInclude", 
"routes,rests,routeConfigurations,beans");
+                main.addInitialProperty("camel.main.dumpRoutesInclude", 
"routes,rests,routeConfigurations,beans,dataFormats");
                 main.addInitialProperty("camel.main.dumpRoutesLog", "false");
                 
main.addInitialProperty("camel.main.dumpRoutesResolvePlaceholders", 
Boolean.toString(resolvePlaceholders));
                 
main.addInitialProperty("camel.main.dumpRoutesUriAsParameters", 
Boolean.toString(uriAsParameters));

Reply via email to