Bug 6814: Fix (de)serialization of anyxml in JSON 91/47491/4
authorIgor Foltin <ifoltin@cisco.com>
Tue, 25 Oct 2016 11:10:23 +0000 (13:10 +0200)
committerRobert Varga <nite@hq.sk>
Thu, 3 Nov 2016 13:00:35 +0000 (13:00 +0000)
JSON parser can now deserialize anyxml nodes.
JSON serializer can now serialize anyxml nodes

Change-Id: I815afb5aac82618f27cd26d747d6637eb4e962f0
Signed-off-by: Igor Foltin <ifoltin@cisco.com>
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlSupportTest.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonStreamToNormalizedNodeTest.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java
yang/yang-data-codec-gson/src/test/resources/complexjson/anyxml-node-with-composite-value-in-container.json [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/resources/complexjson/anyxml-node-with-simple-value-in-container.json [new file with mode: 0644]

index 27aedad9e8cf6a19e255d7dbd498754568950853..2a1f8e1c990b259aee98fa0c1bc013ce4ed60ebf 100644 (file)
@@ -7,10 +7,18 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import static org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream.ANYXML_ARRAY_ELEMENT_ID;
+import static org.w3c.dom.Node.ELEMENT_NODE;
+import static org.w3c.dom.Node.TEXT_NODE;
+
 import com.google.common.base.Preconditions;
 import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
 import java.net.URI;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.RegEx;
+import javax.xml.transform.dom.DOMSource;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@@ -22,6 +30,8 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * This implementation will create JSON output as output stream.
@@ -36,6 +46,14 @@ public final class JSONNormalizedNodeStreamWriter implements NormalizedNodeStrea
      */
     private static final boolean DEFAULT_EMIT_EMPTY_CONTAINERS = true;
 
+    @RegEx
+    private static final String NUMBER_STRING = "-?\\d+(\\.\\d+)?";
+    private static final Pattern NUMBER_PATTERN = Pattern.compile(NUMBER_STRING);
+
+    @RegEx
+    private static final String NOT_DECIMAL_NUMBER_STRING = "-?\\d+";
+    private static final Pattern NOT_DECIMAL_NUMBER_PATTERN = Pattern.compile(NOT_DECIMAL_NUMBER_STRING);
+
     private final SchemaTracker tracker;
     private final JSONCodecFactory codecs;
     private final JsonWriter writer;
@@ -183,8 +201,8 @@ public final class JSONNormalizedNodeStreamWriter implements NormalizedNodeStrea
 
         context.emittingChild(codecs.getSchemaContext(), writer);
         context.writeChildJsonIdentifier(codecs.getSchemaContext(), writer, name.getNodeType());
-        // FIXME this kind of serialization is incorrect since the value for AnyXml is now a DOMSource
-        writer.value(String.valueOf(value));
+
+        writeAnyXmlValue((DOMSource) value);
     }
 
     @Override
@@ -208,6 +226,101 @@ public final class JSONNormalizedNodeStreamWriter implements NormalizedNodeStrea
         ((JSONCodec<Object>) codec).serializeToWriter(writer, value);
     }
 
