Add YangInstanceIdentifierWriter 50/99550/14
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 1 Feb 2022 17:14:32 +0000 (18:14 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 10 Mar 2022 18:11:01 +0000 (19:11 +0100)
Add a utility that allows us to emit a number of enter events
into a NormalizedNodeStreamWriter, so we dont have to create
the whole normalized node structure prior to writing into the
stream.

This allows us to ditch InstanceIdTo*Nodes classes, as the creation
of NormalizedNode structure can easily be performed through streaming
events.

JIRA: YANGTOOLS-1392
Change-Id: Iea17a27559573d523cc17683e56b41faafa54f31
Signed-off-by: Tomas Cere <tomas.cere@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
data/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriter.java [new file with mode: 0644]
data/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriterTest.java [new file with mode: 0644]
data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNodes.java
data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToCompositeNodes.java [deleted file]
data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToNodes.java [deleted file]
data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToSimpleNodes.java [deleted file]

diff --git a/data/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriter.java b/data/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriter.java
new file mode 100644 (file)
index 0000000..37c0b03
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2022 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.yangtools.yang.data.api.schema.stream;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.List;
+import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.util.ImmutableOffsetMap;
+import org.opendaylight.yangtools.yang.common.QName;
+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.NormalizedAnydata;
+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.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ * Utility for emitting a {@link YangInstanceIdentifier} into a {@link NormalizedNodeStreamWriter} as a set of
+ * {@code startXXXNode} events. An example of usage would be something along the lines of:
+ * <pre>
+ *   <code>
+ *       YangModelContext
+ *       YangInstanceIdentifier id;
+ *       var result = new NormalizedNodeResult();
+ *       try (var writer = ImmutableNormalizedNodeStreamWriter.from(result)) {
+ *           try (var iidWriter = YangInstanceIdentifierWriter.open(writer, ctx, id)) {
+ *               // Here the state of 'writer' reflects the nodes in 'id'
+ *           }
+ *           // Here the writer is back to its initial state
+ *       }
+ *
+ *       // NormalizedNode result, including the structure created from YangInstanceIdentifier
+ *       var node = result.getResult();
+ *   </code>
+ * </pre>
+ */
+public final class YangInstanceIdentifierWriter implements AutoCloseable {
+    private NormalizedNodeStreamWriter writer;
+    private final int endNodeCount;
+
+    private YangInstanceIdentifierWriter(final NormalizedNodeStreamWriter writer, final int endNodeCount) {
+        this.writer = requireNonNull(writer);
+        this.endNodeCount = endNodeCount;
+    }
+
+    /**
+     * Open a writer, emitting events in target {@link NormalizedNodeStreamWriter}.
+     *
+     * @param writer Writer to enter
+     * @param root Root container
+     * @param path Path to enter
+     * @return A writer instance
+     * @throws IOException if the path cannot be entered
+     */
+    public static @NonNull YangInstanceIdentifierWriter open(final NormalizedNodeStreamWriter writer,
+            final DataNodeContainer root, final YangInstanceIdentifier path) throws IOException {
+        final var it = path.getPathArguments().iterator();
+        if (!it.hasNext()) {
+            return new YangInstanceIdentifierWriter(writer, 0);
+        }
+
+        // State tracking
+        int endNodes = 0;
+        Object parent = root;
+        boolean reuse = false;
+        boolean terminal = false;
+
+        do {
+            if (terminal) {
+                throw new IOException(parent + " is a terminal node, cannot resolve " + ImmutableList.copyOf(it));
+            }
+
+            final var arg = it.next();
+            if (arg instanceof AugmentationIdentifier) {
+                if (!(parent instanceof AugmentationTarget)) {
+                    throw new IOException(parent + " does not support augmentations, cannot resolve" + arg);
+                }
+                if (reuse) {
+                    throw new IOException(parent + " is expecting a nested item, cannot resolve " + arg);
+                }
+
+                final var augId = (AugmentationIdentifier) arg;
+                parent = enterAugmentation((AugmentationTarget) parent, augId);
+                writer.startAugmentationNode(augId);
+            } else if (arg instanceof NodeWithValue) {
+                if (!(parent instanceof LeafListSchemaNode)) {
+                    throw new IOException(parent + " does not support leaf-list entry " + arg);
+                }
+                if (!reuse) {
+                    throw new IOException(parent + " is already at its entry, cannot enter " + arg);
+                }
+
+                reuse = false;
+                terminal = true;
+                writer.startLeafSetEntryNode((NodeWithValue<?>) arg);
+            } else if (arg instanceof NodeIdentifierWithPredicates) {
+                if (!(parent instanceof ListSchemaNode)) {
+                    throw new IOException(parent + " does not support map entry " + arg);
+                }
+                if (!reuse) {
+                    throw new IOException(parent + " is already at its entry, cannot enter " + arg);
+                }
+
+                final var nodeId = (NodeIdentifierWithPredicates) arg;
+                final var list = (ListSchemaNode) parent;
+                if (!list.getQName().equals(nodeId.getNodeType())) {
+                    throw new IOException(parent + " expects a matching map entry, cannot enter " + arg);
+                }
+
+                final var key = list.getKeyDefinition();
+                if (key.isEmpty()) {
+                    throw new IOException(parent + " does not expect map entry " + arg);
+                }
+                if (key.size() != nodeId.size()) {
+                    throw new IOException(parent + " expects " + key.size() + " predicates, cannot use " + arg);
+                }
+
+                reuse = false;
+                writer.startMapEntryNode(normalizePredicates(nodeId, key), 1);
+            } else if (arg instanceof NodeIdentifier) {
+                final var nodeId = (NodeIdentifier) arg;
+
+                if (reuse) {
+                    if (!(parent instanceof ListSchemaNode)) {
+                        throw new IOException(parent + " expects an identifiable entry, cannot enter " + arg);
+                    }
+
+                    final var list = (ListSchemaNode) parent;
+                    if (!list.getKeyDefinition().isEmpty()) {
+                        throw new IOException(parent + " expects a map entry, cannot enter " + arg);
+                    }
+                    if (!list.getQName().equals(nodeId.getNodeType())) {
+                        throw new IOException(parent + " expects a matching entry, cannot enter " + arg);
+                    }
+
+                    reuse = false;
+                    writer.startUnkeyedListItem(nodeId, 1);
+                    endNodes++;
+                    continue;
+                }
+
+                final DataSchemaNode child;
+                if (parent instanceof DataNodeContainer) {
+                    child = ((DataNodeContainer) parent).dataChildByName(nodeId.getNodeType());
+                } else if (parent instanceof ChoiceSchemaNode) {
+                    child = ((ChoiceSchemaNode) parent).findDataSchemaChild(nodeId.getNodeType()).orElse(null);
+                } else {
+                    throw new IOException("Unhandled parent " + parent + " when looking up " + arg);
+                }
+
+                if (child == null) {
+                    throw new IOException("Failed to find child " + arg + " in parent " + parent);
+                }
+
+                // FIXME: check & repair augmentations (brr!)
+
+                if (child instanceof ContainerLike) {
+                    parent = child;
+                    writer.startContainerNode(nodeId, 1);
+                } else if (child instanceof ListSchemaNode) {
+                    parent = child;
+                    reuse = true;
+                    final var list = (ListSchemaNode) child;
+                    if (list.getKeyDefinition().isEmpty()) {
+                        writer.startUnkeyedList(nodeId, 1);
+                    } else if (list.isUserOrdered()) {
+                        writer.startOrderedMapNode(nodeId, 1);
+                    } else {
+                        writer.startMapNode(nodeId, 1);
+                    }
+                } else if (child instanceof LeafSchemaNode) {
+                    parent = child;
+                    terminal = true;
+                    writer.startLeafNode(nodeId);
+                } else if (child instanceof ChoiceSchemaNode) {
+                    parent = child;
+                    writer.startChoiceNode(nodeId, 1);
+                } else if (child instanceof LeafListSchemaNode) {
+                    parent = child;
+                    reuse = true;
+                    if (((LeafListSchemaNode) child).isUserOrdered()) {
+                        writer.startOrderedLeafSet(nodeId, 1);
+                    } else {
+                        writer.startLeafSet(nodeId, 1);
+                    }
+                } else if (child instanceof AnydataSchemaNode) {
+                    parent = child;
+                    terminal = true;
+                    writer.startAnydataNode(nodeId, NormalizedAnydata.class);
+                } else if (child instanceof AnyxmlSchemaNode) {
+                    parent = child;
+                    terminal = true;
+                    writer.startAnyxmlNode(nodeId, DOMSource.class);
+                } else {
+                    throw new IOException("Unhandled child " + child);
+                }
+            } else {
+                throw new IOException("Unhandled argument " + arg);
+            }
+
+            endNodes++;
+        } while (it.hasNext());
+
+        return new YangInstanceIdentifierWriter(writer, endNodes);
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (writer != null) {
+            for (int i = 0; i < endNodeCount; ++i) {
+                writer.endNode();
+            }
+            writer = null;
+        }
+    }
+
+    private static NodeIdentifierWithPredicates normalizePredicates(final NodeIdentifierWithPredicates input,
+            final List<QName> key) throws IOException {
+        if (Iterables.elementsEqual(input.keySet(), key)) {
+            return input;
+        }
+
+        final var builder = ImmutableMap.<QName, Object>builderWithExpectedSize(key.size());
+        for (var qname : key) {
+            final var value = input.getValue(qname);
+            if (value == null) {
+                throw new IOException("Cannot normalize " + input + " to " + key + ", missing value for " + qname);
+            }
+            builder.put(qname, value);
+        }
+
+        return NodeIdentifierWithPredicates.of(input.getNodeType(), ImmutableOffsetMap.orderedCopyOf(builder.build()));
+    }
+
+    private static AugmentationSchemaNode enterAugmentation(final AugmentationTarget target,
+            final AugmentationIdentifier id) throws IOException {
+        for (var augment : target.getAvailableAugmentations()) {
+            if (id.equals(augmentationIdentifierFrom(augment))) {
+                return augment;
+            }
+        }
+        throw new IOException("Cannot find augmentation " + id + " in " + target);
+    }
+
+    // FIXME: duplicate of data.util.DataSchemaContextNode.augmentationIdentifierFrom()
+    static @NonNull AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode schema) {
+        return new AugmentationIdentifier(
+            schema.getChildNodes().stream().map(DataSchemaNode::getQName).collect(ImmutableSet.toImmutableSet()));
+    }
+}
diff --git a/data/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriterTest.java b/data/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriterTest.java
new file mode 100644 (file)
index 0000000..ae7371a
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2022 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.yangtools.yang.data.api.schema.stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opendaylight.yangtools.yang.common.QName;
+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.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+@ExtendWith(MockitoExtension.class)
+public class YangInstanceIdentifierWriterTest {
+    @Test
+    public void testYangInstanceIdentifierWriter() throws IOException {
+        final FormattingNormalizedNodeStreamWriter streamWriter = new FormattingNormalizedNodeStreamWriter();
+
+        final DataNodeContainer root = mock(DataNodeContainer.class);
+
+        final ContainerLike containerSchema1 = mock(ContainerLike.class);
+        final ContainerLike containerSchema2 = mock(ContainerLike.class);
+        final ContainerLike containerSchema3 = mock(ContainerLike.class);
+
+        doReturn(containerSchema1).when(root).dataChildByName(any());
+        doReturn(containerSchema2).when(containerSchema1).dataChildByName(any());
+        doReturn(containerSchema3).when(containerSchema2).dataChildByName(any());
+
+        final YangInstanceIdentifier path = YangInstanceIdentifier.builder()
+            .node(QName.create("test", "container-1"))
+            .node(QName.create("test", "container-2"))
+            .node(QName.create("test", "container-3"))
+            .build();
+
+        try (var iidWriter = YangInstanceIdentifierWriter.open(streamWriter, root, path)) {
+            try (var nnWriter = new NormalizedNodeWriter(streamWriter)) {
+                nnWriter.write(mockedPayload());
+            }
+        }
+
+        assertEquals("(test)container-1(container)\n"
+            + "  (test)container-2(container)\n"
+            + "    (test)container-3(container)\n"
+            + "      (test)payload-container(container)\n"
+            + "        (test)payload-leaf(leaf)\n"
+            + "          (String)=leaf-value\n"
+            + "        (end)\n"
+            + "      (end)\n"
+            + "    (end)\n"
+            + "  (end)\n"
+            + "(end)\n", streamWriter.result());
+    }
+
+    @Test
+    public void testAugmentationIdentifier() throws IOException {
+        final FormattingNormalizedNodeStreamWriter streamWriter = new FormattingNormalizedNodeStreamWriter();
+
+        final ContainerLike root = mock(ContainerLike.class);
+        final QName augmented = QName.create("augment-namespace", "augmented-container");
+        final QName container2Qname = QName.create("augment-namespace", "container-2");
+
+        final ContainerLike containerSchema1 = mock(ContainerLike.class);
+        final AugmentationSchemaNode augmentationSchema = mock(AugmentationSchemaNode.class);
+        final ContainerLike augmentedContainerSchema = mock(ContainerLike.class);
+        final ContainerLike containerSchema2 = mock(ContainerLike.class);
+
+        doReturn(containerSchema1).when(root).dataChildByName(any());
+
+        doReturn(Set.of(augmentationSchema)).when(containerSchema1).getAvailableAugmentations();
+        doReturn(augmentedContainerSchema).when(augmentationSchema).dataChildByName(augmented);
+
+        doReturn(Set.of(augmentedContainerSchema)).when(augmentationSchema).getChildNodes();
+        doReturn(augmented).when(augmentedContainerSchema).getQName();
+
+        doReturn(containerSchema2).when(augmentedContainerSchema).dataChildByName(any());
+
+        final YangInstanceIdentifier path = YangInstanceIdentifier.builder()
+            .node(QName.create("test", "container-1"))
+            .node(AugmentationIdentifier.create(Set.of(augmented)))
+            .node(augmented)
+            .node(container2Qname)
+            .build();
+
+        try (var iidWriter = YangInstanceIdentifierWriter.open(streamWriter, root, path)) {
+            try (var nnWriter = new NormalizedNodeWriter(streamWriter)) {
+                nnWriter.write(mockedPayload());
+            }
+        }
+
+        assertEquals("(test)container-1(container)\n"
+            + "  AugmentationIdentifier{childNames=[(augment-namespace)augmented-container]}(augmentation)\n"
+            + "    (augment-namespace)augmented-container(container)\n"
+            + "      (augment-namespace)container-2(container)\n"
+            + "        (test)payload-container(container)\n"
+            + "          (test)payload-leaf(leaf)\n"
+            + "            (String)=leaf-value\n"
+            + "          (end)\n"
+            + "        (end)\n"
+            + "      (end)\n"
+            + "    (end)\n"
+            + "  (end)\n"
+            + "(end)\n", streamWriter.result());
+    }
+
+    @Test
+    public void testMapIdentifier() throws IOException {
+        final FormattingNormalizedNodeStreamWriter streamWriter = new FormattingNormalizedNodeStreamWriter();
+
+        final ContainerLike root = mock(ContainerLike.class);
+        final ListSchemaNode listSchemaNode = mock(ListSchemaNode.class);
+
+        final MapEntryNode listEntry = mock(MapEntryNode.class);
+
+        final ContainerLike containerSchema1 = mock(ContainerLike.class);
+        final QName container1Qname = QName.create("test", "container-1");
+        final QName list1KeyQname = QName.create("test", "list-1-key");
+        final QName listQname = QName.create("test", "list-1");
+
+        doReturn(listQname).when(listSchemaNode).getQName();
+        doReturn(listSchemaNode).when(root).dataChildByName(any());
+        doReturn(List.of(list1KeyQname)).when(listSchemaNode).getKeyDefinition();
+        doReturn(containerSchema1).when(listSchemaNode).dataChildByName(container1Qname);
+        doReturn("test-list-entry").when(listEntry).toString();
+
+        final YangInstanceIdentifier path = YangInstanceIdentifier.builder()
+            .node(listQname)
+            .nodeWithKey(listQname,list1KeyQname, listEntry)
+            .node(container1Qname)
+            .build();
+
+        try (var iidWriter = YangInstanceIdentifierWriter.open(streamWriter, root, path)) {
+            try (var nnWriter = new NormalizedNodeWriter(streamWriter)) {
+                nnWriter.write(mockedPayload());
+            }
+        }
+
+        assertEquals("(test)list-1(key)\n"
+            + "  (test)list-1[{(test)list-1-key=test-list-entry}][](key)\n"
+            + "    (test)container-1(container)\n"
+            + "      (test)payload-container(container)\n"
+            + "        (test)payload-leaf(leaf)\n"
+            + "          (String)=leaf-value\n"
+            + "        (end)\n"
+            + "      (end)\n"
+            + "    (end)\n"
+            + "  (end)\n"
+            + "(end)\n", streamWriter.result());
+    }
+
+    @Test
+    public void testChoiceIdentifier() throws IOException {
+        final FormattingNormalizedNodeStreamWriter streamWriter = new FormattingNormalizedNodeStreamWriter();
+        final ContainerLike root = mock(ContainerLike.class);
+        final ChoiceSchemaNode choiceSchemaNode = mock(ChoiceSchemaNode.class);
+        final CaseSchemaNode caseSchemaNode = mock(CaseSchemaNode.class);
+        final ContainerLike caseContainer = mock(ContainerLike.class);
+
+        final QName choiceQname = QName.create("test", "choice-node");
+        final QName caseQname = QName.create("test", "container-in-case");
+
+        doReturn(choiceSchemaNode).when(root).dataChildByName(choiceQname);
+        doReturn(Set.of(caseSchemaNode)).when(choiceSchemaNode).getCases();
+        doCallRealMethod().when(choiceSchemaNode).findDataSchemaChild(any());
+        doReturn(Optional.of(caseContainer)).when(caseSchemaNode).findDataChildByName(any());
+
+        final YangInstanceIdentifier path = YangInstanceIdentifier.builder()
+            .node(choiceQname)
+            .node(caseQname)
+            .build();
+
+        try (var iidWriter = YangInstanceIdentifierWriter.open(streamWriter, root, path)) {
+            try (var nnWriter = new NormalizedNodeWriter(streamWriter)) {
+                nnWriter.write(mockedPayload());
+            }
+        }
+
+        assertEquals("(test)choice-node(choice)\n"
+            + "  (test)container-in-case(container)\n"
+            + "    (test)payload-container(container)\n"
+            + "      (test)payload-leaf(leaf)\n"
+            + "        (String)=leaf-value\n"
+            + "      (end)\n"
+            + "    (end)\n"
+            + "  (end)\n"
+            + "(end)\n", streamWriter.result());
+    }
+
+    @Test
+    public void testLeafSetIdentifier() throws IOException {
+        final FormattingNormalizedNodeStreamWriter streamWriter = new FormattingNormalizedNodeStreamWriter();
+
+        final ContainerLike root = mock(ContainerLike.class);
+        final LeafListSchemaNode leafSetSchema = mock(LeafListSchemaNode.class);
+
+        doReturn(leafSetSchema).when(root).dataChildByName(any());
+
+        final YangInstanceIdentifier path = YangInstanceIdentifier.builder()
+            .node(QName.create("test", "list-list"))
+            .build();
+
+        try (var iidWriter = YangInstanceIdentifierWriter.open(streamWriter, root, path)) {
+            try (var nnWriter = new NormalizedNodeWriter(streamWriter)) {
+                final QName leafQname = QName.create("test", "leaf");
+
+                final LeafSetEntryNode<?> leafNode = mock(LeafSetEntryNode.class);
+                doReturn(new NodeWithValue<>(leafQname, "test-value")).when(leafNode).getIdentifier();
+                doReturn("test-value").when(leafNode).body();
+                nnWriter.write(leafNode);
+
+                final LeafSetEntryNode<?> leafNode2 = mock(LeafSetEntryNode.class);
+                doReturn(new NodeWithValue<>(leafQname, "test-value-2")).when(leafNode2).getIdentifier();
+                doReturn("test-value-2").when(leafNode2).body();
+                nnWriter.write(leafNode2);
+            }
+        }
+
+        assertEquals("(test)list-list(leaf-list)\n"
+            + "  (test)leaf(entry)\n"
+            + "    (String)=test-value\n"
+            + "  (end)\n"
+            + "  (test)leaf(entry)\n"
+            + "    (String)=test-value-2\n"
+            + "  (end)\n"
+            + "(end)\n", streamWriter.result());
+    }
+
+    private static NormalizedNode mockedPayload() {
+        final ContainerNode containerNode = mock(ContainerNode.class);
+        final LeafNode<?> leafNode = mock(LeafNode.class);
+
+        doReturn(new NodeIdentifier(QName.create("test", "payload-container"))).when(containerNode).getIdentifier();
+        doReturn(Set.of(leafNode)).when(containerNode).body();
+        doReturn(new NodeIdentifier(QName.create("test", "payload-leaf"))).when(leafNode).getIdentifier();
+        doReturn("leaf-value").when(leafNode).body();
+
+        return containerNode;
+    }
+}
\ No newline at end of file
index 553243f24d085ea01040b98fef197740908e5ad0..5b3b694828915a41fe36e8fcb8d7efaeeb6ac912 100644 (file)
@@ -7,15 +7,15 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Verify.verify;
 
