Add binding support for anydata nodes 39/82239/5
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 24 May 2019 15:42:43 +0000 (17:42 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 28 May 2019 07:23:58 +0000 (09:23 +0200)
These nodes are following essentially the same blueprint as
anyxml nodes. Unlike anyxml nodes, we need specific implementation
support to allow streaming the nodes.

JIRA: MDSAL-438
Change-Id: I7ff081c58a9e5198762c67cbb908beec0bae144b
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
15 files changed:
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AnydataBindingStreamWriter.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingToNormalizedStreamWriter.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CachingNormalizedNodeSerializer.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamer.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerGenerator.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ForwardingBindingStreamEventWriter.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/OpaqueNodeCodecContext.java
binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AnydataLeafTest.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/AbstractOpaqueTest.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal437Test.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal438Test.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/test/resources/mdsal438.yang [new file with mode: 0644]
binding/mdsal-binding-test-model/src/main/yang/mdsal438.yang [new file with mode: 0644]

diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AnydataBindingStreamWriter.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AnydataBindingStreamWriter.java
new file mode 100644 (file)
index 0000000..47d2d65
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.impl;
+
+import java.io.IOException;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
+
+interface AnydataBindingStreamWriter extends BindingStreamEventWriter {
+
+    void anydataNode(String name, OpaqueObject<?> value) throws IOException;
+}
index 488892be817f570edcb1d3678923e80e0fc202a5..baf6772eb5f8d858338292441e95be8a4a61fd50 100644 (file)
@@ -60,6 +60,7 @@ import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
@@ -301,8 +302,8 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree
             final DataNodeContainer childSchema) {
         final Map<String, DataSchemaNode> getterToLeafSchema = new HashMap<>();
         for (final DataSchemaNode leaf : childSchema.getChildNodes()) {
-            // FIXME: support AnyDataSchemaNode, too
-            if (leaf instanceof TypedDataSchemaNode || leaf instanceof AnyXmlSchemaNode) {
+            if (leaf instanceof TypedDataSchemaNode || leaf instanceof AnyXmlSchemaNode
+                    || leaf instanceof AnyDataSchemaNode) {
                 getterToLeafSchema.put(BindingSchemaMapping.getGetterMethodName(leaf), leaf);
             }
         }
@@ -343,10 +344,11 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree
                     final Codec<Object, Object> codec = getCodec(valueType, leafListSchema.getType());
                     valueNode = new LeafSetNodeCodecContext(leafListSchema, codec, method.getName());
                 } else if (schema instanceof AnyXmlSchemaNode) {
-                    final Class<?> valueType = method.getReturnType();
-                    verify(OpaqueObject.class.isAssignableFrom(valueType), "Illegal value type %s", valueType);
                     valueNode = new OpaqueNodeCodecContext.AnyXml<>((AnyXmlSchemaNode) schema, method.getName(),
-                            valueType.asSubclass(OpaqueObject.class), loader);
+                            opaqueReturnType(method), loader);
+                } else if (schema instanceof AnyDataSchemaNode) {
+                    valueNode = new OpaqueNodeCodecContext.AnyData<>((AnyDataSchemaNode) schema, method.getName(),
+                            opaqueReturnType(method), loader);
                 } else {
                     verify(schema == null, "Unhandled schema %s for method %s", schema, method);
                     // We do not have schema for leaf, so we will ignore it (e.g. getClass).
@@ -428,4 +430,11 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree
     public BindingCodecTreeNode getSubtreeCodec(final SchemaPath path) {
         throw new UnsupportedOperationException("Not implemented yet.");
     }
+
+    @SuppressWarnings("rawtypes")
+    private static Class<? extends OpaqueObject> opaqueReturnType(final Method method) {
+        final Class<?> valueType = method.getReturnType();
+        verify(OpaqueObject.class.isAssignableFrom(valueType), "Illegal value type %s", valueType);
+        return valueType.asSubclass(OpaqueObject.class);
+    }
 }
index 129024f91b17c6b4f620bbb8fb36bb7846504ae2..2d6ad13e68287f5eb587d362ad181230c4080cf5 100644 (file)
@@ -19,20 +19,22 @@ import java.util.Map.Entry;
 import javax.xml.transform.dom.DOMSource;
 import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.AnydataExtension;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
