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));