From a2bd6a23f3b2edf06afb1b4b95dc7755d4730a00 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 8 Oct 2020 02:03:52 +0200 Subject: [PATCH] Expose SchemaNodeIdentifier-based XML access NETCONF is using SchemaPath-based instantiation quite heavily, some of which is getting triggered with operations and their SchemaNodeIdentifier. To ease the pain of that interaction, add methods which take SchemaNodeIdentifier.Absolute. This allows users to minimize conversions. Change-Id: I843ffc6ae63aa68118d4e95abe354cd65b3be51d Signed-off-by: Robert Varga --- .../XMLStreamNormalizedNodeStreamWriter.java | 49 +++++++++++++++++++ .../yang/data/impl/codec/SchemaTracker.java | 30 ++++++++++++ .../yang/data/impl/schema/SchemaUtils.java | 21 +++++++- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java index 2816d6a5f0..6fa8238ca8 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java @@ -22,6 +22,7 @@ import javax.xml.transform.dom.DOMSource; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.YangConstants; 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; @@ -32,6 +33,7 @@ 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.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Node; @@ -98,6 +100,53 @@ public abstract class XMLStreamNormalizedNodeStreamWriter implements Normaliz return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, SchemaTracker.create(context, path)); } + /** + * Create a new writer with the specified context and rooted in the specified schema path. + * + * @param writer Output {@link XMLStreamWriter} + * @param context Associated {@link EffectiveModelContext}. + * @param path path + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute path) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, SchemaTracker.create(context, path)); + } + + /** + * Create a new writer with the specified context and rooted in the specified operation's input. + * + * @param writer Output {@link XMLStreamWriter} + * @param context Associated {@link EffectiveModelContext}. + * @param operationPath Parent operation (RPC or action) path. + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter forInputOf(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute operationPath) { + return forOperation(writer, context, operationPath, + YangConstants.operationInputQName(operationPath.lastNodeIdentifier().getModule())); + } + + /** + * Create a new writer with the specified context and rooted in the specified operation's output. + * + * @param writer Output {@link XMLStreamWriter} + * @param context Associated {@link EffectiveModelContext}. + * @param operationPath Parent operation (RPC or action) path. + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter forOutputOf(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute operationPath) { + return forOperation(writer, context, operationPath, + YangConstants.operationOutputQName(operationPath.lastNodeIdentifier().getModule())); + } + + private static @NonNull NormalizedNodeStreamWriter forOperation(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute operationPath, final QName qname) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, + SchemaTracker.forOperation(context, operationPath, qname)); + } + /** * Create a new schema-less writer. Note that this version is intended for debugging * where doesn't have a SchemaContext available and isn't meant for production use. diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java index e8aad15dbf..e6befe8763 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; +import java.util.List; import java.util.Optional; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.odlext.model.api.YangModeledAnyxmlSchemaNode; @@ -44,6 +45,7 @@ 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.stmt.SchemaNodeIdentifier.Absolute; import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,6 +74,17 @@ public final class SchemaTracker { return new SchemaTracker(root); } + /** + * Create a new writer with the specified context and rooted in the specified schema path. + * + * @param context Associated {@link EffectiveModelContext} + * @param path schema path + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull SchemaTracker create(final EffectiveModelContext context, final Absolute path) { + return create(context, path.getNodeIdentifiers()); + } + /** * Create a new writer with the specified context and rooted in the specified schema path. * @@ -80,6 +93,10 @@ public final class SchemaTracker { * @return A new {@link NormalizedNodeStreamWriter} */ public static @NonNull SchemaTracker create(final EffectiveModelContext context, final SchemaPath path) { + return create(context, path.getPathFromRoot()); + } + + private static @NonNull SchemaTracker create(final EffectiveModelContext context, final Iterable path) { final Collection schemaNodes = SchemaUtils.findParentSchemaNodesOnPath(context, path); checkArgument(!schemaNodes.isEmpty(), "Unable to find schema node for supplied schema path: %s", path); if (schemaNodes.size() > 1) { @@ -94,6 +111,19 @@ public final class SchemaTracker { return new SchemaTracker(current.get()); } + /** + * Create a new writer with the specified context and rooted in the specified schema path. + * + * @param context Associated {@link EffectiveModelContext} + * @param operation Operation schema path + * @param qname Input/Output container QName + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull SchemaTracker forOperation(final EffectiveModelContext context, final Absolute operation, + final QName qname) { + return create(context, Iterables.concat(operation.getNodeIdentifiers(), List.of(qname))); + } + public Object getParent() { if (schemaStack.isEmpty()) { return root; diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java index fd0b77e918..63a98c54a8 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java @@ -477,10 +477,29 @@ public final class SchemaUtils { */ public static Collection findParentSchemaNodesOnPath(final SchemaContext schemaContext, final SchemaPath path) { + return findParentSchemaNodesOnPath(schemaContext, path.getPathFromRoot()); + } + + /** + * Finds schema node for given path in schema context. This method performs lookup in both the namespace + * of groupings and the namespace of all leafs, leaf-lists, lists, containers, choices, rpcs, actions, + * notifications, anydatas and anyxmls according to Rfc6050/Rfc7950 section 6.2.1. + * + *

+ * This method returns collection of SchemaNodes, because name conflicts can occur between the namespace + * of groupings and namespace of data nodes. This method finds and collects all schema nodes that matches supplied + * SchemaPath and returns them all as collection of schema nodes. + * + * @param schemaContext schema context + * @param path path + * @return collection of schema nodes on path + */ + public static Collection findParentSchemaNodesOnPath(final SchemaContext schemaContext, + final Iterable path) { final Collection currentNodes = new ArrayList<>(); final Collection childNodes = new ArrayList<>(); currentNodes.add(requireNonNull(schemaContext)); - for (final QName qname : path.getPathFromRoot()) { + for (final QName qname : path) { for (final SchemaNode current : currentNodes) { childNodes.addAll(findChildSchemaNodesByQName(current, qname)); } -- 2.36.6