X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=data%2Fyang-data-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Futil%2FNormalizedNodeStreamWriterStack.java;h=1b48afe72800a157e6024c20b9744dbd98be5d93;hb=8f5f0782ffb25f903946d23816b199bdfb41fcda;hp=89052d8f92b786a6c0c5a8eaa155b86495a46b95;hpb=05efa813196bd32c6c40c3b09d24690baf028164;p=yangtools.git diff --git a/data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/NormalizedNodeStreamWriterStack.java b/data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/NormalizedNodeStreamWriterStack.java index 89052d8f92..1b48afe728 100644 --- a/data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/NormalizedNodeStreamWriterStack.java +++ b/data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/NormalizedNodeStreamWriterStack.java @@ -13,48 +13,38 @@ import static com.google.common.base.Verify.verify; import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; -import com.google.common.collect.Iterables; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; +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.NodeWithValue; 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.stream.NormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode; -import org.opendaylight.yangtools.yang.model.api.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.DocumentedNode.WithStatus; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference; -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; -import org.opendaylight.yangtools.yang.model.api.SchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ActionEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.AnydataEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ContainerEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeAwareEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafListEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.NotificationEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; -import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema; import org.opendaylight.yangtools.yang.model.util.LeafrefResolver; import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference; @@ -68,9 +58,9 @@ import org.slf4j.LoggerFactory; public final class NormalizedNodeStreamWriterStack implements LeafrefResolver { private static final Logger LOG = LoggerFactory.getLogger(NormalizedNodeStreamWriterStack.class); - private final Deque schemaStack = new ArrayDeque<>(); + private final Deque> schemaStack = new ArrayDeque<>(); private final SchemaInferenceStack dataTree; - private final DataNodeContainer root; + private final Object root; private NormalizedNodeStreamWriterStack(final EffectiveModelContext context) { dataTree = SchemaInferenceStack.of(context); @@ -80,12 +70,14 @@ public final class NormalizedNodeStreamWriterStack implements LeafrefResolver { private NormalizedNodeStreamWriterStack(final SchemaInferenceStack dataTree) { this.dataTree = requireNonNull(dataTree); if (!dataTree.isEmpty()) { - final EffectiveStatement current = dataTree.currentStatement(); - checkArgument(current instanceof DataNodeContainer, "Cannot instantiate on %s", current); - - root = (DataNodeContainer) current; + final var current = dataTree.currentStatement(); + if (current instanceof DataTreeAwareEffectiveStatement container) { + root = container; + } else { + throw new IllegalArgumentException("Cannot instantiate on " + current); + } } else { - root = dataTree.getEffectiveModelContext(); + root = dataTree.modelContext(); } } @@ -137,18 +129,20 @@ public final class NormalizedNodeStreamWriterStack implements LeafrefResolver { } /** - * Create a new writer with the specified context and rooted in the specified schema path. + * Create a new writer with the specified context and rooted in the specified {@link YangInstanceIdentifier}.. * * @param context Associated {@link EffectiveModelContext} - * @param path schema path + * @param path Normalized path * @return A new {@link NormalizedNodeStreamWriterStack} * @throws NullPointerException if any argument is null * @throws IllegalArgumentException if {@code path} does not point to a valid root */ - @Deprecated public static @NonNull NormalizedNodeStreamWriterStack of(final EffectiveModelContext context, - final SchemaPath path) { - return new NormalizedNodeStreamWriterStack(SchemaInferenceStack.ofInstantiatedPath(context, path)); + final YangInstanceIdentifier path) { + return new NormalizedNodeStreamWriterStack(DataSchemaContextTree.from(context) + .enterPath(path) + .orElseThrow() + .stack()); } /** @@ -177,156 +171,126 @@ public final class NormalizedNodeStreamWriterStack implements LeafrefResolver { return dataTree.resolveLeafref(type); } - public Object getParent() { - final WithStatus schema = schemaStack.peek(); - return schema == null ? root : schema; + /** + * Return the current {@link EffectiveStatement}, or {@code null}. + * + * @return the current {@link EffectiveStatement}, or {@code null} + */ + public @Nullable EffectiveStatement currentStatement() { + return schemaStack.peek(); } - private SchemaNode enterDataTree(final PathArgument name) { - final QName qname = name.getNodeType(); - final DataTreeEffectiveStatement stmt = dataTree.enterDataTree(qname); - verify(stmt instanceof SchemaNode, "Unexpected result %s", stmt); - final SchemaNode ret = (SchemaNode) stmt; - final Object parent = getParent(); - if (parent instanceof ChoiceSchemaNode) { - final DataSchemaNode check = ((ChoiceSchemaNode) parent).findDataSchemaChild(qname).orElse(null); - verify(check == ret, "Data tree result %s does not match choice result %s", ret, check); + private @NonNull DataTreeEffectiveStatement enterDataTree(final PathArgument name) { + final var qname = name.getNodeType(); + final var stmt = dataTree.enterDataTree(qname); + if (currentStatement() instanceof ChoiceEffectiveStatement choice) { + final var check = choice.findDataTreeNode(qname).orElse(null); + verify(check == stmt, "Data tree result %s does not match choice result %s", stmt, check); } - return ret; + return stmt; + } + + private > @NonNull T enterDataTree(final PathArgument name, + final @NonNull Class expectedClass, final @NonNull String humanString) { + final var schema = enterDataTree(name); + final @NonNull T casted; + try { + casted = expectedClass.cast(schema); + } catch (ClassCastException e) { + throw new IllegalArgumentException("Node " + schema + " is not " + humanString, e); + } + schemaStack.push(casted); + return casted; } public void startList(final PathArgument name) { - final SchemaNode schema = enterDataTree(name); - checkArgument(schema instanceof ListSchemaNode, "Node %s is not a list", schema); - schemaStack.push(schema); + enterDataTree(name, ListEffectiveStatement.class, "a list"); } public void startListItem(final PathArgument name) throws IOException { - final Object schema = getParent(); - checkArgument(schema instanceof ListSchemaNode, "List item is not appropriate"); - schemaStack.push((ListSchemaNode) schema); + if (!(currentStatement() instanceof ListEffectiveStatement parentList)) { + throw new IllegalArgumentException("List item is not appropriate"); + } + schemaStack.push(parentList); } public void startLeafNode(final NodeIdentifier name) throws IOException { - final SchemaNode schema = enterDataTree(name); - checkArgument(schema instanceof LeafSchemaNode, "Node %s is not a leaf", schema); - schemaStack.push(schema); + enterDataTree(name, LeafEffectiveStatement.class, "a leaf"); } - public LeafListSchemaNode startLeafSet(final NodeIdentifier name) { - final SchemaNode schema = enterDataTree(name); - checkArgument(schema instanceof LeafListSchemaNode, "Node %s is not a leaf-list", schema); - schemaStack.push(schema); - return (LeafListSchemaNode) schema; - } - - public LeafListSchemaNode leafSetEntryNode(final QName qname) { - final Object parent = getParent(); - if (parent instanceof LeafListSchemaNode) { - return (LeafListSchemaNode) parent; - } - checkArgument(parent instanceof DataNodeContainer, "Cannot lookup %s in parent %s", qname, parent); - final DataSchemaNode child = ((DataNodeContainer) parent).dataChildByName(qname); - checkArgument(child instanceof LeafListSchemaNode, - "Node %s is neither a leaf-list nor currently in a leaf-list", child); - return (LeafListSchemaNode) child; + public void startLeafSet(final NodeIdentifier name) { + enterDataTree(name, LeafListEffectiveStatement.class, "a leaf-list"); } public void startLeafSetEntryNode(final NodeWithValue name) { schemaStack.push(leafSetEntryNode(name.getNodeType())); } - public ChoiceSchemaNode startChoiceNode(final NodeIdentifier name) { + private @NonNull LeafListEffectiveStatement leafSetEntryNode(final QName qname) { + final var parent = currentStatement(); + if (parent instanceof LeafListEffectiveStatement leafList) { + return leafList; + } + if (parent instanceof DataTreeAwareEffectiveStatement parentContainer) { + final var child = parentContainer.findDataTreeNode(qname).orElse(null); + if (child instanceof LeafListEffectiveStatement childLeafList) { + return childLeafList; + } + throw new IllegalArgumentException( + "Node " + child + " is neither a leaf-list nor currently in a leaf-list"); + } + throw new IllegalArgumentException("Cannot lookup " + qname + " in parent " + parent); + } + + public void startChoiceNode(final NodeIdentifier name) { LOG.debug("Enter choice {}", name); - final ChoiceEffectiveStatement stmt = dataTree.enterChoice(name.getNodeType()); - verify(stmt instanceof ChoiceSchemaNode, "Node %s is not a choice", stmt); - final ChoiceSchemaNode ret = (ChoiceSchemaNode) stmt; - schemaStack.push(ret); - return ret; + schemaStack.push(dataTree.enterChoice(name.getNodeType())); } - public SchemaNode startContainerNode(final NodeIdentifier name) { + public @NonNull DataTreeAwareEffectiveStatement startContainerNode(final NodeIdentifier name) { LOG.debug("Enter container {}", name); - final SchemaNode schema; - if (schemaStack.isEmpty() && root instanceof NotificationDefinition) { + final DataTreeAwareEffectiveStatement ret; + if (schemaStack.isEmpty() && root instanceof NotificationEffectiveStatement notification + && name.getNodeType().equals(notification.argument())) { // Special case for stacks initialized at notification. We pretend the first container is contained within // itself. // FIXME: 8.0.0: factor this special case out to something more reasonable, like being initialized at the // Notification's parent and knowing to enterSchemaTree() instead of enterDataTree(). - schema = (NotificationDefinition) root; + ret = notification; } else { - schema = enterDataTree(name); - checkArgument(schema instanceof ContainerLike, "Node %s is not a container", schema); + final var child = enterDataTree(name); + if (child instanceof ContainerEffectiveStatement container) { + ret = container; + } else if (child instanceof InputEffectiveStatement input) { + ret = input; + } else if (child instanceof OutputEffectiveStatement output) { + ret = output; + } else { + dataTree.exitToDataTree(); + throw new IllegalArgumentException("Node " + child + " is not a container"); + } } - schemaStack.push(schema); - return schema; + schemaStack.push(ret); + return ret; } public void startAnyxmlNode(final NodeIdentifier name) { - final SchemaNode schema = enterDataTree(name); - checkArgument(schema instanceof AnyxmlSchemaNode, "Node %s is not anyxml", schema); - schemaStack.push(schema); + enterDataTree(name, AnyxmlEffectiveStatement.class, "anyxml"); } public void startAnydataNode(final NodeIdentifier name) { - final SchemaNode schema = enterDataTree(name); - checkArgument(schema instanceof AnydataSchemaNode, "Node %s is not anydata", schema); - schemaStack.push(schema); + enterDataTree(name, AnydataEffectiveStatement.class, "anydata"); } - public Object endNode() { - final Object ret = schemaStack.pop(); + public EffectiveStatement endNode() { + final var ret = schemaStack.pop(); // If this is a data tree node, make sure it is updated. Before that, though, we need to check if this is not // actually listEntry -> list or leafListEntry -> leafList exit. - if (!(ret instanceof AugmentationSchemaNode) && getParent() != ret) { + if (currentStatement() != ret) { dataTree.exit(); } return ret; } - - public AugmentationSchemaNode startAugmentationNode(final AugmentationIdentifier identifier) { - LOG.debug("Enter augmentation {}", identifier); - Object parent = getParent(); - - checkArgument(parent instanceof AugmentationTarget, "Augmentation not allowed under %s", parent); - if (parent instanceof ChoiceSchemaNode) { - final QName name = Iterables.get(identifier.getPossibleChildNames(), 0); - parent = findCaseByChild((ChoiceSchemaNode) parent, name); - } - checkArgument(parent instanceof DataNodeContainer, "Augmentation allowed only in DataNodeContainer", parent); - final AugmentationSchemaNode schema = findSchemaForAugment((AugmentationTarget) parent, - identifier.getPossibleChildNames()); - final AugmentationSchemaNode resolvedSchema = EffectiveAugmentationSchema.create(schema, - (DataNodeContainer) parent); - schemaStack.push(resolvedSchema); - return resolvedSchema; - } - - // FIXME: 7.0.0: can we get rid of this? - private static @NonNull AugmentationSchemaNode findSchemaForAugment(final AugmentationTarget schema, - final Set qnames) { - for (final AugmentationSchemaNode augment : schema.getAvailableAugmentations()) { - if (qnames.equals(augment.getChildNodes().stream() - .map(DataSchemaNode::getQName) - .collect(Collectors.toUnmodifiableSet()))) { - return augment; - } - } - - throw new IllegalStateException( - "Unknown augmentation node detected, identified by: " + qnames + ", in: " + schema); - } - - // FIXME: 7.0.0: can we get rid of this? - private static SchemaNode findCaseByChild(final ChoiceSchemaNode parent, final QName qname) { - for (final CaseSchemaNode caze : parent.getCases()) { - final Optional potential = caze.findDataChildByName(qname); - if (potential.isPresent()) { - return caze; - } - } - return null; - } }