Allow emission of operation input/output
[yangtools.git] / data / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / NormalizedNodeStreamWriterStack.java
index c03aae08a55d23dd326fe4091029d577b7615ba9..1b48afe72800a157e6024c20b9744dbd98be5d93 100644 (file)
@@ -13,11 +13,11 @@ import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
-import com.google.common.base.VerifyException;
 import java.io.IOException;
 import java.util.ArrayDeque;
 import java.util.Deque;
 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;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@@ -25,22 +25,23 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithV
 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.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.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.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;
@@ -57,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<DataSchemaNode> schemaStack = new ArrayDeque<>();
+    private final Deque<EffectiveStatement<?, ?>> schemaStack = new ArrayDeque<>();
     private final SchemaInferenceStack dataTree;
-    private final DataNodeContainer root;
+    private final Object root;
 
     private NormalizedNodeStreamWriterStack(final EffectiveModelContext context) {
         dataTree = SchemaInferenceStack.of(context);
@@ -70,7 +71,7 @@ public final class NormalizedNodeStreamWriterStack implements LeafrefResolver {
         this.dataTree = requireNonNull(dataTree);
         if (!dataTree.isEmpty()) {
             final var current = dataTree.currentStatement();
-            if (current instanceof DataNodeContainer container) {
+            if (current instanceof DataTreeAwareEffectiveStatement container) {
                 root = container;
             } else {
                 throw new IllegalArgumentException("Cannot instantiate on " + current);
@@ -170,28 +171,29 @@ public final class NormalizedNodeStreamWriterStack implements LeafrefResolver {
         return dataTree.resolveLeafref(type);
     }
 
-    public Object getParent() {
-        final var 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 @NonNull SchemaNode enterDataTree(final PathArgument name) {
+    private @NonNull DataTreeEffectiveStatement<?> enterDataTree(final PathArgument name) {
         final var qname = name.getNodeType();
         final var stmt = dataTree.enterDataTree(qname);
-        if (!(stmt instanceof SchemaNode ret)) {
-            throw new VerifyException("Unexpected result " + stmt);
+        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);
         }
-        if (getParent() instanceof ChoiceSchemaNode choice) {
-            final var check = choice.findDataSchemaChild(qname).orElse(null);
-            verify(check == ret, "Data tree result %s does not match choice result %s", ret, check);
-        }
-        return ret;
+        return stmt;
     }
 
-    private <T extends DataSchemaNode> @NonNull T enterDataTree(final PathArgument name,
+    private <T extends DataTreeEffectiveStatement<?>> @NonNull T enterDataTree(final PathArgument name,
             final @NonNull Class<T> expectedClass, final @NonNull String humanString) {
         final var schema = enterDataTree(name);
-        final T casted;
+        final @NonNull T casted;
         try {
             casted = expectedClass.cast(schema);
         } catch (ClassCastException e) {
@@ -202,32 +204,36 @@ public final class NormalizedNodeStreamWriterStack implements LeafrefResolver {
     }
 
     public void startList(final PathArgument name) {
-        enterDataTree(name, ListSchemaNode.class, "a list");
+        enterDataTree(name, ListEffectiveStatement.class, "a list");
     }
 
     public void startListItem(final PathArgument name) throws IOException {
-        if (!(getParent() instanceof ListSchemaNode parentList)) {
+        if (!(currentStatement() instanceof ListEffectiveStatement parentList)) {
             throw new IllegalArgumentException("List item is not appropriate");
         }
         schemaStack.push(parentList);
     }
 
     public void startLeafNode(final NodeIdentifier name) throws IOException {
-        enterDataTree(name, LeafSchemaNode.class, "a leaf");
+        enterDataTree(name, LeafEffectiveStatement.class, "a leaf");
     }
 
     public void startLeafSet(final NodeIdentifier name) {
-        enterDataTree(name, LeafListSchemaNode.class, "a leaf-list");
+        enterDataTree(name, LeafListEffectiveStatement.class, "a leaf-list");
+    }
+
+    public void startLeafSetEntryNode(final NodeWithValue<?> name) {
+        schemaStack.push(leafSetEntryNode(name.getNodeType()));
     }
 
-    private @NonNull LeafListSchemaNode leafSetEntryNode(final QName qname) {
-        final Object parent = getParent();
-        if (parent instanceof LeafListSchemaNode leafList) {
+    private @NonNull LeafListEffectiveStatement leafSetEntryNode(final QName qname) {
+        final var parent = currentStatement();
+        if (parent instanceof LeafListEffectiveStatement leafList) {
             return leafList;
         }
-        if (parent instanceof DataNodeContainer parentContainer) {
-            final var child = parentContainer.dataChildByName(qname);
-            if (child instanceof LeafListSchemaNode childLeafList) {
+        if (parent instanceof DataTreeAwareEffectiveStatement parentContainer) {
+            final var child = parentContainer.findDataTreeNode(qname).orElse(null);
+            if (child instanceof LeafListEffectiveStatement childLeafList) {
                 return childLeafList;
             }
             throw new IllegalArgumentException(
@@ -236,52 +242,53 @@ public final class NormalizedNodeStreamWriterStack implements LeafrefResolver {
         throw new IllegalArgumentException("Cannot lookup " + qname + " in parent " + parent);
     }
 
-    public void startLeafSetEntryNode(final NodeWithValue<?> name) {
-        schemaStack.push(leafSetEntryNode(name.getNodeType()));
-    }
-
     public void startChoiceNode(final NodeIdentifier name) {
         LOG.debug("Enter choice {}", name);
-        final var stmt = dataTree.enterChoice(name.getNodeType());
-        if (stmt instanceof ChoiceSchemaNode choice) {
-            schemaStack.push(choice);
-        } else {
-            throw new VerifyException("Node " + stmt + " is not a choice");
-        }
+        schemaStack.push(dataTree.enterChoice(name.getNodeType()));
     }
 
-    public @NonNull ContainerLike startContainerNode(final NodeIdentifier name) {
+    public @NonNull DataTreeAwareEffectiveStatement<QName, ?> startContainerNode(final NodeIdentifier name) {
         LOG.debug("Enter container {}", name);
 
-        final ContainerLike schema;
-        if (schemaStack.isEmpty() && root instanceof NotificationDefinition notification
-            && name.getNodeType().equals(notification.getQName())) {
+        final DataTreeAwareEffectiveStatement<QName, ?> 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 = notification.toContainerLike();
-            schemaStack.push(schema);
+            ret = notification;
         } else {
-            schema = enterDataTree(name, ContainerLike.class, "a container");
+            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");
+            }
         }
 
-        return schema;
+        schemaStack.push(ret);
+        return ret;
     }
 
     public void startAnyxmlNode(final NodeIdentifier name) {
-        enterDataTree(name, AnyxmlSchemaNode.class, "anyxml");
+        enterDataTree(name, AnyxmlEffectiveStatement.class, "anyxml");
     }
 
     public void startAnydataNode(final NodeIdentifier name) {
-        enterDataTree(name, AnydataSchemaNode.class, "anydata");
+        enterDataTree(name, AnydataEffectiveStatement.class, "anydata");
     }
 
-    public Object endNode() {
+    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 (getParent() != ret) {
+        if (currentStatement() != ret) {
             dataTree.exit();
         }
         return ret;