-final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Delegator<NormalizedNodeStreamWriter> {
+final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWriter,
+        Delegator<NormalizedNodeStreamWriter> {
     private final Deque<NodeCodecContext> schema = new ArrayDeque<>();
     private final NormalizedNodeStreamWriter delegate;
     private final NodeCodecContext rootNodeSchema;
@@ -126,6 +128,18 @@ final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter,
         delegate.endNode();
     }
 
+    @Override
+    public void anydataNode(final String name, final OpaqueObject<?> value) throws IOException {
+        final AnydataExtension ext = delegate.getExtensions().getInstance(AnydataExtension.class);
+        if (ext != null) {
+            final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
+            if (ext.startAnydataNode(dom.getKey(), value.getValue().getObjectModel())) {
+                delegate.scalarValue(dom.getValue());
+                delegate.endNode();
+            }
+        }
+    }
+
     @Override
     public void anyxmlNode(final String name, final Object value) throws IOException {
         final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
index 4012de25382f54f7a14d364c2fab513f1f9cacad..21e64c484366a915e63672767764f8556d92b148 100644 (file)
@@ -48,7 +48,7 @@ final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEvent
     }
 
     @Override
-    protected BindingStreamEventWriter delegate() {
+    protected AnydataBindingStreamWriter delegate() {
         return delegate;
     }
 
index dd42c1e6e142ca716b7ccf2a9b55ae192cb207fd..b494d33962c094ee40f6c75d2e306699e9ccef64 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
 
 import com.google.common.annotations.Beta;
 import com.google.common.collect.ImmutableClassToInstanceMap;
@@ -30,6 +31,7 @@ import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
 import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,6 +49,14 @@ public abstract class DataObjectStreamer<T extends DataObject> implements DataOb
 
     }
 
+    protected static final void streamAnydata(final BindingStreamEventWriter writer, final String localName,
+            final Object value) throws IOException {
+        if (value != null && writer instanceof AnydataBindingStreamWriter) {
+            verify(value instanceof OpaqueObject, "Unexpected data %s", value);
+            ((AnydataBindingStreamWriter) writer).anydataNode(localName, (OpaqueObject<?>) value);
+        }
+    }
+
     protected static final void streamAnyxml(final BindingStreamEventWriter writer, final String localName,
             final Object value) throws IOException {
         if (value != null) {
index fa7b0c7443423b7178166d3561fa24b387b4066c..35bf0fc8e54e3e1f906209151fc599b61bee1f47 100644 (file)
@@ -63,6 +63,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
 import org.opendaylight.yangtools.yang.binding.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
@@ -122,6 +123,8 @@ final class DataObjectStreamerGenerator<T extends DataObjectStreamer<?>> impleme
         UNKNOWN_SIZE,
         invokeMethod(BindingStreamEventWriter.class, "startUnkeyedListItem", int.class));
 
+    private static final StackManipulation STREAM_ANYDATA = invokeMethod(DataObjectStreamer.class,
+        "streamAnydata", BindingStreamEventWriter.class, String.class, Object.class);
     private static final StackManipulation STREAM_ANYXML = invokeMethod(DataObjectStreamer.class,
         "streamAnyxml", BindingStreamEventWriter.class, String.class, Object.class);
     private static final StackManipulation STREAM_CHOICE = invokeMethod(DataObjectStreamer.class,
@@ -267,6 +270,9 @@ final class DataObjectStreamerGenerator<T extends DataObjectStreamer<?>> impleme
         if (childSchema instanceof ChoiceSchemaNode) {
             return choiceChildStream(getter);
         }
+        if (childSchema instanceof AnyDataSchemaNode) {
+            return qnameChildStream(STREAM_ANYDATA, getter, childSchema);
+        }
         if (childSchema instanceof AnyXmlSchemaNode) {
             return qnameChildStream(STREAM_ANYXML, getter, childSchema);
         }
index 16a2b330800e1a54976591d264a58b145a316fb4..660026810a01336c438291ab86498b71cad803bf 100644 (file)
@@ -9,16 +9,16 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import java.io.IOException;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 
 //FIXME: Consider moving this to yang.binding.util.* in Be
-abstract class ForwardingBindingStreamEventWriter implements BindingStreamEventWriter {
+abstract class ForwardingBindingStreamEventWriter implements AnydataBindingStreamWriter {
 
-    protected abstract BindingStreamEventWriter delegate();
+    protected abstract AnydataBindingStreamWriter delegate();
 
     @Override
     public void leafNode(final String localName, final Object value) throws IOException {
@@ -90,6 +90,11 @@ abstract class ForwardingBindingStreamEventWriter implements BindingStreamEventW
         delegate().startAugmentationNode(augmentationType);
     }
 
+    @Override
+    public void anydataNode(final String name, final OpaqueObject<?> value) throws IOException {
+        delegate().anydataNode(name, value);
+    }
+
     @Override
     public void anyxmlNode(final String name, final Object value) throws IOException {
         delegate().anyxmlNode(name, value);
index 77acf086e4e79953434ad38c8e43a8939db9cdd0..adbeb2ac8358b510154d037932f7bbcc8dc9055c 100644 (file)
@@ -28,9 +28,11 @@ import org.opendaylight.yangtools.concepts.Codec;
 import org.opendaylight.yangtools.yang.binding.OpaqueData;
 import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.AnydataNode;
 import org.opendaylight.yangtools.yang.data.api.schema.ForeignDataNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
@@ -49,6 +51,30 @@ abstract class OpaqueNodeCodecContext<T extends OpaqueObject<T>> extends ValueNo
             return Builders.anyXmlBuilder().withNodeIdentifier(getDomPathArgument())
                     .withValue((DOMSource) opaqueData.getData()).build();
         }
+
+        @Override
+        T deserialize(final ForeignDataNode<?, ?> foreignData) {
+            // Streaming cannot support anything but DOMSource-based AnyxmlNodes.
+            verify(foreignData instanceof AnyXmlNode, "Variable node %s not supported yet", foreignData);
+            return super.deserialize(foreignData);
+        }
+    }
+
+    static final class AnyData<T extends OpaqueObject<T>> extends OpaqueNodeCodecContext<T> {
+        AnyData(final AnyDataSchemaNode schema, final String getterName, final Class<T> bindingClass,
+                final CodecClassLoader loader) {
+            super(schema, getterName, bindingClass, loader);
+        }
+
+        @Override
+        AnydataNode<?> serializedData(final OpaqueData<?> opaqueData) {
+            return buildAnydata(opaqueData);
+        }
+
+        private <M> @NonNull AnydataNode<M> buildAnydata(final OpaqueData<M> opaqueData) {
+            return Builders.anydataBuilder(opaqueData.getObjectModel()).withNodeIdentifier(getDomPathArgument())
+                    .withValue(opaqueData.getData()).build();
+        }
     }
 
     private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(OpaqueObject.class,
@@ -93,10 +119,10 @@ abstract class OpaqueNodeCodecContext<T extends OpaqueObject<T>> extends ValueNo
     @Override
     public final T deserialize(final NormalizedNode<?, ?> data) {
         checkArgument(data instanceof ForeignDataNode, "Unexpected value %s", data);
-        final ForeignDataNode<?, ?> foreignData = (ForeignDataNode<?, ?>) data;
-        // Streaming cannot support anything but DOMSource-based AnyxmlNodes.
-        verify(foreignData instanceof AnyXmlNode, "Variable node %s not supported yet", foreignData);
+        return deserialize((ForeignDataNode<?, ?>) data);
+    }
 
+    T deserialize(final ForeignDataNode<?, ?> foreignData) {
         return bindingClass.cast(createBindingProxy(new ForeignOpaqueData<>(foreignData)));
     }
 
diff --git a/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AnydataLeafTest.java b/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AnydataLeafTest.java
new file mode 100644 (file)
index 0000000..8ad5fdc
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.test;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+
+import java.util.Map.Entry;
+import javax.xml.transform.dom.DOMSource;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.mdsal438.norev.Cont;
+import org.opendaylight.yang.gen.v1.mdsal438.norev.ContBuilder;
+import org.opendaylight.yang.gen.v1.mdsal438.norev.cont.ContAny;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.binding.AbstractOpaqueData;
+import org.opendaylight.yangtools.yang.binding.AbstractOpaqueObject;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.OpaqueData;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class AnydataLeafTest extends AbstractBindingCodecTest {
+    private static final NodeIdentifier CONT_NODE_ID = new NodeIdentifier(Cont.QNAME);
+
+    private DOMSource domSource;
+    private ContainerNode cont;
+
+    @Override
+    public void before() {
+        super.before();
+
+        final Document doc = UntrustedXML.newDocumentBuilder().newDocument();
+        final Element element = doc.createElement("foo");
+        domSource = new DOMSource(element);
+
+        cont = Builders.containerBuilder()
+                .withNodeIdentifier(CONT_NODE_ID)
+                .withChild(Builders.anydataBuilder(DOMSource.class)
+                    .withNodeIdentifier(new NodeIdentifier(ContAny.QNAME))
+                    .withValue(domSource)
+                    .build())
+                .build();
+    }
+
+    @Test
+    public void testAnydataToBinding() {
+        final Entry<InstanceIdentifier<?>, DataObject> entry = registry.fromNormalizedNode(
+            YangInstanceIdentifier.create(CONT_NODE_ID), cont);
+        assertEquals(InstanceIdentifier.create(Cont.class), entry.getKey());
+        final DataObject ldo = entry.getValue();
+        assertThat(ldo, instanceOf(Cont.class));
+
+        // So no... GrpAny should be null ..
+        final Cont contValue = (Cont) ldo;
+        assertNull(contValue.getGrpAny());
+
+        // ContAny is interesting
+        final ContAny anyCont = contValue.getContAny();
+        assertNotNull(anyCont);
+        assertEquals(ContAny.class, anyCont.implementedInterface());
+
+        final OpaqueData<?> value = anyCont.getValue();
+        assertNotNull(value);
+        assertEquals(DOMSource.class, value.getObjectModel());
+        assertSame(domSource, value.getData());
+
+        // Stable hashCode
+        final int hashOne = anyCont.hashCode();
+        final int hashTwo = anyCont.hashCode();
+        assertEquals(hashOne, hashTwo);
+
+        // Basic equality
+        assertNotEquals(anyCont, null);
+        assertEquals(anyCont, anyCont);
+        assertEquals(new FakeCont(), anyCont);
+        assertEquals(anyCont, new FakeCont());
+        assertNotEquals(anyCont, new TestNormalizedNodeCont());
+        assertNotEquals(new TestNormalizedNodeCont(), anyCont);
+    }
+
+    @Test
+    public void testAnydataFromBinding() {
+        final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry = registry.toNormalizedNode(
+            InstanceIdentifier.create(Cont.class), new ContBuilder().setContAny(new FakeCont()).build());
+        assertEquals(YangInstanceIdentifier.create(CONT_NODE_ID), entry.getKey());
+        assertEquals(cont, entry.getValue());
+    }
+
+    private final class FakeData extends AbstractOpaqueData<DOMSource> {
+        @Override
+        public Class<DOMSource> getObjectModel() {
+            return DOMSource.class;
+        }
+
+        @Override
+        public DOMSource getData() {
+            return domSource;
+        }
+    }
+
+    private abstract static class AbstractTestCont extends AbstractOpaqueObject<ContAny> implements ContAny {
+
+    }
+
+    private final class FakeCont extends AbstractTestCont {
+        @Override
+        public OpaqueData<?> getValue() {
+            return new FakeData();
+        }
+    }
+
+    private final class TestNormalizedNodeCont extends AbstractTestCont {
+        @Override
+        public OpaqueData<?> getValue() {
+            return new AbstractOpaqueData<NormalizedNode>() {
+
+                @Override
+                public Class<NormalizedNode> getObjectModel() {
+                    return NormalizedNode.class;
+                }
+
+                @Override
+                public NormalizedNode getData() {
+                    return cont;
+                }
+            };
+        }
+    }
+}
index 5304db608a7e401186d7d6ce146a402664292e96..c937a2fd54d2ceb8f37897b097d6a9603d726d31 100644 (file)
@@ -89,6 +89,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
@@ -1052,9 +1053,8 @@ abstract class AbstractTypeGenerator {
                 listToGenType(context, typeBuilder, baseInterface, (ListSchemaNode) node, inGrouping);
             } else if (node instanceof ChoiceSchemaNode) {
                 choiceToGeneratedType(context, typeBuilder, (ChoiceSchemaNode) node, inGrouping);
-            } else if (node instanceof AnyXmlSchemaNode) {
-                // FIXME: MDSAL-438: also cover AnyDataSchemaNode
-                opaqueToGeneratedType(context, typeBuilder, (AnyXmlSchemaNode) node);
+            } else if (node instanceof AnyXmlSchemaNode || node instanceof AnyDataSchemaNode) {
+                opaqueToGeneratedType(context, typeBuilder, node);
             } else {
                 LOG.debug("Unable to add schema node {} as method in {}: unsupported type of node.", node.getClass(),
                         typeBuilder.getFullyQualifiedName());
@@ -1096,17 +1096,17 @@ abstract class AbstractTypeGenerator {
     }
 
     private void opaqueToGeneratedType(final ModuleContext context, final GeneratedTypeBuilder parent,
-            final AnyXmlSchemaNode anyxmlNode) {
-        if (!anyxmlNode.isAddedByUses()) {
+            final DataSchemaNode anyNode) {
+        if (!anyNode.isAddedByUses()) {
             final GeneratedTypeBuilder anyxmlTypeBuilder = addRawInterfaceDefinition(
-                JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), anyxmlNode.getPath()),
-                BindingMapping.getClassName(anyxmlNode.getQName())), anyxmlNode);
+                JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), anyNode.getPath()),
+                BindingMapping.getClassName(anyNode.getQName())), anyNode);
             anyxmlTypeBuilder.addImplementsType(opaqueObject(anyxmlTypeBuilder)).addImplementsType(childOf(parent));
             defaultImplementedInterace(anyxmlTypeBuilder);
-            annotateDeprecatedIfNecessary(anyxmlNode.getStatus(), anyxmlTypeBuilder);
-            context.addChildNodeType(anyxmlNode, anyxmlTypeBuilder);
+            annotateDeprecatedIfNecessary(anyNode.getStatus(), anyxmlTypeBuilder);
+            context.addChildNodeType(anyNode, anyxmlTypeBuilder);
 
-            constructGetter(parent, anyxmlTypeBuilder.build(), anyxmlNode);
+            constructGetter(parent, anyxmlTypeBuilder.build(), anyNode);
         }
     }
 
diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/AbstractOpaqueTest.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/AbstractOpaqueTest.java
new file mode 100644 (file)
index 0000000..2619919
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.generator.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
+
+abstract class AbstractOpaqueTest {
+
+    static void assertOpaqueNode(final List<Type> types, final String ns, final String pkg, final String name) {
+        final JavaTypeName typeName = JavaTypeName.create("org.opendaylight.yang.gen.v1." + ns + ".norev" + pkg, name);
+        final Optional<Type> optType = types.stream().filter(t -> typeName.equals(t.getIdentifier())).findFirst();
+        assertTrue(optType.isPresent());
+        final Type type = optType.get();
+        assertTrue(type instanceof GeneratedType);
+        final GeneratedType genType = (GeneratedType) type;
+        final Iterator<Type> it = genType.getImplements().iterator();
+        final Type first = it.next();
+        assertTrue(first instanceof ParameterizedType);
+        assertEquals(JavaTypeName.create(OpaqueObject.class), ((ParameterizedType) first).getRawType().getIdentifier());
+
+        final Type second = it.next();
+        assertTrue(second instanceof ParameterizedType);
+        assertEquals(JavaTypeName.create(ChildOf.class), ((ParameterizedType) second).getRawType().getIdentifier());
+
+        assertFalse(it.hasNext());
+    }
+}
index 98963cb9ff58bb7d17344d69d4249a9d74cd04df..71650f89a74bb7401dbbbe53f5e8620099b2fd38 100644 (file)
@@ -8,24 +8,15 @@
 package org.opendaylight.mdsal.binding.generator.impl;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