-import java.util.Iterator;
+import java.io.IOException;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 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.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
@@ -26,6 +26,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
 import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.YangInstanceIdentifierWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
@@ -33,7 +34,7 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMa
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUserMapNodeBuilder;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 public final class ImmutableNodes {
@@ -202,22 +203,29 @@ public final class ImmutableNodes {
      * @param ctx schema context to used during serialization
      * @param id instance identifier to convert to node structure starting from root
      * @return serialized normalized node for provided instance Id
+     * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if the identifier cannot be converted
      */
-    public static @NonNull NormalizedNode fromInstanceId(final SchemaContext ctx, final YangInstanceIdentifier id) {
-        final PathArgument topLevelElement;
-        final InstanceIdToNodes<?> instanceIdToNodes;
-        final Iterator<PathArgument> it = id.getPathArguments().iterator();
-        if (it.hasNext()) {
-            topLevelElement = it.next();
-            final DataSchemaNode dataChildByName = ctx.dataChildByName(topLevelElement.getNodeType());
-            checkNotNull(dataChildByName,
-                "Cannot find %s node in schema context. Instance identifier has to start from root", topLevelElement);
-            instanceIdToNodes = InstanceIdToNodes.fromSchemaAndQNameChecked(ctx, topLevelElement.getNodeType());
-        } else {
-            topLevelElement = SCHEMACONTEXT_NAME;
-            instanceIdToNodes = InstanceIdToNodes.fromDataSchemaNode(ctx);
+    public static @NonNull NormalizedNode fromInstanceId(final EffectiveModelContext ctx,
+            final YangInstanceIdentifier id) {
+        if (id.isEmpty()) {
+            return ImmutableNodes.containerNode(SchemaContext.NAME);
         }
 
-        return instanceIdToNodes.create(topLevelElement, it);
+        final var result = new NormalizedNodeResult();
+        try (var writer = ImmutableNormalizedNodeStreamWriter.from(result)) {
+            try (var iidWriter = YangInstanceIdentifierWriter.open(writer, ctx, id)) {
+                // leaf-list entry nodes are special: they require a value and we can derive it from our instance
+                // identitifier
+                final var lastArg = id.getLastPathArgument();
+                if (lastArg instanceof NodeWithValue) {
+                    writer.scalarValue(((NodeWithValue<?>) lastArg).getValue());
+                }
+            }
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Failed to convert " + id, e);
+        }
+        verify(result.isFinished());
+        return result.getResult();
     }
 }
diff --git a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToCompositeNodes.java b/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToCompositeNodes.java
deleted file mode 100644 (file)
index f5f447d..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (c) 2015 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.impl.schema;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verify;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.util.ImmutableOffsetMap;
-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;
-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.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerLike;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
- */
-abstract class InstanceIdToCompositeNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
-    private static final Logger LOG = LoggerFactory.getLogger(InstanceIdToCompositeNodes.class);
-
-    InstanceIdToCompositeNodes(final T identifier) {
-        super(identifier);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    final NormalizedNode create(final PathArgument first, final Iterator<PathArgument> others) {
-        if (!isMixin()) {
-            final QName type = getIdentifier().getNodeType();
-            if (type != null) {
-                final QName firstType = first.getNodeType();
-                checkArgument(type.equals(firstType), "Node QName must be %s was %s", type, firstType);
-            }
-        }
-
-        @SuppressWarnings("rawtypes")
-        final NormalizedNodeContainerBuilder builder = createBuilder(first);
-
-        if (others.hasNext()) {
-            final PathArgument childPath = others.next();
-            final InstanceIdToNodes<?> childOp = getChildOperation(childPath);
-            builder.addChild(childOp.create(childPath, others));
-        }
-
-        return builder.build();
-    }
-
-    @SuppressWarnings("checkstyle:illegalCatch")
-    private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
-        final InstanceIdToNodes<?> childOp;
-        try {
-            childOp = getChild(childPath);
-        } catch (final RuntimeException e) {
-            throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
-        }
-        checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
-        return childOp;
-    }
-
-    abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(PathArgument compositeNode);
-
-    abstract static class DataContainerNormalizationOperation<T extends PathArgument, S extends DataNodeContainer>
-            extends InstanceIdToCompositeNodes<T> {
-
-        private final Map<PathArgument, InstanceIdToNodes<?>> byArg = new ConcurrentHashMap<>();
-        private final @NonNull S schema;
-
-        DataContainerNormalizationOperation(final T identifier, final S schema) {
-            super(identifier);
-            this.schema = requireNonNull(schema);
-        }
-
-        @Override
-        final InstanceIdToNodes<?> getChild(final PathArgument child) {
-            final InstanceIdToNodes<?> existing = byArg.get(child);
-            if (existing != null) {
-                return existing;
-            }
-            return register(fromLocalSchema(child));
-        }
-
-        final @NonNull S schema() {
-            return schema;
-        }
-
-        private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
-            if (child instanceof AugmentationIdentifier) {
-                return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
-                        .iterator().next());
-            }
-            return fromSchemaAndQNameChecked(schema, child.getNodeType());
-        }
-
-        private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
-            if (potential != null) {
-                byArg.put(potential.getIdentifier(), potential);
-            }
-            return potential;
-        }
-    }
-
-    static final class MapEntryNormalization
-            extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates, ListSchemaNode> {
-        MapEntryNormalization(final ListSchemaNode schema) {
-            super(NodeIdentifierWithPredicates.of(schema.getQName()), schema);
-        }
-
-        @Override
-        boolean isMixin() {
-            return false;
-        }
-
-        @Override
-        DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> createBuilder(
-                final PathArgument currentArg) {
-            final NodeIdentifierWithPredicates arg = (NodeIdentifierWithPredicates) currentArg;
-            return createBuilder(arg.size() < 2 ? arg : reorderPredicates(schema().getKeyDefinition(), arg));
-        }
-
-        private static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> createBuilder(
-                final NodeIdentifierWithPredicates arg) {
-            final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
-                    .mapEntryBuilder().withNodeIdentifier(arg);
-            for (final Entry<QName, Object> keyValue : arg.entrySet()) {
-                builder.addChild(Builders.leafBuilder()
-                        .withNodeIdentifier(NodeIdentifier.create(keyValue.getKey())).withValue(keyValue.getValue())
-                        .build());
-            }
-            return builder;
-        }
-
-        private static NodeIdentifierWithPredicates reorderPredicates(final List<QName> keys,
-                final NodeIdentifierWithPredicates arg) {
-            if (Iterables.elementsEqual(keys, arg.keySet())) {
-                // Iteration order matches key order, reuse the identifier
-                return arg;
-            }
-
-            // We care about iteration order here!
-            final LinkedHashMap<QName, Object> map = Maps.newLinkedHashMapWithExpectedSize(arg.size());
-            for (QName qname : keys) {
-                final Object value = arg.getValue(qname);
-                if (value != null) {
-                    map.put(qname, value);
-                }
-            }
-            if (map.size() < arg.size()) {
-                // Okay, this should not happen, but let's handle that anyway
-                LOG.debug("Extra predicates in {} while expecting {}", arg, keys);
-                for (Entry<QName, Object> entry : arg.entrySet()) {
-                    map.putIfAbsent(entry.getKey(), entry.getValue());
-                }
-            }
-
-            // This copy retains iteration order and since we have more than one argument, it should always be
-            // and ImmutableOffsetMap -- which is guaranteed to be taken as-is
-            final Map<QName, Object> copy = ImmutableOffsetMap.orderedCopyOf(map);
-            verify(copy instanceof ImmutableOffsetMap);
-            return NodeIdentifierWithPredicates.of(arg.getNodeType(), (ImmutableOffsetMap<QName, Object>) copy);
-        }
-    }
-
-    static final class UnkeyedListItemNormalization
-            extends DataContainerNormalizationOperation<NodeIdentifier, ListSchemaNode> {
-        UnkeyedListItemNormalization(final ListSchemaNode schema) {
-            super(NodeIdentifier.create(schema.getQName()), schema);
-        }
-
-        @Override
-        DataContainerNodeBuilder<NodeIdentifier, UnkeyedListEntryNode> createBuilder(
-                final PathArgument compositeNode) {
-            return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        boolean isMixin() {
-            return false;
-        }
-    }
-
-    static final class ContainerTransformation
-            extends DataContainerNormalizationOperation<NodeIdentifier, ContainerLike> {
-        ContainerTransformation(final ContainerLike schema) {
-            super(NodeIdentifier.create(schema.getQName()), schema);
-        }
-
-        @Override
-        DataContainerNodeBuilder<NodeIdentifier, ContainerNode> createBuilder(final PathArgument compositeNode) {
-            return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        boolean isMixin() {
-            return false;
-        }
-    }
-
-    private abstract static class LeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
-        private final InstanceIdToNodes<?> innerOp;
-
-        LeafListMixinNormalization(final LeafListSchemaNode potential) {
-            super(NodeIdentifier.create(potential.getQName()));
-            innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
-        }
-
-        @Override
-        final InstanceIdToNodes<?> getChild(final PathArgument child) {
-            return child instanceof NodeWithValue ? innerOp : null;
-        }
-
-        @Override
-        final boolean isMixin() {
-            return true;
-        }
-    }
-
-    static final class OrderedLeafListMixinNormalization extends LeafListMixinNormalization {
-        OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
-            super(potential);
-        }
-
-        @Override
-        ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
-            return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
-        }
-    }
-
-    static class UnorderedLeafListMixinNormalization extends LeafListMixinNormalization {
-        UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
-            super(potential);
-        }
-
-        @Override
-        ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
-            return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
-        }
-    }
-
-    static final class AugmentationNormalization
-            extends DataContainerNormalizationOperation<AugmentationIdentifier, AugmentationSchemaNode> {
-        AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
-            super(DataSchemaContextNode.augmentationIdentifierFrom(augmentation),
-                new EffectiveAugmentationSchema(augmentation, schema));
-        }
-
-        @Override
-        DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> createBuilder(
-                final PathArgument compositeNode) {
-            return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        boolean isMixin() {
-            return true;
-        }
-    }
-
-    static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
-        private final MapEntryNormalization innerNode;
-
-        UnorderedMapMixinNormalization(final ListSchemaNode list) {
-            super(NodeIdentifier.create(list.getQName()));
-            innerNode = new MapEntryNormalization(list);
-        }
-
-        @Override
-        CollectionNodeBuilder<MapEntryNode, ? extends MapNode> createBuilder(final PathArgument compositeNode) {
-            return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        final InstanceIdToNodes<?> getChild(final PathArgument child) {
-            return child.getNodeType().equals(getIdentifier().getNodeType()) ? innerNode : null;
-        }
-
-        @Override
-        final boolean isMixin() {
-            return true;
-        }
-    }
-
-    static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
-        OrderedMapMixinNormalization(final ListSchemaNode list) {
-            super(list);
-        }
-
-        @Override
-        CollectionNodeBuilder<MapEntryNode, UserMapNode> createBuilder(final PathArgument compositeNode) {
-            return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
-        }
-    }
-
-    static final class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
-        private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
-
-        ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
-            super(NodeIdentifier.create(schema.getQName()));
-            final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
-
-            for (final CaseSchemaNode caze : schema.getCases()) {
-                for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
-                    final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
-                    byArgBuilder.put(childOp.getIdentifier(), childOp);
-                }
-            }
-            byArg = byArgBuilder.build();
-        }
-
-        @Override
-        InstanceIdToNodes<?> getChild(final PathArgument child) {
-            return byArg.get(child);
-        }
-
-        @Override
-        DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> createBuilder(final PathArgument compositeNode) {
-            return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        boolean isMixin() {
-            return true;
-        }
-    }
-}
diff --git a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToNodes.java b/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToNodes.java
deleted file mode 100644 (file)
index 4d4ffb7..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2015 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.impl.schema;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.common.collect.Iterables;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.concepts.AbstractSimpleIdentifiable;
-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.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
-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.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerLike;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-
-/**
- * Base strategy for converting an instance identifier into a normalized node structure.
- * Use provided static methods for generic YangInstanceIdentifier -> NormalizedNode translation in ImmutableNodes.
- */
-abstract class InstanceIdToNodes<T extends PathArgument> extends AbstractSimpleIdentifiable<T> {
-    InstanceIdToNodes(final T identifier) {
-        super(identifier);
-    }
-
-    /**
-     * Build a strategy for the next path argument.
-     *
-     * @param child child identifier
-     * @return transformation strategy for a specific child
-     */
-    abstract @Nullable InstanceIdToNodes<?> getChild(PathArgument child);
-
-    /**
-     * Convert instance identifier into a NormalizedNode structure.
-     *
-     * @param first First path argument
-     * @param others Subsequent path arguments
-     * @return NormalizedNode structure corresponding to submitted instance ID
-     */
-    abstract @NonNull NormalizedNode create(PathArgument first, Iterator<PathArgument> others);
-
-    abstract boolean isMixin();
-
-    private static final class UnkeyedListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
-        private final UnkeyedListItemNormalization innerNode;
-
-        UnkeyedListMixinNormalization(final ListSchemaNode list) {
-            super(NodeIdentifier.create(list.getQName()));
-            innerNode = new UnkeyedListItemNormalization(list);
-        }
-
-        @Override
-        CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> createBuilder(final PathArgument compositeNode) {
-            return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        InstanceIdToNodes<?> getChild(final PathArgument child) {
-            return child.getNodeType().equals(getIdentifier().getNodeType()) ? innerNode : null;
-        }
-
-        @Override
-        boolean isMixin() {
-            return true;
-        }
-    }
-
-    private static final class OpaqueNormalization extends InstanceIdToNodes<NodeIdentifier> {
-        private OpaqueNormalization(final QName qname) {
-            super(NodeIdentifier.create(qname));
-        }
-
-        OpaqueNormalization(final AnydataSchemaNode schema) {
-            this(schema.getQName());
-        }
-
-        OpaqueNormalization(final AnyxmlSchemaNode schema) {
-            this(schema.getQName());
-        }
-
-        @Override
-        InstanceIdToNodes<?> getChild(final PathArgument child) {
-            return null;
-        }
-
-        @Override
-        boolean isMixin() {
-            return false;
-        }
-
-        @Override
-        NormalizedNode create(final PathArgument first, final Iterator<PathArgument> others) {
-            throw new IllegalStateException("Cannot instantiate opaque node without a value");
-        }
-    }
-
-    private static Optional<DataSchemaNode> findChildSchemaNode(final DataNodeContainer parent, final QName child) {
-        final Optional<DataSchemaNode> potential = parent.findDataChildByName(child);
-        return potential.isPresent() ? potential : Optional.ofNullable(
-            findChoice(Iterables.filter(parent.getChildNodes(), ChoiceSchemaNode.class), child));
-    }
-
-    static @Nullable InstanceIdToNodes<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) {
-        final Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
-        checkArgument(potential.isPresent(),
-                "Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child, schema,
-                schema.getChildNodes());
-
-        final DataSchemaNode result = potential.get();
-        // We try to look up if this node was added by augmentation
-        if (schema instanceof DataSchemaNode && result.isAugmenting()) {
-            return fromAugmentation(schema, (AugmentationTarget) schema, result);
-        }
-        return fromDataSchemaNode(result);
-    }
-
-    private static @Nullable ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) {
-        for (final ChoiceSchemaNode choice : choices) {
-            for (final CaseSchemaNode caze : choice.getCases()) {
-                if (findChildSchemaNode(caze, child).isPresent()) {
-                    return choice;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns a SchemaPathUtil for provided child node
-     * <p/>
-     * If supplied child is added by Augmentation this operation returns
-     * a SchemaPathUtil for augmentation,
-     * otherwise returns a SchemaPathUtil for child as
-     * call for {@link #fromDataSchemaNode(org.opendaylight.yangtools.yang.model.api.DataSchemaNode)}.
-     */
-    private static @Nullable InstanceIdToNodes<?> fromAugmentation(final DataNodeContainer parent,
-            final AugmentationTarget parentAug, final DataSchemaNode child) {
-        for (final AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
-            final Optional<DataSchemaNode> potential = aug.findDataChildByName(child.getQName());
-            if (potential.isPresent()) {
-                return new InstanceIdToCompositeNodes.AugmentationNormalization(aug, parent);
-            }
-        }
-        return fromDataSchemaNode(child);
-    }
-
-    static @Nullable InstanceIdToNodes<?> fromDataSchemaNode(final DataSchemaNode potential) {
-        if (potential instanceof ContainerLike) {
-            return new InstanceIdToCompositeNodes.ContainerTransformation((ContainerLike) potential);
-        } else if (potential instanceof ListSchemaNode) {
-            return fromListSchemaNode((ListSchemaNode) potential);
-        } else if (potential instanceof LeafSchemaNode) {
-            return new InstanceIdToSimpleNodes.LeafNormalization((LeafSchemaNode) potential);
-        } else if (potential instanceof ChoiceSchemaNode) {
-            return new InstanceIdToCompositeNodes.ChoiceNodeNormalization((ChoiceSchemaNode) potential);
-        } else if (potential instanceof LeafListSchemaNode) {
-            return fromLeafListSchemaNode((LeafListSchemaNode) potential);
-        } else if (potential instanceof AnydataSchemaNode) {
-            return new OpaqueNormalization((AnydataSchemaNode) potential);
-        } else if (potential instanceof AnyxmlSchemaNode) {
-            return new OpaqueNormalization((AnyxmlSchemaNode) potential);
-        }
-        return null;
-    }
-
-    private static InstanceIdToNodes<?> fromListSchemaNode(final ListSchemaNode potential) {
-        final List<QName> keyDefinition = potential.getKeyDefinition();
-        if (keyDefinition == null || keyDefinition.isEmpty()) {
-            return new UnkeyedListMixinNormalization(potential);
-        }
-        return potential.isUserOrdered() ? new InstanceIdToCompositeNodes.OrderedMapMixinNormalization(potential)
-                : new InstanceIdToCompositeNodes.UnorderedMapMixinNormalization(potential);
-    }
-
-    private static InstanceIdToNodes<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
-        return potential.isUserOrdered() ? new InstanceIdToCompositeNodes.OrderedLeafListMixinNormalization(potential)
-                : new InstanceIdToCompositeNodes.UnorderedLeafListMixinNormalization(potential);
-    }
-}
diff --git a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToSimpleNodes.java b/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToSimpleNodes.java
deleted file mode 100644 (file)
index bf40186..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2015 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.impl.schema;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.util.Iterator;
-import org.opendaylight.yangtools.yang.common.Empty;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-
-/**
-* Base strategy for converting an instance identifier into a normalized node structure for leaf and leaf-list types.
-*/
-abstract class InstanceIdToSimpleNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
-
-    InstanceIdToSimpleNodes(final T identifier) {
-        super(identifier);
-    }
-
-    @Override
-    final NormalizedNode create(final PathArgument first, final Iterator<PathArgument> others) {
-        return getBuilder(first).build();
-    }
-
-    @Override
-    final InstanceIdToNodes<?> getChild(final PathArgument child) {
-        return null;
-    }
-
-    @Override
-    final boolean isMixin() {
-        return false;
-    }
-
-    abstract NormalizedNodeBuilder<? extends PathArgument, Object, ? extends NormalizedNode> getBuilder(
-        PathArgument node);
-
-    static final class LeafNormalization extends InstanceIdToSimpleNodes<NodeIdentifier> {
-        LeafNormalization(final LeafSchemaNode potential) {
-            super(new NodeIdentifier(potential.getQName()));
-        }
-
-        @Override
-        NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> getBuilder(final PathArgument node) {
-            return Builders.leafBuilder().withNodeIdentifier(getIdentifier());
-        }
-    }
-
-    static final class LeafListEntryNormalization extends InstanceIdToSimpleNodes<NodeWithValue> {
-        LeafListEntryNormalization(final LeafListSchemaNode potential) {
-            // We are fudging a value here
-            super(new NodeWithValue<>(potential.getQName(), Empty.value()));
-        }
-
-        @Override
-        NormalizedNodeBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> getBuilder(final PathArgument node) {
-            checkArgument(node instanceof NodeWithValue);
-            return Builders.leafSetEntryBuilder().withNodeIdentifier((NodeWithValue<?>) node)
-                    .withValue(((NodeWithValue<?>) node).getValue());
-        }
-    }
-}