+    private void writeAnyXmlValue(final DOMSource anyXmlValue) throws IOException {
+        final Node documentNode = anyXmlValue.getNode();
+        final Node firstChild = documentNode.getFirstChild();
+        if (ELEMENT_NODE == firstChild.getNodeType() && !ANYXML_ARRAY_ELEMENT_ID.equals(firstChild.getNodeName())) {
+            writer.beginObject();
+            traverseAnyXmlValue(documentNode);
+            writer.endObject();
+        } else {
+            traverseAnyXmlValue(documentNode);
+        }
+    }
+
+    private void traverseAnyXmlValue(final Node node) throws IOException {
+        final NodeList children = node.getChildNodes();
+        boolean inArray = false;
+
+        for (int i = 0, length = children.getLength(); i < length; i++) {
+            final Node childNode = children.item(i);
+            boolean inObject = false;
+
+            if (ELEMENT_NODE == childNode.getNodeType()) {
+                final Node firstChild = childNode.getFirstChild();
+                // beginning of an array
+                if (ANYXML_ARRAY_ELEMENT_ID.equals(childNode.getNodeName()) && !inArray) {
+                    writer.beginArray();
+                    inArray = true;
+                    // object at the beginning of the array
+                    if (isJsonObjectInArray(childNode, firstChild)) {
+                        writer.beginObject();
+                        inObject = true;
+                    }
+                    // object in the array
+                } else if (isJsonObjectInArray(childNode, firstChild)) {
+                    writer.beginObject();
+                    inObject = true;
+                    // object
+                } else if (isJsonObject(firstChild)) {
+                    writer.name(childNode.getNodeName());
+                    writer.beginObject();
+                    inObject = true;
+                    // name
+                } else if (!inArray){
+                    writer.name(childNode.getNodeName());
+                }
+            }
+
+            // text value, i.e. a number, string, boolean or null
+            if (TEXT_NODE == childNode.getNodeType()) {
+                final String childNodeText = childNode.getNodeValue();
+                final Matcher matcher = NUMBER_PATTERN.matcher(childNodeText);
+                if (matcher.matches()) {
+                    writer.value(parseNumber(childNodeText));
+                } else if ("true".equals(childNodeText) || "false".equals(childNodeText)) {
+                    writer.value(Boolean.parseBoolean(childNodeText));
+                } else if ("null".equals(childNodeText)) {
+                    writer.nullValue();
+                } else {
+                    writer.value(childNodeText);
+                }
+
+                return;
+            }
+
+            traverseAnyXmlValue(childNode);
+
+            if (inObject) {
+                writer.endObject();
+            }
+        }
+
+        if (inArray) {
+            writer.endArray();
+        }
+    }
+
+    // json numbers are 64 bit wide floating point numbers - in java terms it is either long or double
+    private static Number parseNumber(final String numberText) {
+        Matcher matcher = NOT_DECIMAL_NUMBER_PATTERN.matcher(numberText);
+        if (matcher.matches()) {
+            return Long.parseLong(numberText);
+        } else {
+            return Double.parseDouble(numberText);
+        }
+    }
+
+    private static boolean isJsonObject(final Node firstChild) {
+        return !ANYXML_ARRAY_ELEMENT_ID.equals(firstChild.getNodeName()) && TEXT_NODE != firstChild.getNodeType();
+    }
+
+    private static boolean isJsonObjectInArray(final Node node, final Node firstChild) {
+        return ANYXML_ARRAY_ELEMENT_ID.equals(node.getNodeName())
+                && !ANYXML_ARRAY_ELEMENT_ID.equals(firstChild.getNodeName())
+                && TEXT_NODE != firstChild.getNodeType();
+    }
+
     @Override
     public void flush() throws IOException {
         writer.flush();
index 90ade685d9fd28430de00975d07021c08bf34143..c398384c261fbdfadf9ce4376e21b82aa4fb9d40 100644 (file)
@@ -24,6 +24,8 @@ import java.util.Collections;
 import java.util.Deque;
 import java.util.HashSet;
 import java.util.Set;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.util.AbstractNodeDataWithSchema;
 import org.opendaylight.yangtools.yang.data.util.AnyXmlNodeDataWithSchema;
@@ -36,7 +38,6 @@ import org.opendaylight.yangtools.yang.data.util.ListNodeDataWithSchema;
 import org.opendaylight.yangtools.yang.data.util.ParserStreamUtils;
 import org.opendaylight.yangtools.yang.data.util.RpcAsContainer;
 import org.opendaylight.yangtools.yang.data.util.SimpleNodeDataWithSchema;
-import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -46,6 +47,9 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
 
 /**
  * This class parses JSON elements from a GSON JsonReader. It disallows multiple elements of the same name unlike the
@@ -53,6 +57,8 @@ import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode;
  */
 @Beta
 public final class JsonParserStream implements Closeable, Flushable {
+    static final String ANYXML_ARRAY_ELEMENT_ID = "array-element";
+
     private final Deque<URI> namespaces = new ArrayDeque<>();
     private final NormalizedNodeStreamWriter writer;
     private final JSONCodecFactory codecs;
@@ -111,15 +117,58 @@ public final class JsonParserStream implements Closeable, Flushable {
         }
     }
 
-    private void setValue(final AbstractNodeDataWithSchema parent, final String value) {
-        Preconditions.checkArgument(parent instanceof SimpleNodeDataWithSchema, "Node %s is not a simple type",
-                parent.getSchema().getQName());
-        final SimpleNodeDataWithSchema parentSimpleNode = (SimpleNodeDataWithSchema) parent;
-        Preconditions.checkArgument(parentSimpleNode.getValue() == null, "Node '%s' has already set its value to '%s'",
-                parentSimpleNode.getSchema().getQName(), parentSimpleNode.getValue());
+    private void traverseAnyXmlValue(final JsonReader in, final Document doc, final Element parentElement)
+            throws IOException {
+        switch (in.peek()) {
+            case STRING:
+            case NUMBER:
+                Text textNode = doc.createTextNode(in.nextString());
+                parentElement.appendChild(textNode);
+                break;
+            case BOOLEAN:
+                textNode = doc.createTextNode(Boolean.toString(in.nextBoolean()));
+                parentElement.appendChild(textNode);
+                break;
+            case NULL:
+                in.nextNull();
+                textNode = doc.createTextNode("null");
+                parentElement.appendChild(textNode);
+                break;
+            case BEGIN_ARRAY:
+                in.beginArray();
+                while (in.hasNext()) {
+                    final Element childElement = doc.createElement(ANYXML_ARRAY_ELEMENT_ID);
+                    parentElement.appendChild(childElement);
+                    traverseAnyXmlValue(in, doc, childElement);
+                }
+                in.endArray();
+                break;
+            case BEGIN_OBJECT:
+                in.beginObject();
+                while (in.hasNext()) {
+                    final Element childElement = doc.createElement(in.nextName());
+                    parentElement.appendChild(childElement);
+                    traverseAnyXmlValue(in, doc, childElement);
+                }
+                in.endObject();
+            case END_DOCUMENT:
+            case NAME:
+            case END_OBJECT:
+            case END_ARRAY:
+                break;
+        }
+    }
 
-        final Object translatedValue = translateValueByType(value, parentSimpleNode.getSchema());
-        parentSimpleNode.setValue(translatedValue);
+    private void readAnyXmlValue(final JsonReader in, final AnyXmlNodeDataWithSchema parent,
+            final String anyXmlObjectName) throws IOException {
+        final String anyXmlObjectNS = getCurrentNamespace().toString();
+        final Document doc = UntrustedXML.newDocumentBuilder().newDocument();
+        final Element rootElement = doc.createElementNS(anyXmlObjectNS, anyXmlObjectName);
+        doc.appendChild(rootElement);
+        traverseAnyXmlValue(in, doc, rootElement);
+
+        final DOMSource domSource = new DOMSource(doc.getDocumentElement());
+        parent.setValue(domSource);
     }
 
     public void read(final JsonReader in, AbstractNodeDataWithSchema parent) throws IOException {
@@ -182,13 +231,8 @@ public final class JsonParserStream implements Closeable, Flushable {
                 }
 
                 final AbstractNodeDataWithSchema newChild = ((CompositeNodeDataWithSchema) parent).addChild(childDataSchemaNodes);
-                /*
-                 * FIXME:anyxml data shouldn't be skipped but should be loaded somehow.
-                 * will be able to load anyxml which conforms to YANG data using these
-                 * parser, for other anyxml will be harder.
-                 */
                 if (newChild instanceof AnyXmlNodeDataWithSchema) {
-                    in.skipValue();
+                    readAnyXmlValue(in, (AnyXmlNodeDataWithSchema) newChild, jsonElementName);
                 } else {
                     read(in, newChild);
                 }
@@ -221,15 +265,18 @@ public final class JsonParserStream implements Closeable, Flushable {
         return newChild;
     }
 
+    private void setValue(final AbstractNodeDataWithSchema parent, final String value) {
+        Preconditions.checkArgument(parent instanceof SimpleNodeDataWithSchema, "Node %s is not a simple type",
+                parent.getSchema().getQName());
+        final SimpleNodeDataWithSchema parentSimpleNode = (SimpleNodeDataWithSchema) parent;
+        Preconditions.checkArgument(parentSimpleNode.getValue() == null, "Node '%s' has already set its value to '%s'",
+                parentSimpleNode.getSchema().getQName(), parentSimpleNode.getValue());
+
+        final Object translatedValue = translateValueByType(value, parentSimpleNode.getSchema());
+        parentSimpleNode.setValue(translatedValue);
+    }
+
     private Object translateValueByType(final String value, final DataSchemaNode node) {
-        if (node instanceof AnyXmlSchemaNode) {
-            /*
-             *  FIXME: Figure out some YANG extension dispatch, which will
-             *  reuse JSON parsing or XML parsing - anyxml is not well-defined in
-             * JSON.
-             */
-            return value;
-        }
         return codecs.codecFor(node).deserialize(value);
     }
 
diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlSupportTest.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlSupportTest.java
new file mode 100644 (file)
index 0000000..7fc8f04
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.loadModules;
+import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.loadTextFile;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.stream.JsonReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URISyntaxException;
+import javax.xml.transform.dom.DOMSource;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+public class AnyXmlSupportTest {
+
+    private static final QName CONT_1 = QName.create("ns:complex:json", "2014-08-11", "cont1");
+    private static final QName LF12_ANY = QName.create(CONT_1, "lf12-any");
+    private static final QName LF13_ANY = QName.create(CONT_1, "lf13-any");
+    private static final QName LF14_ANY = QName.create(CONT_1, "lf14-any");
+
+    private static SchemaContext schemaContext;
+
+    @BeforeClass
+    public static void setup() throws IOException, URISyntaxException, ReactorException {
+        schemaContext = loadModules("/complexjson/yang");
+    }
+
+    @Test
+    public void anyXmlNodeWithSimpleValueInContainer() throws IOException, URISyntaxException {
+        final String inputJson = loadTextFile("/complexjson/anyxml-node-with-simple-value-in-container.json");
+
+        // deserialization
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext);
+        jsonParser.parse(new JsonReader(new StringReader(inputJson)));
+        final NormalizedNode<?, ?> transformedInput = result.getResult();
+        assertNotNull(transformedInput);
+
+        // lf12-any check
+        final DOMSource Lf12AnyActualValue = getParsedAnyXmlValue(transformedInput, LF12_ANY);
+        final DOMSource Lf12AnyExpectedValue = createAnyXmlSimpleValue("ns:complex:json", "lf12-any", "100.5");
+        verifyTransformedAnyXmlNodeValue(Lf12AnyExpectedValue, Lf12AnyActualValue);
+
+        // lf13-any check
+        final DOMSource Lf13AnyActualValue = getParsedAnyXmlValue(transformedInput, LF13_ANY);
+        final DOMSource Lf13AnyExpectedValue = createAnyXmlSimpleValue("ns:complex:json", "lf13-any", "true");
+        verifyTransformedAnyXmlNodeValue(Lf13AnyExpectedValue, Lf13AnyActualValue);
+
+        // lf14-any check
+        final DOMSource Lf14AnyActualValue = getParsedAnyXmlValue(transformedInput, LF14_ANY);
+        final DOMSource Lf14AnyExpectedValue = createAnyXmlSimpleValue("ns:complex:json", "lf14-any", "null");
+        verifyTransformedAnyXmlNodeValue(Lf14AnyExpectedValue, Lf14AnyActualValue);
+
+        // serialization
+        final Writer writer = new StringWriter();
+        final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.
+                createExclusiveWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null,
+                        JsonWriterFactory.createJsonWriter(writer, 2));
+        final NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream);
+        nodeWriter.write(transformedInput);
+        nodeWriter.close();
+        final String serializationResult = writer.toString();
+
+        final JsonParser parser = new JsonParser();
+        final JsonElement expected = parser.parse(inputJson);
+        final JsonElement actual = parser.parse(serializationResult);
+        assertTrue(expected.equals(actual));
+    }
+
+    @Test
+    public void anyXmlNodeWithCompositeValueInContainer() throws IOException, URISyntaxException {
+        final String inputJson = loadTextFile("/complexjson/anyxml-node-with-composite-value-in-container.json");
+
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext);
+        jsonParser.parse(new JsonReader(new StringReader(inputJson)));
+        final NormalizedNode<?, ?> transformedInput = result.getResult();
+        assertNotNull(transformedInput);
+
+        // lf12-any check
+        final DOMSource Lf12AnyActualValue = getParsedAnyXmlValue(transformedInput, LF12_ANY);
+        final DOMSource Lf12AnyExpectedValue = createLf12AnyXmlCompositeValue("ns:complex:json", "lf12-any");
+        verifyTransformedAnyXmlNodeValue(Lf12AnyExpectedValue, Lf12AnyActualValue);
+
+        // lf13-any check
+        final DOMSource Lf13AnyActualValue = getParsedAnyXmlValue(transformedInput, LF13_ANY);
+        final DOMSource Lf13AnyExpectedValue = createLf13AnyXmlCompositeValue("ns:complex:json", "lf13-any");
+        verifyTransformedAnyXmlNodeValue(Lf13AnyExpectedValue, Lf13AnyActualValue);
+
+        // lf14-any check
+        final DOMSource Lf14AnyActualValue = getParsedAnyXmlValue(transformedInput, LF14_ANY);
+        final DOMSource Lf14AnyExpectedValue = createLf14AnyXmlCompositeValue("ns:complex:json", "lf14-any");
+        verifyTransformedAnyXmlNodeValue(Lf14AnyExpectedValue, Lf14AnyActualValue);
+
+        // serialization
+        final Writer writer = new StringWriter();
+        final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.
+                createExclusiveWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null,
+                        JsonWriterFactory.createJsonWriter(writer, 2));
+        final NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream);
+        nodeWriter.write(transformedInput);
+        nodeWriter.close();
+        final String serializationResult = writer.toString();
+
+        final JsonParser parser = new JsonParser();
+        final JsonElement expected = parser.parse(inputJson);
+        final JsonElement actual = parser.parse(serializationResult);
+        assertTrue(expected.equals(actual));
+    }
+
+    private static DOMSource getParsedAnyXmlValue(final NormalizedNode<?, ?> transformedInput, final QName anyxmlName) {
+        assertTrue(transformedInput instanceof ContainerNode);
+        final ContainerNode cont1 = (ContainerNode) transformedInput;
+        final DataContainerChild<? extends PathArgument, ?> child = cont1.getChild(new NodeIdentifier(anyxmlName)).get();
+        assertNotNull(child);
+        assertTrue(child instanceof AnyXmlNode);
+        final AnyXmlNode anyXmlNode = (AnyXmlNode) child;
+        return anyXmlNode.getValue();
+    }
+
+    private static void verifyTransformedAnyXmlNodeValue(final DOMSource expectedValue, final DOMSource actualValue) {
+        assertTrue(expectedValue.getNode().isEqualNode(actualValue.getNode()));
+    }
+
+    private static DOMSource createAnyXmlSimpleValue(final String ns, final String name, final String value) {
+        final Document doc = UntrustedXML.newDocumentBuilder().newDocument();
+        final Element rootElement = doc.createElementNS(ns, name);
+        doc.appendChild(rootElement);
+        final Text textNode = doc.createTextNode(value);
+        rootElement.appendChild(textNode);
+        return new DOMSource(doc.getDocumentElement());
+    }
+
+    private static DOMSource createLf12AnyXmlCompositeValue(final String ns, final String name) {
+        final Document doc = UntrustedXML.newDocumentBuilder().newDocument();
+        final Element rootElement = doc.createElementNS(ns, name);
+
+        final Element arrayElement1 = doc.createElement("array-element");
+        final Text arrayElement1Text = doc.createTextNode("true");
+        arrayElement1.appendChild(arrayElement1Text);
+
+        final Element arrayElement2 = doc.createElement("array-element");
+
+        final Element arrayElement2Baz = doc.createElement("baz");
+        final Element bazArrayElement1 = doc.createElement("array-element");
+        final Text bazArrayElement1Text = doc.createTextNode("120");
+        bazArrayElement1.appendChild(bazArrayElement1Text);
+        final Element bazArrayElement2 = doc.createElement("array-element");
+        final Text bazArrayElement2Text = doc.createTextNode("str-val");
+        bazArrayElement2.appendChild(bazArrayElement2Text);
+        final Element bazArrayElement3 = doc.createElement("array-element");
+        final Text bazArrayElement3Text = doc.createTextNode("false");
+        bazArrayElement3.appendChild(bazArrayElement3Text);
+
+        arrayElement2Baz.appendChild(bazArrayElement1);
+        arrayElement2Baz.appendChild(bazArrayElement2);
+        arrayElement2Baz.appendChild(bazArrayElement3);
+
+        arrayElement2.appendChild(arrayElement2Baz);
+
+        final Element arrayElement3 = doc.createElement("array-element");
+        final Element arrayElement3Foo = doc.createElement("foo");
+        final Text fooText = doc.createTextNode("null");
+        arrayElement3Foo.appendChild(fooText);
+        arrayElement3.appendChild(arrayElement3Foo);
+
+        rootElement.appendChild(arrayElement1);
+        rootElement.appendChild(arrayElement2);
+        rootElement.appendChild(arrayElement3);
+
+        doc.appendChild(rootElement);
+
+        return new DOMSource(doc.getDocumentElement());
+    }
+
+    private static DOMSource createLf13AnyXmlCompositeValue(final String ns, final String name) {
+        final Document doc = UntrustedXML.newDocumentBuilder().newDocument();
+        final Element rootElement = doc.createElementNS(ns, name);
+
+        final Element anyXmlArrayA = doc.createElement("anyxml-array-a");
+
+        final Element arrayAElement1 = doc.createElement("array-element");
+        final Element arrayAElement1Foo = doc.createElement("foo");
+        final Text fooText = doc.createTextNode("true");
+        arrayAElement1Foo.appendChild(fooText);
+        arrayAElement1.appendChild(arrayAElement1Foo);
+
+        final Element arrayAElement2 = doc.createElement("array-element");
+        final Text arrayAElement2Text = doc.createTextNode("10");
+        arrayAElement2.appendChild(arrayAElement2Text);
+
+        final Element arrayAElement3 = doc.createElement("array-element");
+        final Element arrayAElement3Bar = doc.createElement("bar");
+        final Text barText = doc.createTextNode("false");
+        arrayAElement3Bar.appendChild(barText);
+        arrayAElement3.appendChild(arrayAElement3Bar);
+
+        anyXmlArrayA.appendChild(arrayAElement1);
+        anyXmlArrayA.appendChild(arrayAElement2);
+        anyXmlArrayA.appendChild(arrayAElement3);
+
+        final Element anyXmlArrayB = doc.createElement("anyxml-array-b");
+
+        final Element arrayBElement1 = doc.createElement("array-element");
+        final Text arrayBElement1Text = doc.createTextNode("1");
+        arrayBElement1.appendChild(arrayBElement1Text);
+
+        final Element arrayBElement2 = doc.createElement("array-element");
+        final Text arrayBElement2Text = doc.createTextNode("2");
+        arrayBElement2.appendChild(arrayBElement2Text);
+
+        final Element arrayBElement3 = doc.createElement("array-element");
+
+        final Element arrayBElement3Element1 = doc.createElement("array-element");
+        final Text arrayBElement3Element1Text = doc.createTextNode("4");
+        arrayBElement3Element1.appendChild(arrayBElement3Element1Text);
+        final Element arrayBElement3Element2 = doc.createElement("array-element");
+        final Text arrayBElement3Element2Text = doc.createTextNode("5");
+        arrayBElement3Element2.appendChild(arrayBElement3Element2Text);
+
+        arrayBElement3.appendChild(arrayBElement3Element1);
+        arrayBElement3.appendChild(arrayBElement3Element2);
+
+        final Element arrayBElement4 = doc.createElement("array-element");
+        final Text arrayBElement4Text = doc.createTextNode("7");
+        arrayBElement4.appendChild(arrayBElement4Text);
+
+        anyXmlArrayB.appendChild(arrayBElement1);
+        anyXmlArrayB.appendChild(arrayBElement2);
+        anyXmlArrayB.appendChild(arrayBElement3);
+        anyXmlArrayB.appendChild(arrayBElement4);
+
+        rootElement.appendChild(anyXmlArrayA);
+        rootElement.appendChild(anyXmlArrayB);
+
+        doc.appendChild(rootElement);
+
+        return new DOMSource(doc.getDocumentElement());
+    }
+
+    private static DOMSource createLf14AnyXmlCompositeValue(final String ns, final String name) {
+        final Document doc = UntrustedXML.newDocumentBuilder().newDocument();
+        final Element rootElement = doc.createElementNS(ns, name);
+
+        final Element anyXmlObjectA = doc.createElement("anyxml-object-a");
+        final Element dataA1 = doc.createElement("data-a1");
+        final Text dataA1Text = doc.createTextNode("10");
+        dataA1.appendChild(dataA1Text);
+        final Element dataA2 = doc.createElement("data-a2");
+        final Text dataA2Text = doc.createTextNode("11");
+        dataA2.appendChild(dataA2Text);
+
+        anyXmlObjectA.appendChild(dataA1);
+        anyXmlObjectA.appendChild(dataA2);
+
+        final Element anyXmlObjectB = doc.createElement("anyxml-object-b");
+
+        final Element childObjectB1 = doc.createElement("child-object-b1");
+        final Element dataB1 = doc.createElement("data-b1");
+        final Text dataB1Text = doc.createTextNode("5.5");
+        dataB1.appendChild(dataB1Text);
+        childObjectB1.appendChild(dataB1);
+
+        final Element childObjectB2 = doc.createElement("child-object-b2");
+        final Element dataB2 = doc.createElement("data-b2");
+        final Text dataB2Text = doc.createTextNode("b2-val");
+        dataB2.appendChild(dataB2Text);
+        childObjectB2.appendChild(dataB2);
+
+        anyXmlObjectB.appendChild(childObjectB1);
+        anyXmlObjectB.appendChild(childObjectB2);
+
+        rootElement.appendChild(anyXmlObjectA);
+        rootElement.appendChild(anyXmlObjectB);
+
+        doc.appendChild(rootElement);
+
+        return new DOMSource(doc.getDocumentElement());
+    }
+}
index 25d8931540c9d979c6099f7293a4ea681b637a2c..96bb518cbd337e6a5e96afa04282cd6e38f0a5f4 100644 (file)
@@ -24,7 +24,6 @@ import java.io.IOException;
 import java.io.StringReader;
 import java.net.URISyntaxException;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -52,26 +51,6 @@ public class JsonStreamToNormalizedNodeTest {
         schemaContext = loadModules("/complexjson/yang");
     }
 
