From: Robert Varga Date: Tue, 1 Feb 2022 17:14:32 +0000 (+0100) Subject: Add YangInstanceIdentifierWriter X-Git-Tag: v8.0.0~6 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=yangtools.git;a=commitdiff_plain;h=a9c6dbac402cba3d68e0ffa77503f83431fc6ddb Add YangInstanceIdentifierWriter 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 Signed-off-by: Robert Varga --- 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 index 0000000000..37c0b03353 --- /dev/null +++ b/data/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriter.java @@ -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: + *
+ *   
+ *       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();
+ *   
+ * 
+ */ +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 key) throws IOException { + if (Iterables.elementsEqual(input.keySet(), key)) { + return input; + } + + final var builder = ImmutableMap.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 index 0000000000..ae7371a64b --- /dev/null +++ b/data/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/schema/stream/YangInstanceIdentifierWriterTest.java @@ -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 diff --git a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNodes.java b/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNodes.java index 553243f24d..5b3b694828 100644 --- a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNodes.java +++ b/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNodes.java @@ -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 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 index f5f447dd55..0000000000 --- a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToCompositeNodes.java +++ /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 extends InstanceIdToNodes { - 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 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 - extends InstanceIdToCompositeNodes { - - private final Map> 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 { - MapEntryNormalization(final ListSchemaNode schema) { - super(NodeIdentifierWithPredicates.of(schema.getQName()), schema); - } - - @Override - boolean isMixin() { - return false; - } - - @Override - DataContainerNodeBuilder createBuilder( - final PathArgument currentArg) { - final NodeIdentifierWithPredicates arg = (NodeIdentifierWithPredicates) currentArg; - return createBuilder(arg.size() < 2 ? arg : reorderPredicates(schema().getKeyDefinition(), arg)); - } - - private static DataContainerNodeBuilder createBuilder( - final NodeIdentifierWithPredicates arg) { - final DataContainerNodeBuilder builder = Builders - .mapEntryBuilder().withNodeIdentifier(arg); - for (final Entry keyValue : arg.entrySet()) { - builder.addChild(Builders.leafBuilder() - .withNodeIdentifier(NodeIdentifier.create(keyValue.getKey())).withValue(keyValue.getValue()) - .build()); - } - return builder; - } - - private static NodeIdentifierWithPredicates reorderPredicates(final List 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 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 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 copy = ImmutableOffsetMap.orderedCopyOf(map); - verify(copy instanceof ImmutableOffsetMap); - return NodeIdentifierWithPredicates.of(arg.getNodeType(), (ImmutableOffsetMap) copy); - } - } - - static final class UnkeyedListItemNormalization - extends DataContainerNormalizationOperation { - UnkeyedListItemNormalization(final ListSchemaNode schema) { - super(NodeIdentifier.create(schema.getQName()), schema); - } - - @Override - DataContainerNodeBuilder createBuilder( - final PathArgument compositeNode) { - return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier()); - } - - @Override - boolean isMixin() { - return false; - } - } - - static final class ContainerTransformation - extends DataContainerNormalizationOperation { - ContainerTransformation(final ContainerLike schema) { - super(NodeIdentifier.create(schema.getQName()), schema); - } - - @Override - DataContainerNodeBuilder createBuilder(final PathArgument compositeNode) { - return Builders.containerBuilder().withNodeIdentifier(getIdentifier()); - } - - @Override - boolean isMixin() { - return false; - } - } - - private abstract static class LeafListMixinNormalization extends InstanceIdToCompositeNodes { - 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 { - AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) { - super(DataSchemaContextNode.augmentationIdentifierFrom(augmentation), - new EffectiveAugmentationSchema(augmentation, schema)); - } - - @Override - DataContainerNodeBuilder createBuilder( - final PathArgument compositeNode) { - return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier()); - } - - @Override - boolean isMixin() { - return true; - } - } - - static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes { - private final MapEntryNormalization innerNode; - - UnorderedMapMixinNormalization(final ListSchemaNode list) { - super(NodeIdentifier.create(list.getQName())); - innerNode = new MapEntryNormalization(list); - } - - @Override - CollectionNodeBuilder 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 createBuilder(final PathArgument compositeNode) { - return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier()); - } - } - - static final class ChoiceNodeNormalization extends InstanceIdToCompositeNodes { - private final ImmutableMap> byArg; - - ChoiceNodeNormalization(final ChoiceSchemaNode schema) { - super(NodeIdentifier.create(schema.getQName())); - final ImmutableMap.Builder> 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 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 index 4d4ffb77b0..0000000000 --- a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToNodes.java +++ /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 extends AbstractSimpleIdentifiable { - 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 others); - - abstract boolean isMixin(); - - private static final class UnkeyedListMixinNormalization extends InstanceIdToCompositeNodes { - private final UnkeyedListItemNormalization innerNode; - - UnkeyedListMixinNormalization(final ListSchemaNode list) { - super(NodeIdentifier.create(list.getQName())); - innerNode = new UnkeyedListItemNormalization(list); - } - - @Override - CollectionNodeBuilder 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 { - 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 others) { - throw new IllegalStateException("Cannot instantiate opaque node without a value"); - } - } - - private static Optional findChildSchemaNode(final DataNodeContainer parent, final QName child) { - final Optional 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 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 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 - *

- * 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 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 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 index bf4018617c..0000000000 --- a/data/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/InstanceIdToSimpleNodes.java +++ /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 extends InstanceIdToNodes { - - InstanceIdToSimpleNodes(final T identifier) { - super(identifier); - } - - @Override - final NormalizedNode create(final PathArgument first, final Iterator others) { - return getBuilder(first).build(); - } - - @Override - final InstanceIdToNodes getChild(final PathArgument child) { - return null; - } - - @Override - final boolean isMixin() { - return false; - } - - abstract NormalizedNodeBuilder getBuilder( - PathArgument node); - - static final class LeafNormalization extends InstanceIdToSimpleNodes { - LeafNormalization(final LeafSchemaNode potential) { - super(new NodeIdentifier(potential.getQName())); - } - - @Override - NormalizedNodeBuilder> getBuilder(final PathArgument node) { - return Builders.leafBuilder().withNodeIdentifier(getIdentifier()); - } - } - - static final class LeafListEntryNormalization extends InstanceIdToSimpleNodes { - LeafListEntryNormalization(final LeafListSchemaNode potential) { - // We are fudging a value here - super(new NodeWithValue<>(potential.getQName(), Empty.value())); - } - - @Override - NormalizedNodeBuilder> getBuilder(final PathArgument node) { - checkArgument(node instanceof NodeWithValue); - return Builders.leafSetEntryBuilder().withNodeIdentifier((NodeWithValue) node) - .withValue(((NodeWithValue) node).getValue()); - } - } -}