-import java.util.Iterator;
 import java.util.List;
-import java.util.Optional;
 import org.junit.Test;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
-import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
 import org.opendaylight.mdsal.binding.model.api.Type;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
-import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
-public class Mdsal437Test {
+public class Mdsal437Test extends AbstractOpaqueTest {
 
     @Test
     public void generateAnyxmlTest() {
@@ -35,28 +26,8 @@ public class Mdsal437Test {
         assertNotNull(types);
         assertEquals(7, types.size());
 
-        assertXmlNode(types, "", "Any");
-        assertXmlNode(types, ".cont", "Cont");
-        assertXmlNode(types, ".grp", "Grp");
-
-    }
-
-    private static void assertXmlNode(final List<Type> types, final String pkg, final String name) {
-        final JavaTypeName typeName = JavaTypeName.create("org.opendaylight.yang.gen.v1.mdsal437.norev" + pkg, name);
-        final Optional<Type> optType = types.stream().filter(t -> typeName.equals(t.getIdentifier())).findFirst();
-        assertTrue(optType.isPresent());
-        final Type type = optType.get();
-        assertTrue(type instanceof GeneratedType);
-        final GeneratedType genType = (GeneratedType) type;
-        final Iterator<Type> it = genType.getImplements().iterator();
-        final Type first = it.next();
-        assertTrue(first instanceof ParameterizedType);
-        assertEquals(JavaTypeName.create(OpaqueObject.class), ((ParameterizedType) first).getRawType().getIdentifier());
-
-        final Type second = it.next();
-        assertTrue(second instanceof ParameterizedType);
-        assertEquals(JavaTypeName.create(ChildOf.class), ((ParameterizedType) second).getRawType().getIdentifier());
-
-        assertFalse(it.hasNext());
+        assertOpaqueNode(types, "mdsal437", "", "Any");
+        assertOpaqueNode(types, "mdsal437", ".cont", "Cont");
+        assertOpaqueNode(types, "mdsal437", ".grp", "Grp");
     }
 }
diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal438Test.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal438Test.java
new file mode 100644 (file)
index 0000000..a5138cb
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.generator.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class Mdsal438Test extends AbstractOpaqueTest {
+
+    @Test
+    public void generateAnydataTest() {
+        final SchemaContext context = YangParserTestUtils.parseYangResource("/mdsal438.yang");
+
+        final List<Type> types = new BindingGeneratorImpl().generateTypes(context);
+        assertNotNull(types);
+        assertEquals(7, types.size());
+
+        assertOpaqueNode(types, "mdsal438", "", "Any");
+        assertOpaqueNode(types, "mdsal438", ".cont", "Cont");
+        assertOpaqueNode(types, "mdsal438", ".grp", "Grp");
+    }
+}
diff --git a/binding/mdsal-binding-generator-impl/src/test/resources/mdsal438.yang b/binding/mdsal-binding-generator-impl/src/test/resources/mdsal438.yang
new file mode 100644 (file)
index 0000000..04136b9
--- /dev/null
@@ -0,0 +1,22 @@
+module mdsal438 {
+    yang-version 1.1;
+    prefix mdsal438;
+    namespace mdsal438;
+
+    grouping grp {
+        anydata grp;
+    }
+
+    container cont {
+        anydata cont;
+
+        uses grp;
+    }
+
+    list lst {
+        uses grp;
+    }
+
+    anydata any;
+}
+
diff --git a/binding/mdsal-binding-test-model/src/main/yang/mdsal438.yang b/binding/mdsal-binding-test-model/src/main/yang/mdsal438.yang
new file mode 100644 (file)
index 0000000..472b525
--- /dev/null
@@ -0,0 +1,22 @@
+module mdsal438 {
+    yang-version 1.1;
+    prefix mdsal438;
+    namespace mdsal438;
+
+    grouping grp {
+        anydata grp-any;
+    }
+
+    container cont {
+        anydata cont-any;
+
+        uses grp;
+    }
+
+    list lst {
+        uses grp;
+    }
+
+    anydata any;
+}
+