package org.opendaylight.yangtools.yang.data.codec.gson;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
-import static org.w3c.dom.Node.ELEMENT_NODE;
-import static org.w3c.dom.Node.TEXT_NODE;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableClassToInstanceMap;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
-import java.util.List;
+import java.util.NoSuchElementException;
import java.util.regex.Pattern;
import javax.xml.transform.dom.DOMSource;
import org.checkerframework.checker.regex.qual.Regex;
import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
* the writer too.
*
* @param codecFactory JSON codec factory
- * @param path Schema Path
+ * @param rootNode Root node inference
* @param initialNs Initial namespace
* @param jsonWriter JsonWriter
* @return A stream writer instance
*/
public static NormalizedNodeStreamWriter createExclusiveWriter(final JSONCodecFactory codecFactory,
- final Absolute path, final XMLNamespace initialNs, final JsonWriter jsonWriter) {
- return new Exclusive(codecFactory, SchemaTracker.create(codecFactory.getEffectiveModelContext(), path),
- jsonWriter, new JSONStreamWriterExclusiveRootContext(initialNs));
+ final EffectiveStatementInference rootNode, final XMLNamespace initialNs, final JsonWriter jsonWriter) {
+ return new Exclusive(codecFactory, SchemaTracker.create(rootNode), jsonWriter,
+ new JSONStreamWriterExclusiveRootContext(initialNs));
}
/**
* the writer too.
*
* @param codecFactory JSON codec factory
- * @param rootNode Root node
+ * @param path Schema Path
* @param initialNs Initial namespace
* @param jsonWriter JsonWriter
* @return A stream writer instance
*/
public static NormalizedNodeStreamWriter createExclusiveWriter(final JSONCodecFactory codecFactory,
- final DataNodeContainer rootNode, final XMLNamespace initialNs, final JsonWriter jsonWriter) {
- return new Exclusive(codecFactory, SchemaTracker.create(rootNode), jsonWriter,
- new JSONStreamWriterExclusiveRootContext(initialNs));
+ final Absolute path, final XMLNamespace initialNs, final JsonWriter jsonWriter) {
+ return new Exclusive(codecFactory, SchemaTracker.create(codecFactory.getEffectiveModelContext(), path),
+ jsonWriter, new JSONStreamWriterExclusiveRootContext(initialNs));
}
/**
* close the wrapped writer; the caller must take care of that.
*
* @param codecFactory JSON codec factory
- * @param rootNode Root node
+ * @param rootNode Root node inference
* @param initialNs Initial namespace
* @param jsonWriter JsonWriter
* @return A stream writer instance
*/
public static NormalizedNodeStreamWriter createNestedWriter(final JSONCodecFactory codecFactory,
- final DataNodeContainer rootNode, final XMLNamespace initialNs, final JsonWriter jsonWriter) {
+ final EffectiveStatementInference rootNode, final XMLNamespace initialNs, final JsonWriter jsonWriter) {
return new Nested(codecFactory, SchemaTracker.create(rootNode), jsonWriter,
new JSONStreamWriterSharedRootContext(initialNs));
}
}
private void writeNormalizedAnydata(final NormalizedAnydata anydata) throws IOException {
- final EffectiveStatementInference inference = anydata.getInference();
- final List<? extends EffectiveStatement<?, ?>> path = inference.statementPath();
- final DataNodeContainer parent;
- if (path.size() > 1) {
- final EffectiveStatement<?, ?> stmt = path.get(path.size() - 2);
- verify(stmt instanceof DataNodeContainer, "Unexpected statement %s", stmt);
- parent = (DataNodeContainer) stmt;
- } else {
- parent = inference.getEffectiveModelContext();
+ // Adjust state to point to parent node and ensure it can handle data tree nodes
+ final SchemaInferenceStack.Inference inference;
+ try {
+ final SchemaInferenceStack stack = SchemaInferenceStack.ofInference(anydata.getInference());
+ stack.exitToDataTree();
+ inference = stack.toInference();
+ } catch (IllegalArgumentException | IllegalStateException | NoSuchElementException e) {
+ throw new IOException("Cannot emit " + anydata, e);
}
anydata.writeTo(JSONNormalizedNodeStreamWriter.createNestedWriter(
- codecs.rebaseTo(inference.getEffectiveModelContext()), parent, context.getNamespace(), writer));
+ codecs.rebaseTo(inference.getEffectiveModelContext()), inference, context.getNamespace(), writer));
}
private void writeAnyXmlValue(final DOMSource anyXmlValue) throws IOException {
}
private static boolean isArrayElement(final Node node) {
- if (ELEMENT_NODE == node.getNodeType()) {
+ if (Node.ELEMENT_NODE == node.getNodeType()) {
final String nodeName = node.getNodeName();
for (Node nextNode = node.getNextSibling(); nextNode != null; nextNode = nextNode.getNextSibling()) {
- if (ELEMENT_NODE == nextNode.getNodeType() && nodeName.equals(nextNode.getNodeName())) {
+ if (Node.ELEMENT_NODE == nextNode.getNodeType() && nodeName.equals(nextNode.getNodeName())) {
return true;
}
}
private void writeObject(Node node) throws IOException {
String previousNodeName = "";
while (node != null) {
- if (ELEMENT_NODE == node.getNodeType()) {
+ if (Node.ELEMENT_NODE == node.getNodeType()) {
if (!node.getNodeName().equals(previousNodeName)) {
previousNodeName = node.getNodeName();
writer.name(node.getNodeName());
final NodeList children = node.getChildNodes();
for (int i = 0, length = children.getLength(); i < length; i++) {
final Node childNode = children.item(i);
- if (ELEMENT_NODE == childNode.getNodeType()) {
+ if (Node.ELEMENT_NODE == childNode.getNodeType()) {
return (Element) childNode;
}
}
final NodeList children = node.getChildNodes();
for (int i = 0, length = children.getLength(); i < length; i++) {
final Node childNode = children.item(i);
- if (TEXT_NODE == childNode.getNodeType()) {
+ if (Node.TEXT_NODE == childNode.getNodeType()) {
return (Text) childNode;
}
}
*/
package org.opendaylight.yangtools.yang.data.codec.xml;
-import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
import com.google.common.base.Strings;
import java.io.IOException;
-import java.util.List;
+import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.XMLConstants;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedAnydata;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
void emitNormalizedAnydata(final NormalizedAnydata anydata) throws XMLStreamException {
flushElement();
- final EffectiveStatementInference inference = anydata.getInference();
- final List<? extends EffectiveStatement<?, ?>> path = inference.statementPath();
- final DataNodeContainer parent;
- if (path.size() > 1) {
- final EffectiveStatement<?, ?> stmt = path.get(path.size() - 2);
- verify(stmt instanceof DataNodeContainer, "Unexpected statement %s", stmt);
- parent = (DataNodeContainer) stmt;
- } else {
- parent = inference.getEffectiveModelContext();
+ // Adjust state to point to parent node and ensure it can handle data tree nodes
+ final SchemaInferenceStack.Inference inference;
+ try {
+ final SchemaInferenceStack stack = SchemaInferenceStack.ofInference(anydata.getInference());
+ stack.exitToDataTree();
+ inference = stack.toInference();
+ } catch (IllegalArgumentException | IllegalStateException | NoSuchElementException e) {
+ throw new XMLStreamException("Cannot emit " + anydata, e);
}
try {
- anydata.writeTo(XMLStreamNormalizedNodeStreamWriter.create(writer, inference.getEffectiveModelContext(),
- parent));
+ anydata.writeTo(XMLStreamNormalizedNodeStreamWriter.create(writer, inference));
} catch (IOException e) {
throw new XMLStreamException("Failed to emit anydata " + anydata, e);
}
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriterExtension;
import org.opendaylight.yangtools.yang.data.impl.codec.SchemaTracker;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
import org.slf4j.Logger;
*/
public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
final EffectiveModelContext context) {
- return create(writer, context, context);
+ return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, SchemaTracker.create(context));
}
/**
* Create a new writer with the specified context and rooted at the specified node.
*
* @param writer Output {@link XMLStreamWriter}
- * @param context Associated {@link EffectiveModelContext}.
- * @param rootNode Root node
+ * @param inference root node inference
* @return A new {@link NormalizedNodeStreamWriter}
*/
public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer,
- final EffectiveModelContext context, final DataNodeContainer rootNode) {
- return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, SchemaTracker.create(rootNode));
+ final EffectiveStatementInference inference) {
+ return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, inference.getEffectiveModelContext(),
+ SchemaTracker.create(inference));
}
/**
requires transitive org.opendaylight.yangtools.yang.data.api;
requires transitive org.opendaylight.yangtools.rfc7952.data.api;
requires transitive org.opendaylight.yangtools.rfc7952.data.util;
+ requires transitive org.opendaylight.yangtools.yang.model.util;
requires org.opendaylight.yangtools.util;
requires org.opendaylight.yangtools.rfc8528.data.util;
requires org.opendaylight.yangtools.yang.common;
requires org.opendaylight.yangtools.yang.model.api;
requires org.opendaylight.yangtools.yang.model.spi;
- requires org.opendaylight.yangtools.yang.model.util;
requires org.slf4j;
// Annotations
package org.opendaylight.yangtools.yang.data.impl.codec;
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.annotations.Beta;
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.GroupingDefinition;
+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.SchemaPath;
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.ChoiceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
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.util.EffectiveAugmentationSchema;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(SchemaTracker.class);
private final Deque<WithStatus> schemaStack = new ArrayDeque<>();
+ private final SchemaInferenceStack dataTree;
private final DataNodeContainer root;
- private SchemaTracker(final DataNodeContainer root) {
- this.root = requireNonNull(root);
+ private SchemaTracker(final EffectiveModelContext context) {
+ root = requireNonNull(context);
+ dataTree = SchemaInferenceStack.of(context);
}
- private static @NonNull SchemaTracker create(final SchemaInferenceStack root) {
- if (root.isEmpty()) {
- return new SchemaTracker(root.getEffectiveModelContext());
+ private SchemaTracker(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;
+ } else {
+ root = dataTree.getEffectiveModelContext();
}
+ }
- final EffectiveStatement<?, ?> current = root.currentStatement();
- checkArgument(current instanceof DataNodeContainer, "Cannot instantiate on %s", current);
- return new SchemaTracker((DataNodeContainer) current);
+ /**
+ * Create a new writer with the specified inference state as its root.
+ *
+ * @param root Root inference state
+ * @return A new {@link NormalizedNodeStreamWriter}
+ * @throws NullPointerException if {@code root} is null
+ */
+ public static @NonNull SchemaTracker create(final EffectiveStatementInference root) {
+ return new SchemaTracker(SchemaInferenceStack.ofInference(root));
}
/**
- * Create a new writer with the specified node as its root.
+ * Create a new writer with the specified inference state as its root.
*
- * @param root Root node
+ * @param root Root inference state
* @return A new {@link NormalizedNodeStreamWriter}
* @throws NullPointerException if {@code root} is null
*/
- public static @NonNull SchemaTracker create(final DataNodeContainer root) {
- return new SchemaTracker(root);
+ public static @NonNull SchemaTracker create(final Inference root) {
+ return new SchemaTracker(root.toSchemaInferenceStack());
+ }
+
+ /**
+ * Create a new writer at the root of specified {@link EffectiveModelContext}.
+ *
+ * @param context effective model context
+ * @return A new {@link NormalizedNodeStreamWriter}
+ * @throws NullPointerException if {@code context} is null
+ */
+ public static @NonNull SchemaTracker create(final EffectiveModelContext context) {
+ return new SchemaTracker(context);
}
/**
* @throws IllegalArgumentException if {@code path} does not point to a valid root
*/
public static @NonNull SchemaTracker create(final EffectiveModelContext context, final Absolute path) {
- return create(SchemaInferenceStack.of(context, path));
+ return new SchemaTracker(SchemaInferenceStack.of(context, path));
}
/**
* @throws IllegalArgumentException if {@code path} does not point to a valid root
*/
public static @NonNull SchemaTracker create(final EffectiveModelContext context, final SchemaPath path) {
- return create(SchemaInferenceStack.ofInstantiatedPath(context, path));
+ return new SchemaTracker(SchemaInferenceStack.ofInstantiatedPath(context, path));
}
/**
checkArgument(current instanceof RpcEffectiveStatement || current instanceof ActionEffectiveStatement,
"Path %s resolved into non-operation %s", operation, current);
stack.enterSchemaTree(qname);
- return create(stack);
+ return new SchemaTracker(stack);
}
public Object getParent() {
- if (schemaStack.isEmpty()) {
- return root;
- }
- return schemaStack.peek();
+ final WithStatus schema = schemaStack.peek();
+ return schema == null ? root : schema;
}
- private SchemaNode getSchema(final PathArgument name) {
- final Object parent = getParent();
- SchemaNode schema = null;
+ private SchemaNode enterDataTree(final PathArgument name) {
final QName qname = name.getNodeType();
- if (parent instanceof DataNodeContainer) {
- schema = ((DataNodeContainer)parent).dataChildByName(qname);
- if (schema == null) {
- if (parent instanceof GroupingDefinition) {
- schema = (GroupingDefinition) parent;
- } else if (parent instanceof NotificationDefinition) {
- schema = (NotificationDefinition) parent;
- }
- }
- } else if (parent instanceof ChoiceSchemaNode) {
- schema = findChildInCases((ChoiceSchemaNode) parent, qname);
- } else {
- throw new IllegalStateException("Unsupported schema type " + parent.getClass() + " on stack.");
- }
-
- checkArgument(schema != null, "Could not find schema for node %s in %s", qname, parent);
- return schema;
- }
-
- private static SchemaNode findChildInCases(final ChoiceSchemaNode parent, final QName qname) {
- for (final CaseSchemaNode caze : parent.getCases()) {
- final Optional<DataSchemaNode> potential = caze.findDataChildByName(qname);
- if (potential.isPresent()) {
- return potential.get();
- }
- }
- return null;
- }
-
- private static SchemaNode findCaseByChild(final ChoiceSchemaNode parent, final QName qname) {
- for (final CaseSchemaNode caze : parent.getCases()) {
- final Optional<DataSchemaNode> potential = caze.findDataChildByName(qname);
- if (potential.isPresent()) {
- return caze;
- }
+ 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);
}
- return null;
+ return ret;
}
public void startList(final PathArgument name) {
- final SchemaNode schema = getSchema(name);
+ final SchemaNode schema = enterDataTree(name);
checkArgument(schema instanceof ListSchemaNode, "Node %s is not a list", schema);
schemaStack.push(schema);
}
schemaStack.push((ListSchemaNode) schema);
}
- public LeafSchemaNode leafNode(final NodeIdentifier name) throws IOException {
- final SchemaNode schema = getSchema(name);
- checkArgument(schema instanceof LeafSchemaNode, "Node %s is not a leaf", schema);
- return (LeafSchemaNode) schema;
- }
-
public void startLeafNode(final NodeIdentifier name) throws IOException {
- schemaStack.push(leafNode(name));
+ final SchemaNode schema = enterDataTree(name);
+ checkArgument(schema instanceof LeafSchemaNode, "Node %s is not a leaf", schema);
+ schemaStack.push(schema);
}
public LeafListSchemaNode startLeafSet(final NodeIdentifier name) {
- final SchemaNode schema = getSchema(name);
+ final SchemaNode schema = enterDataTree(name);
checkArgument(schema instanceof LeafListSchemaNode, "Node %s is not a leaf-list", schema);
schemaStack.push(schema);
return (LeafListSchemaNode) schema;
return (LeafListSchemaNode) parent;
}
+ // FIXME: when would this trigger?
final SchemaNode child = SchemaUtils.findDataChildSchemaByQName((SchemaNode) parent, qname);
checkArgument(child instanceof LeafListSchemaNode,
"Node %s is neither a leaf-list nor currently in a leaf-list", child);
public ChoiceSchemaNode startChoiceNode(final NodeIdentifier name) {
LOG.debug("Enter choice {}", name);
- final SchemaNode schema = getSchema(name);
-
- checkArgument(schema instanceof ChoiceSchemaNode, "Node %s is not a choice", schema);
- schemaStack.push(schema);
- return (ChoiceSchemaNode)schema;
+ 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;
}
public SchemaNode startContainerNode(final NodeIdentifier name) {
LOG.debug("Enter container {}", name);
- final SchemaNode schema = getSchema(name);
- final boolean isAllowed = schema instanceof ContainerLike || schema instanceof NotificationDefinition;
-
- checkArgument(isAllowed, "Node %s is not a container nor a notification", schema);
+ final SchemaNode schema = enterDataTree(name);
+ checkArgument(schema instanceof ContainerLike || schema instanceof NotificationDefinition,
+ "Node %s is not a container nor a notification", schema);
schemaStack.push(schema);
return schema;
}
return resolvedSchema;
}
- public AnyxmlSchemaNode anyxmlNode(final NodeIdentifier name) {
- final SchemaNode schema = getSchema(name);
- checkArgument(schema instanceof AnyxmlSchemaNode, "Node %s is not anyxml", schema);
- return (AnyxmlSchemaNode)schema;
+ private static SchemaNode findCaseByChild(final ChoiceSchemaNode parent, final QName qname) {
+ for (final CaseSchemaNode caze : parent.getCases()) {
+ final Optional<DataSchemaNode> potential = caze.findDataChildByName(qname);
+ if (potential.isPresent()) {
+ return caze;
+ }
+ }
+ return null;
}
public void startAnyxmlNode(final NodeIdentifier name) {
- schemaStack.push(anyxmlNode(name));
- }
-
- public AnydataSchemaNode anydataNode(final NodeIdentifier name) {
- final SchemaNode schema = getSchema(name);
- checkArgument(schema instanceof AnydataSchemaNode, "Node %s is not anydata", schema);
- return (AnydataSchemaNode)schema;
+ final SchemaNode schema = enterDataTree(name);
+ checkArgument(schema instanceof AnyxmlSchemaNode, "Node %s is not anyxml", schema);
+ schemaStack.push(schema);
}
public void startAnydataNode(final NodeIdentifier name) {
- schemaStack.push(anydataNode(name));
+ final SchemaNode schema = enterDataTree(name);
+ checkArgument(schema instanceof AnydataSchemaNode, "Node %s is not anydata", schema);
+ schemaStack.push(schema);
}
public Object endNode() {
- return schemaStack.pop();
+ final Object 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) {
+ dataTree.exit();
+ }
+ return ret;
}
}
this.clean = clean;
}
+ private SchemaInferenceStack(final EffectiveModelContext effectiveModel) {
+ this.effectiveModel = requireNonNull(effectiveModel);
+ this.deque = new ArrayDeque<>();
+ this.clean = true;
+ }
+
/**
* Create a new empty stack backed by an effective model.
*
* @param effectiveModel EffectiveModelContext to which this stack is attached
+ * @return A new stack
* @throws NullPointerException if {@code effectiveModel} is null
*/
- public SchemaInferenceStack(final EffectiveModelContext effectiveModel) {
- this.deque = new ArrayDeque<>();
- this.effectiveModel = requireNonNull(effectiveModel);
- this.clean = true;
+ public static @NonNull SchemaInferenceStack of(final EffectiveModelContext effectiveModel) {
+ return new SchemaInferenceStack(effectiveModel);
}
/**
* @throws IllegalArgumentException if {@code path} cannot be resolved in the effective model or if it is not an
* absolute path.
*/
- // FIXME: 7.0.0: consider deprecating this method
+ @Deprecated
public static @NonNull SchemaInferenceStack ofInstantiatedPath(final EffectiveModelContext effectiveModel,
final SchemaPath path) {
checkArgument(path.isAbsolute(), "Cannot operate on relative path %s", path);
return prev;
}
+ /**
+ * Pop the current statement from the stack, asserting it is a {@link DataTreeEffectiveStatement} and that
+ * subsequent {@link #enterDataTree(QName)} will find it again.
+ *
+ * @return Previous statement
+ * @throws NoSuchElementException if this stack is empty
+ * @throws IllegalStateException if current statement is not a DataTreeEffectiveStatement or if its parent is not
+ * a {@link DataTreeAwareEffectiveStatement}
+ */
+ public @NonNull DataTreeEffectiveStatement<?> exitToDataTree() {
+ final EffectiveStatement<?, ?> child = exit();
+ checkState(child instanceof DataTreeEffectiveStatement, "Unexpected current %s", child);
+ final EffectiveStatement<?, ?> parent = deque.peekFirst();
+ checkState(parent == null || parent instanceof DataTreeAwareEffectiveStatement, "Unexpected parent %s", parent);
+ return (DataTreeEffectiveStatement<?>) child;
+ }
+
/**
* Return an {@link Inference} equivalent of current state.
*
@Test
public void testEnterDataTree() {
final EffectiveModelContext context = YangParserTestUtils.parseYangResource("/yt1231.yang");
- final SchemaInferenceStack stack = new SchemaInferenceStack(context);
+ final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
// Trivial
assertThat(stack.enterDataTree(FOO), instanceOf(ContainerEffectiveStatement.class));
@Test
public void testEnterChoice() {
final EffectiveModelContext context = YangParserTestUtils.parseYangResource("/yt1231.yang");
- final SchemaInferenceStack stack = new SchemaInferenceStack(context);
+ final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
// Simple
assertThat(stack.enterDataTree(FOO), instanceOf(ContainerEffectiveStatement.class));
--- /dev/null
+/*
+ * Copyright (c) 2021 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.model.util;
+
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.GroupingEffectiveStatement;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class YT1233Test {
+ private static EffectiveModelContext context;
+
+ private final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+
+ @BeforeClass
+ public static void beforeClass() {
+ context = YangParserTestUtils.parseYangResource("/yt1233.yang");
+ }
+
+ @Test
+ public void testExitToDataTree() {
+ final DataTreeEffectiveStatement<?> foo = stack.enterDataTree(QName.create("foo", "foo"));
+ assertSame(foo, stack.exitToDataTree());
+ assertTrue(stack.isEmpty());
+ assertSame(foo, stack.enterDataTree(foo.argument()));
+ }
+
+ @Test
+ public void testExitToGrouping() {
+ final GroupingEffectiveStatement baz = stack.enterGrouping(QName.create("foo", "baz"));
+ final DataTreeEffectiveStatement<?> xyzzy = stack.enterDataTree(QName.create("foo", "xyzzy"));
+ assertSame(xyzzy, stack.exitToDataTree());
+ assertSame(baz, stack.currentStatement());
+ assertSame(xyzzy, stack.enterDataTree(xyzzy.argument()));
+ }
+
+ @Test
+ public void testEmptyExitToDataTree() {
+ assertThrows(NoSuchElementException.class, stack::exitToDataTree);
+ }
+
+ @Test
+ public void testSchemaExitToDataTree() {
+ stack.enterSchemaTree(QName.create("foo", "bar"));
+ final IllegalStateException ex = assertThrows(IllegalStateException.class, stack::exitToDataTree);
+ assertThat(ex.getMessage(), startsWith("Unexpected current "));
+ }
+}
--- /dev/null
+module foo {
+ namespace foo;
+ prefix foo;
+
+ anyxml foo;
+
+ rpc bar;
+
+ grouping baz {
+ anyxml xyzzy;
+ }
+}
+