Java tutorial
/** * Copyright 2017 Open Source Osijek Community * * Licensed 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.blip.workflowengine.functions; import com.google.common.collect.ImmutableList; import net.sf.saxon.s9api.DocumentBuilder; import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.XPathCompiler; import net.sf.saxon.s9api.XPathSelector; import net.sf.saxon.s9api.XdmValue; import org.blip.workflowengine.transferobject.Attribute; import org.blip.workflowengine.transferobject.ImmutableAttribute; import org.blip.workflowengine.transferobject.ImmutableProperty; import org.blip.workflowengine.transferobject.ImmutableValue; import org.blip.workflowengine.transferobject.ModifiablePropertyNode; import org.blip.workflowengine.transferobject.Property; import org.blip.workflowengine.transferobject.PropertyNode; import org.blip.workflowengine.transferobject.Value; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.xml.sax.InputSource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.nio.charset.Charset; import java.time.Instant; import java.util.AbstractMap; import java.util.Base64; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; import javax.xml.transform.sax.SAXSource; import javax.xml.xpath.XPathException; /** * Created by root on 11.12.16.. */ public interface PropertyNodeXmlFunctions { default Function<Element, PropertyNode> xmlToPropertyNode() { return element -> { Objects.requireNonNull(element, "element is null"); final ModifiablePropertyNode node = ModifiablePropertyNode.create(); for (final Element element1 : element.getChildren()) { final Property property = xmlToProperty().apply(element1); node.add(property); } return node; }; } default Function<Element, Property> xmlToProperty() { return element -> { Objects.requireNonNull(element, "element is null"); final String name = element.getName(); final Collection<Attribute> collection = element.getAttributes().stream() .map(p -> ImmutableAttribute.of(p.getName(), p.getValue())).collect(Collectors.toList()); return ImmutableProperty.of(name, xmlToValue().apply(element.getChildren().get(0))) .withAttributes(collection); }; } default Function<Element, Value> xmlToValue() { return element -> { Objects.requireNonNull(element, "element is null"); final String name = element.getName(); if (name.contentEquals("null")) { return ImmutableValue.of(null); } else if (name.contentEquals("boolean")) { return ImmutableValue.of(Boolean.valueOf(element.getValue())); } else if (name.contentEquals("instant")) { return ImmutableValue.of(Instant.parse(element.getValue())); } else if (name.contentEquals(("byte-array"))) { final String base64Encoded = element.getValue(); final byte[] binary = Base64.getDecoder().decode(base64Encoded.getBytes(Charset.forName("UTF-8"))); return ImmutableValue.of(binary); } else if (name.contentEquals("string")) { return ImmutableValue.of(element.getValue()); } else if (name.contentEquals("byte")) { return ImmutableValue.of(Byte.valueOf(element.getValue())); } else if (name.contentEquals("short")) { return ImmutableValue.of(Short.valueOf(element.getValue())); } else if (name.contentEquals("integer")) { return ImmutableValue.of(Integer.valueOf(element.getValue())); } else if (name.contentEquals("long")) { return ImmutableValue.of(Long.valueOf(element.getValue())); } else if (name.contentEquals("float")) { return ImmutableValue.of(Float.valueOf(element.getValue())); } else if (name.contentEquals("double")) { return ImmutableValue.of(Double.valueOf(element.getValue())); } else if (name.contentEquals("collection")) { final ImmutableList.Builder<Object> objectBuilder = ImmutableList.builder(); for (final Element element1 : element.getChildren()) { if (element1.getName().contentEquals("entry")) { final List<Element> children = element1.getChildren(); if (children.size() == 2) { final Element keyElement = children.get(0); final Element valueElement = children.get(1); final Value key = xmlToValue().apply(keyElement); final Value value = xmlToValue().apply(valueElement); final Map.Entry entry = new AbstractMap.SimpleEntry(key.value(), value.value()); objectBuilder.add(entry); } } else { final Object rawValue = xmlToValue().apply(element1).value(); if (Objects.nonNull(rawValue)) { objectBuilder.add(rawValue); } } } return ImmutableValue.of(objectBuilder.build()); } else if (name.contentEquals("property-node")) { return ImmutableValue.of((xmlToPropertyNode().apply(element))); } else { throw new IllegalArgumentException( new XMLOutputter(Format.getPrettyFormat()).outputString(element)); } }; } default Function<Property, Element> propertyToXml() { return property -> { Objects.requireNonNull(property, "property is null"); final Element element = new Element(property.key()); for (final Attribute attribute : property.attributes()) { element.setAttribute(attribute.key(), attribute.value()); } element.addContent(valueToXml().apply(property.value())); return element; }; } default Function<PropertyNode, Element> propertyNodeToXml() { return propertyNode -> { Objects.requireNonNull(propertyNode, "propertyNode is null"); final Element element = new Element("property-node"); for (final Property property : propertyNode) { element.addContent(propertyToXml().apply(property)); } return element; }; } default Function<Value, Element> valueToXml() { return value -> { Objects.requireNonNull(value, "value is null"); if (value.isNull()) { return new Element("null"); } else if (value.isBoolean()) { return new Element("boolean").setText(value.asBoolean().toString()); } else if (value.isInstant()) { return new Element("instant").setText(value.asString()); } else if (value.isBinary()) { return new Element("byte-array").setText(value.asString()); } else if (value.isString()) { return new Element("string").setText(value.asString()); } else if (value.isByte()) { return new Element("byte").setText(value.asByte().toString()); } else if (value.isShort()) { return new Element("short").setText(value.asShort().toString()); } else if (value.isInteger()) { return new Element("integer").setText(value.asInteger().toString()); } else if (value.isLong()) { return new Element("long").setText(value.asLong().toString()); } else if (value.isFloat()) { return new Element("float").setText(value.asFloat().toString()); } else if (value.isDouble()) { return new Element("double").setText(value.asDouble().toString()); } else if (value.isCollection()) { final Element rootElement = new Element("collection"); for (final Object object : value.asCollection()) { if (object instanceof Map.Entry) { final Map.Entry entry = (Map.Entry) object; final Element entryElement = new Element("entry"); final Element keyElement = valueToXml().apply(ImmutableValue.of(entry.getKey())); final Element valueElement = valueToXml().apply(ImmutableValue.of(entry.getValue())); entryElement.addContent(keyElement).addContent(valueElement); rootElement.addContent(entryElement); } else { final Element element = valueToXml().apply(ImmutableValue.of(object)); rootElement.addContent(element); } } return rootElement; } else if (value.isPropertyNode()) { return propertyNodeToXml().apply(value.asPropertyNode()); } else { throw new IllegalArgumentException(value.toString()); } }; } default Element xpath(final PropertyNode propertyNode, final String expression) throws XPathException { Objects.requireNonNull(propertyNode, "propertyNode is null"); Objects.requireNonNull(expression, "XPath expression is null"); if (expression.trim().isEmpty()) { throw new IllegalArgumentException("XPath expression is empty"); } try { final Processor processor = new Processor(false); final DocumentBuilder builder = processor.newDocumentBuilder(); final XPathCompiler xpc = processor.newXPathCompiler(); final XPathSelector selector = xpc.compile(expression).load(); final Element element = propertyNodeToXml().apply(propertyNode); final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat()); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); xmlOutputter.output(element, baos); final Reader reader = new InputStreamReader(new ByteArrayInputStream(baos.toByteArray()), String.valueOf(Charset.forName("UTF-8"))); final InputSource inputSource = new InputSource(reader); inputSource.setEncoding(String.valueOf(Charset.forName("UTF-8"))); selector.setContextItem(builder.build(new SAXSource(inputSource))); final XdmValue xdmValue = selector.evaluate(); final String content = String.format("<%s>%s</%s>", "XPathResult", xdmValue.toString(), "XPathResult"); final Document doc = new SAXBuilder().build(new StringReader(content)); return doc.getRootElement(); } catch (Exception exception) { throw new XPathException(exception); } } }