Bump upstreams
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / nb / rfc8040 / utils / parser / NetconfFieldsTranslator.java
index 3a9333552b43faf83b29ba48c8a9f11a48d8c7f3..ab2543030e41abc67e83d7803b02b87d5b4005f6 100644 (file)
@@ -22,13 +22,17 @@ import org.opendaylight.restconf.api.query.FieldsParam;
 import org.opendaylight.restconf.api.query.FieldsParam.NodeSelector;
 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.ErrorTag;
 import org.opendaylight.yangtools.yang.common.ErrorType;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContext;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContext.PathMixin;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
@@ -54,8 +58,8 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
  */
 public final class NetconfFieldsTranslator {
     /**
-     * {@link DataSchemaContextNode} of data element grouped with identifiers of leading mixin nodes and previous
-     * path element.<br>
+     * {@link DataSchemaContext} of data element grouped with identifiers of leading mixin nodes and previous path
+     * element.<br>
      *  - identifiers of mixin nodes on the path to the target node - required for construction of full valid
      *    DOM paths,<br>
      *  - {@link LinkedPathElement} of the previous non-mixin node - required to successfully create a chain
@@ -68,7 +72,7 @@ public final class NetconfFieldsTranslator {
     private record LinkedPathElement(
             @Nullable LinkedPathElement parentPathElement,
             @NonNull List<PathArgument> mixinNodesToTarget,
-            @NonNull DataSchemaContextNode<?> targetNode) {
+            @NonNull DataSchemaContext targetNode) {
         LinkedPathElement {
             requireNonNull(mixinNodesToTarget);
             requireNonNull(targetNode);
@@ -96,10 +100,12 @@ public final class NetconfFieldsTranslator {
 
     private static @NonNull Set<LinkedPathElement> parseFields(final @NonNull InstanceIdentifierContext identifier,
             final @NonNull FieldsParam input) {
-        final var startNode = DataSchemaContextNode.fromDataSchemaNode((DataSchemaNode) identifier.getSchemaNode());
-        if (startNode == null) {
+        final DataSchemaContext startNode;
+        try {
+            startNode = DataSchemaContext.of((DataSchemaNode) identifier.getSchemaNode());
+        } catch (IllegalStateException e) {
             throw new RestconfDocumentedException(
-                "Start node missing in " + input, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+                "Start node missing in " + input, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, e);
         }
 
         final var parsed = new HashSet<LinkedPathElement>();
@@ -143,54 +149,74 @@ public final class NetconfFieldsTranslator {
             final QName childQName) {
         final var collectedMixinNodes = new ArrayList<PathArgument>();
 
-        DataSchemaContextNode<?> currentNode = currentElement.targetNode;
-        DataSchemaContextNode<?> actualContextNode = currentNode.getChild(childQName);
+        DataSchemaContext currentNode = currentElement.targetNode;
+        DataSchemaContext actualContextNode = childByQName(currentNode, childQName);
         if (actualContextNode == null) {
-            actualContextNode = resolveMixinNode(currentNode, currentNode.getIdentifier().getNodeType());
-            actualContextNode = actualContextNode.getChild(childQName);
+            actualContextNode = resolveMixinNode(currentNode, currentNode.getPathStep().getNodeType());
+            actualContextNode = childByQName(actualContextNode, childQName);
         }
 
-        while (actualContextNode != null && actualContextNode.isMixin()) {
-            final var actualDataSchemaNode = actualContextNode.getDataSchemaNode();
+        while (actualContextNode != null && actualContextNode instanceof PathMixin) {
+            final var actualDataSchemaNode = actualContextNode.dataSchemaNode();
             if (actualDataSchemaNode instanceof ListSchemaNode listSchema && listSchema.getKeyDefinition().isEmpty()) {
                 // we need just a single node identifier from list in the path IFF it is an unkeyed list, otherwise
                 // we need both (which is the default case)
-                actualContextNode = actualContextNode.getChild(childQName);
+                actualContextNode = childByQName(actualContextNode, childQName);
             } else if (actualDataSchemaNode instanceof LeafListSchemaNode) {
                 // NodeWithValue is unusable - stop parsing
                 break;
             } else {
-                collectedMixinNodes.add(actualContextNode.getIdentifier());
-                actualContextNode = actualContextNode.getChild(childQName);
+                collectedMixinNodes.add(actualContextNode.getPathStep());
+                actualContextNode = childByQName(actualContextNode, childQName);
             }
         }
 
         if (actualContextNode == null) {
             throw new RestconfDocumentedException("Child " + childQName.getLocalName() + " node missing in "
-                + currentNode.getIdentifier().getNodeType().getLocalName(),
+                + currentNode.getPathStep().getNodeType().getLocalName(),
                 ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
         }
 
         return new LinkedPathElement(currentElement, collectedMixinNodes, actualContextNode);
     }
 
+    private static @Nullable DataSchemaContext childByQName(final DataSchemaContext parent, final QName qname) {
+        return parent instanceof DataSchemaContext.Composite composite ? composite.childByQName(qname) : null;
+    }
+
     private static YangInstanceIdentifier buildPath(final LinkedPathElement lastPathElement) {
         LinkedPathElement pathElement = lastPathElement;
         final var path = new LinkedList<PathArgument>();
         do {
-            path.addFirst(pathElement.targetNode.getIdentifier());
+            path.addFirst(contextPathArgument(pathElement.targetNode));
             path.addAll(0, pathElement.mixinNodesToTarget);
             pathElement = pathElement.parentPathElement;
         } while (pathElement.parentPathElement != null);
 
-        return YangInstanceIdentifier.create(path);
+        return YangInstanceIdentifier.of(path);
+    }
+
+    private static @NonNull PathArgument contextPathArgument(final DataSchemaContext context) {
+        final var arg = context.pathStep();
+        if (arg != null) {
+            return arg;
+        }
+
+        final var schema = context.dataSchemaNode();
+        if (schema instanceof ListSchemaNode listSchema && !listSchema.getKeyDefinition().isEmpty()) {
+            return NodeIdentifierWithPredicates.of(listSchema.getQName());
+        }
+        if (schema instanceof LeafListSchemaNode leafListSchema) {
+            return new NodeWithValue<>(leafListSchema.getQName(), Empty.value());
+        }
+        throw new UnsupportedOperationException("Unsupported schema " + schema);
     }
 
-    private static DataSchemaContextNode<?> resolveMixinNode(final DataSchemaContextNode<?> node,
+    private static DataSchemaContext resolveMixinNode(final DataSchemaContext node,
             final @NonNull QName qualifiedName) {
-        DataSchemaContextNode<?> currentNode = node;
-        while (currentNode != null && currentNode.isMixin()) {
-            currentNode = currentNode.getChild(qualifiedName);
+        DataSchemaContext currentNode = node;
+        while (currentNode != null && currentNode instanceof PathMixin currentMixin) {
+            currentNode = currentMixin.childByQName(qualifiedName);
         }
         return currentNode;
     }