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 9b664d32bb8a041c0959a232f4ec0dd13ef1aef8 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Oct 29 14:08:30 2024 +0100 CAMEL-21391: Add support for <dataFormats> in model to xml dumper --- .../org/apache/camel/spi/ModelToXMLDumper.java | 11 +++ .../camel/impl/DefaultDumpRoutesStrategy.java | 41 +++++++++++ .../org/apache/camel/xml/LwModelToXMLDumper.java | 75 +++++++++++++++++++ .../java/org/apache/camel/xml/out/BaseWriter.java | 4 +- .../camel/xml/jaxb/JaxbModelToXMLDumper.java | 84 ++++++++++++++++++++++ .../dsl/jbang/core/commands/TransformRoute.java | 17 ++--- 6 files changed, 223 insertions(+), 9 deletions(-) diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/ModelToXMLDumper.java b/core/camel-api/src/main/java/org/apache/camel/spi/ModelToXMLDumper.java index 4c41645a4d1..951f3da64d0 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/ModelToXMLDumper.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/ModelToXMLDumper.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; @@ -65,4 +66,14 @@ public interface ModelToXMLDumper { */ String dumpBeansAsXml(CamelContext context, List<Object> beans) throws Exception; + /** + * Dumps the global data formats as XML + * + * @param context the CamelContext + * @param dataFormats list of data formats (DataFormatDefinition) + * @return the output in XML (is formatted) + * @throws Exception is throw if error marshalling to XML + */ + String dumpDataFormatsAsXml(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 d3237e4210b..b89c8fb39ac 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 @@ -384,6 +384,18 @@ public class DefaultDumpRoutesStrategy extends ServiceSupport implements DumpRou } } + protected void doDumpXmlDataFormats( + CamelContext camelContext, Map dataFormats, Resource resource, + ModelToXMLDumper dumper, String kind, StringBuilder sbLocal, StringBuilder sbLog) { + try { + String dump = dumper.dumpDataFormatsAsXml(camelContext, dataFormats); + sbLocal.append(dump); + appendLogDump(resource, dump, sbLog); + } catch (Exception e) { + LOG.warn("Error dumping {}} to XML 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); @@ -419,6 +431,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(); + doDumpXmlDataFormats(camelContext, dfs, resource == dummy ? null : resource, dumper, "dataFormats", sbLocal, sbLog); + // dump each resource into its own file + doDumpToDirectory(resource, sbLocal, "dataFormats", "xml", files); + } + if (!sbLog.isEmpty() && log) { + LOG.info("Dumping {} data formats as XML", size); + LOG.info("{}", sbLog); + } + } + } + if (include.contains("*") || include.contains("all") || include.contains("routes")) { int size = model.getRouteDefinitions().size(); if (size > 0) { diff --git a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java index 92fc6489e1b..76dd36e1f30 100644 --- a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java +++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java @@ -31,7 +31,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; @@ -41,6 +43,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.ModelToXMLDumper; import org.apache.camel.spi.NamespaceAware; @@ -198,6 +202,29 @@ public class LwModelToXMLDumper implements ModelToXMLDumper { return buffer.toString(); } + @Override + public String dumpDataFormatsAsXml(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(); + } + buffer.write("\n"); + + return buffer.toString(); + } + /** * Extract all XML namespaces from the expressions in the route * @@ -375,4 +402,52 @@ public class LwModelToXMLDumper implements ModelToXMLDumper { } } + 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; + } + + DataFormatsDefinition def = new DataFormatsDefinition(); + def.setDataFormats(new ArrayList<>(dataFormats.values())); + + StringWriter tmp = new StringWriter(); + ModelWriter writer = new ModelWriter(tmp, null); + writer.writeDataFormatsDefinition(def); + + // output with 4 space indent + for (String line : tmp.toString().split("\n")) { + buffer.write(" "); + buffer.write(line); + buffer.write("\n"); + } + } + } + } diff --git a/core/camel-xml-io/src/main/java/org/apache/camel/xml/out/BaseWriter.java b/core/camel-xml-io/src/main/java/org/apache/camel/xml/out/BaseWriter.java index 9a0ef341381..a8c4b779ce7 100644 --- a/core/camel-xml-io/src/main/java/org/apache/camel/xml/out/BaseWriter.java +++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/out/BaseWriter.java @@ -39,7 +39,9 @@ public class BaseWriter { public BaseWriter(Writer writer, String namespace) throws IOException { this.writer = new XMLWriter(writer); - this.namespacesStack.push(namespace); + if (namespace != null) { + this.namespacesStack.push(namespace); + } } protected void startElement(String name) throws IOException { 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 294e81c45f1..f12752fa7fe 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 @@ -36,6 +36,9 @@ import jakarta.xml.bind.Marshaller; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerException; +import org.apache.camel.model.DataFormatDefinition; +import org.apache.camel.model.dataformat.DataFormatsDefinition; +import org.apache.camel.util.StringHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -242,6 +245,29 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper { return buffer.toString(); } + @Override + public String dumpDataFormatsAsXml(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(); + } + buffer.write("\n"); + + return buffer.toString(); + } + private static void sanitizeXml(Node node, boolean generatedIds) { // we want to remove all customId="false" attributes as they are noisy if (node.hasAttributes()) { @@ -358,4 +384,62 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper { } } + 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; + } + + DataFormatsDefinition def = new DataFormatsDefinition(); + def.setDataFormats(new ArrayList<>(dataFormats.values())); + + final JAXBContext jaxbContext = getJAXBContext(camelContext); + + StringWriter tmp = new StringWriter(); + Marshaller marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); + marshaller.marshal(def, tmp); + + // remove unwanted namespace + String xml = tmp.toString(); + xml = xml.replace("<dataFormats xmlns=\"http://camel.apache.org/schema/spring\">", "<dataFormats>"); + xml = StringHelper.after(xml, "<dataFormats>"); + + // output with 4 space indent + buffer.write(" <dataFormats>"); + for (String line : xml.split("\n")) { + buffer.write(" "); + buffer.write(line); + buffer.write("\n"); + } + } + } + } 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 586eacdaa7e..79bf8ad5d8d 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 @@ -45,9 +45,8 @@ public class TransformRoute extends CamelCommand { private String output; @CommandLine.Option(names = { "--format" }, - description = "Output format (xml or yaml), if only yaml files are provided, the format defaults to xml and vice versa", - defaultValue = "yaml") - String format = "yaml"; + description = "Output format (xml or yaml), if only yaml files are provided, the format defaults to xml and vice versa") + String format; @CommandLine.Option(names = { "--resolve-placeholders" }, defaultValue = "false", description = "Whether to resolve property placeholders in the dumped output") @@ -68,11 +67,13 @@ public class TransformRoute extends CamelCommand { @Override public Integer doCall() throws Exception { - // Automatically transform to xml if all files are yaml - if (files.stream().allMatch(file -> file.endsWith(".yaml"))) { - format = "xml"; - } else { - format = "yaml"; + if (format == null) { + // Automatically transform to xml if all files are yaml + if (files.stream().allMatch(file -> file.endsWith(".yaml"))) { + format = "xml"; + } else { + format = "yaml"; + } } String dump = output;