Expose SchemaNodeIdentifier-based XML access 89/92989/3
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 8 Oct 2020 00:03:52 +0000 (02:03 +0200)
committerRobert Varga <nite@hq.sk>
Thu, 8 Oct 2020 07:28:30 +0000 (07:28 +0000)
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 <robert.varga@pantheon.tech>
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java

index 2816d6a5f0d8397cf80d1ef2d081e9ed68bbdc2b..6fa8238ca8c38b806684bd24ea653db96c8530cf 100644 (file)
@@ -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<T> 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.
index e8aad15dbf0046c34a93b50a288e00b6e7698c7e..e6befe87631d989e8f2c30177cd9aec0cf2355d3 100644 (file)
@@ -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<QName> path) {
         final Collection<SchemaNode> 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;
index fd0b77e918ab4012b4b45a021c5aa0924b5ec080..63a98c54a88161491bc25d29bca2eaddb1a903ab 100644 (file)
@@ -477,10 +477,29 @@ public final class SchemaUtils {
      */
     public static Collection<SchemaNode> 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.
+     *
+     * <p>
+     * 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<SchemaNode> findParentSchemaNodesOnPath(final SchemaContext schemaContext,
+            final Iterable<QName> path) {
         final Collection<SchemaNode> currentNodes = new ArrayList<>();
         final Collection<SchemaNode> 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));
             }