--- /dev/null
+/*
+ * 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()));
+ }
+}
--- /dev/null
+/*
+ * 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
*/
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;
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;
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 {
* @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();
}
}
+++ /dev/null
-/*
- * 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;
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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());
- }
- }
-}