-    /**
-     * case when anyxml contains simple value will be implemented when anyxml normalized node reprezentation will be
-     * specified
-     */
-    @Ignore
-    @Test
-    public void anyXmlNodeWithSimpleValueInContainer() throws IOException, URISyntaxException {
-
-    }
-
-    /**
-     * case when anyxml contains complex xml will be implemented when anyxml normalized node reprezentation will be
-     * specified
-     */
-    @Ignore
-    @Test
-    public void anyXmlNodeWithCompositeValueInContainer() throws IOException, URISyntaxException {
-
-    }
-
     @Test
     public void leafNodeInContainer() throws IOException, URISyntaxException {
         final String inputJson = loadTextFile("/complexjson/leaf-node-in-container.json");
index b78ff441cd645448812633cbf42a0d850260da47..dd866c4b2fe9b54721cf959adbebc0abe32f317b 100644 (file)
@@ -28,7 +28,6 @@ import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.Iterator;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -63,26 +62,6 @@ public class NormalizedNodeToJsonStreamTest {
         schemaContext = loadModules("/complexjson/yang");
     }
 
-    /**
-     * case when anyxml contains simple value will be implemented when anyxml normalized node reprezentation will be
-     * specified
-     */
-    @Ignore
-    @Test
-    public void anyXmlNodeWithSimpleValueInContainer() throws IOException, URISyntaxException {
-
-    }
-
-    /**
-     * case when anyxml contains complex xml will be implemented when anyxml normalized node reprezentation will be
-     * specified
-     */
-    @Ignore
-    @Test
-    public void anyXmlNodeWithCompositeValueInContainer() throws IOException, URISyntaxException {
-
-    }
-
     @Test
     public void leafNodeInContainer() throws IOException, URISyntaxException {
         final Writer writer = new StringWriter();
diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/anyxml-node-with-composite-value-in-container.json b/yang/yang-data-codec-gson/src/test/resources/complexjson/anyxml-node-with-composite-value-in-container.json
new file mode 100644 (file)
index 0000000..1bb60c4
--- /dev/null
@@ -0,0 +1,27 @@
+{
+  "complexjson:cont1": {
+    "lf12-any": [true, {"baz": [120, "str-val", false]}, {"foo": null}],
+
+    "lf13-any": {
+      "anyxml-array-a": [{"foo": true}, 10, {"bar": false}],
+      "anyxml-array-b": [1, 2, [4, 5], 7]
+    },
+
+    "lf14-any": {
+      "anyxml-object-a": {
+        "data-a1": 10,
+        "data-a2": 11
+      },
+
+      "anyxml-object-b": {
+        "child-object-b1": {
+          "data-b1": 5.5
+        },
+
+        "child-object-b2": {
+          "data-b2": "b2-val"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/anyxml-node-with-simple-value-in-container.json b/yang/yang-data-codec-gson/src/test/resources/complexjson/anyxml-node-with-simple-value-in-container.json
new file mode 100644 (file)
index 0000000..930ba22
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "complexjson:cont1": {
+    "lf12-any": 100.5,
+    "lf13-any": true,
+    "lf14-any": null
+  }
+}
\ No newline at end of file