All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.camunda.connectors.soap.xml.ToXmlMapper Maven / Gradle / Ivy

There is a newer version: 8.6.2
Show newest version
/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
 * under one or more contributor license agreements. Licensed under a proprietary license.
 * See the License.txt file for more information. You may not use this file
 * except in compliance with the proprietary license.
 */
package io.camunda.connectors.soap.xml;

import static io.camunda.connectors.soap.xml.TemplateUtil.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import com.samskivert.mustache.Template;
import io.camunda.connectors.soap.xml.ToXmlMapper.XmlNode.ElementXmlNode;
import io.camunda.connectors.soap.xml.ToXmlMapper.XmlNode.TextXmlNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.w3c.dom.Document;

public class ToXmlMapper {
  public static final Template XML_ELEMENT_TEMPLATE =
      loadTemplate("xml-element-template.mustache", false);
  private final ObjectMapper objectMapper;
  private final String contentName;
  private final String attributePrefix;
  private final boolean prettyPrint;
  private final boolean omitXmlDeclaration;

  public ToXmlMapper(
      ObjectMapper objectMapper,
      String contentName,
      String attributePrefix,
      boolean prettyPrint,
      boolean omitXmlDeclaration) {
    this.objectMapper = objectMapper;
    this.contentName = contentName;
    this.attributePrefix = attributePrefix;
    this.prettyPrint = prettyPrint;
    this.omitXmlDeclaration = omitXmlDeclaration;
  }

  public Document toXml(JsonNode jsonNode) {
    if ((jsonNode instanceof ObjectNode objectNode) && objectNode.size() == 1) {
      String rootName = objectNode.fieldNames().next();
      ElementXmlNode xmlNode = new ElementXmlNode(rootName);
      decorateElement(xmlNode, objectNode.get(rootName));
      return XmlUtilities.xmlStringToDocument(xmlNode.toXmlString());
    } else {
      throw new IllegalStateException(
          "The root of the json document has to an object node with 1 root element");
    }
  }

  public String toXmlPartString(Map jsonNode) {
    return jsonNode.entrySet().stream()
        .map(
            e -> {
              ElementXmlNode node = new ElementXmlNode(e.getKey());
              decorateElement(node, objectMapper.valueToTree(e.getValue()));
              return node.toXmlString();
            })
        .collect(Collectors.joining(""));
  }

  public String toXmlString(Map jsonNode) {
    return XmlUtilities.xmlDocumentToString(
        toXml(objectMapper.valueToTree(jsonNode)), omitXmlDeclaration, prettyPrint);
  }

  private void decorateElement(ElementXmlNode element, JsonNode jsonNode) {
    if (jsonNode instanceof TextNode textNode) {
      element.getValue().add(new TextXmlNode(textNode.textValue()));
    } else if (jsonNode instanceof BooleanNode booleanNode) {
      element.getValue().add(new TextXmlNode(Boolean.toString(booleanNode.booleanValue())));
    } else if (jsonNode instanceof NumericNode numericNode) {
      element.getValue().add(new TextXmlNode(String.valueOf(numericNode.numberValue())));
    } else if (jsonNode instanceof NullNode nullNode) {
      element.getValue().add(new TextXmlNode(nullNode.textValue()));
    } else if (jsonNode instanceof ObjectNode objectNode) {
      objectNode
          .properties()
          .forEach(
              e -> {
                if (e.getKey().equals(contentName)) {
                  if (e.getValue() instanceof TextNode textNode) {
                    element.getValue().add(new TextXmlNode(textNode.textValue()));
                  } else {
                    throw new IllegalStateException("Value has to be text value");
                  }
                } else if (e.getKey().startsWith(attributePrefix)) {
                  if (e.getValue() instanceof TextNode textNode) {
                    element.getAttributes().put(e.getKey().substring(1), textNode.textValue());
                  } else {
                    throw new IllegalStateException("Attributes have to have text values");
                  }
                } else {
                  if (e.getValue() instanceof ArrayNode arrayNode) {
                    arrayNode.forEach(
                        child -> {
                          ElementXmlNode childElement = new ElementXmlNode(e.getKey());
                          decorateElement(childElement, child);
                          element.getValue().add(childElement);
                        });
                  } else if (e.getValue() instanceof ObjectNode
                      || e.getValue() instanceof ValueNode) {
                    ElementXmlNode childElement = new ElementXmlNode(e.getKey());
                    decorateElement(childElement, e.getValue());
                    element.getValue().add(childElement);
                  } else {
                    throw new IllegalStateException(
                        "Unexpected node type " + e.getValue().getClass().getSimpleName());
                  }
                }
              });
    } else {
      throw new IllegalStateException(
          "Unexpected node type " + jsonNode.getClass().getSimpleName());
    }
  }

  abstract static class XmlNode {
    @Override
    public final String toString() {
      return toXmlString();
    }

    protected abstract String toXmlString();

    static class ElementXmlNode extends XmlNode {
      private final Map attributes = new HashMap<>();
      private final String elementName;
      private final List value = new ArrayList<>();

      public ElementXmlNode(String elementName) {
        this.elementName = elementName;
      }

      public String getElementName() {
        return elementName;
      }

      public Map getAttributes() {
        return attributes;
      }

      public List getValue() {
        return value;
      }

      @Override
      protected String toXmlString() {
        Map context = new HashMap<>();
        context.put("elementName", elementName);
        context.put("attributes", attributes);
        context.put("value", String.join("", value.stream().map(XmlNode::toXmlString).toList()));
        return XML_ELEMENT_TEMPLATE.execute(context);
      }
    }

    static class TextXmlNode extends XmlNode {
      private final String value;

      public TextXmlNode(String value) {
        this.value = value;
      }

      public String getValue() {
        return value;
      }

      @Override
      protected String toXmlString() {
        return value;
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy