Add DataSchemaContextNode.PathMixin 83/106083/6
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 20 May 2023 19:41:37 +0000 (21:41 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 20 May 2023 21:53:23 +0000 (23:53 +0200)
Remove isMixin() which provides a dummy boolean. We introduce PathMixin,
which guarantees a PathArgument without relying on
DataSchemaContextNode.pathArgument().

Partially seal the implementation hierarchy, making it clear that
PathMixin cannot be freely mixed in by random outsiders -- it really is
only provided by AbstractMixinContextNode.

This also makes it clear that all mixins are NodeIdentifiers, so we
centralize their creation in AbstractMixinContextNode.

JIRA: YANGTOOLS-1413
Change-Id: Ie834ac288658cebe3363ae051f004db4b0a7df75
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/XpathStringParsingPathArgumentBuilder.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/legacy/AbstractDataSchemaContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/legacy/AbstractListLikeContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/legacy/AbstractMixinContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/legacy/ChoiceNodeContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/legacy/UnkeyedListMixinContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/legacy/UnorderedLeafListMixinContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/legacy/UnorderedMapMixinContextNode.java

index f2fa4df0ba1812fde91e1ab34c8d6e14e7ccc61b..3f637be1e7743b0bef1d886962b1f315c749bce4 100644 (file)
@@ -23,6 +23,7 @@ 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.codec.InstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode.PathMixin;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.util.LeafrefResolver;
 
@@ -51,12 +52,10 @@ public abstract class AbstractStringInstanceIdentifierCodec extends AbstractName
             checkArgument(current != null, "Invalid input %s: schema for argument %s (after %s) not found", data, arg,
                     sb);
 
-            if (current.isMixin()) {
+            if (current instanceof PathMixin) {
                 /*
-                 * XML/YANG instance identifier does not have concept
-                 * of augmentation identifier, or list as whole which
-                 * identifies a mixin (same as the parent element),
-                 * so we can safely ignore it if it is part of path
+                 * XML/YANG instance identifier does not have concept of augmentation identifier, or list as whole which
+                 * identifies a mixin (same as the parent element), so we can safely ignore it if it is part of path
                  * (since child node) is identified in same fashion.
                  */
                 continue;
index 8e4c5da07048b867d4d0fabe719c6f73608c88f0..85692bb6f6c618448191998d3ff9d0d2c0110023 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.util.impl.legacy.AbstractMixinContextNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
@@ -29,10 +30,30 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
  * {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode} and serialization format defined in RFC6020,
  * since the mapping is not one-to-one.
  */
-// FIXME: YANGTOOLS-1413: this really should be an interface, as there is a ton of non-trivial composition going on:
-//        - getDataSchemaNode() cannot return AugmentationSchemaNode, which is guarded by isMixinNode() and users should
-//          not be touching mixin details anyway
 public interface DataSchemaContextNode {
+    /**
+    * This node is a {@link NormalizedNode} intermediate, not represented in RFC7950 XML encoding. This is typically
+    * one of
+    * <ul>
+    *   <li>{@link ChoiceNode} backed by a {@link ChoiceSchemaNode}, or</li>
+    *   <li>{@link LeafSetNode} backed by a {@link LeafListSchemaNode}, or</li>
+    *   <li>{@link MapNode} backed by a {@link ListSchemaNode} with a non-empty
+    *       {@link ListSchemaNode#getKeyDefinition()}, or</li>
+    *   <li>{@link UnkeyedListNode} backed by a {@link ListSchemaNode} with an empty
+    *       {@link ListSchemaNode#getKeyDefinition()}</li>
+    * </ul>
+    *
+    * <p>
+    * This trait is important for XML codec, but also for JSON encoding of {@link YangInstanceIdentifier}.
+    */
+    sealed interface PathMixin extends DataSchemaContextNode permits AbstractMixinContextNode {
+        /**
+         * The mixed-in {@link PathArgument}.
+         *
+         * @return Mixed-in PathArgument
+         */
+        @NonNull PathArgument mixinPathArgument();
+    }
 
     @NonNull DataSchemaNode getDataSchemaNode();
 
@@ -40,22 +61,6 @@ public interface DataSchemaContextNode {
     //                        because those identifiers need a value.
     @NonNull PathArgument pathArgument();
 
-     /**
-     * This node is a {@link NormalizedNode} intermediate, not represented in RFC7950 XML encoding. This is typically
-     * one of
-     * <ul>
-     *   <li>{@link ChoiceNode} backed by a {@link ChoiceSchemaNode}, or</li>
-     *   <li>{@link LeafSetNode} backed by a {@link LeafListSchemaNode}, or</li>
-     *   <li>{@link MapNode} backed by a {@link ListSchemaNode} with a non-empty
-     *       {@link ListSchemaNode#getKeyDefinition()}, or</li>
-     *   <li>{@link UnkeyedListNode} backed by a {@link ListSchemaNode} with an empty
-     *       {@link ListSchemaNode#getKeyDefinition()}</li>
-     * </ul>
-     *
-     * @return {@code} false if this node corresponds to an XML element, or {@code true} if it is an encapsulation node.
-     */
-    boolean isMixin();
-
     // FIXME: YANGTOOLS-1413: document this method and (most likely) split it out to a separate interface
     boolean isKeyedEntry();
 
@@ -75,9 +80,9 @@ public interface DataSchemaContextNode {
     /**
      * Find a child node identifier by its {code data tree} {@link QName}. This method returns intermediate nodes
      * significant from {@link YangInstanceIdentifier} hierarchy of {@link PathArgument}s. If the returned node
-     * indicates {@code true} via {@link #isMixin()}, it represents a {@link NormalizedNode} encapsulation which is
-     * not visible in RFC7950 XML encoding, and a further call to this method with the same {@code child} argument will
-     * provide the next step.
+     * indicates is also a {@link PathMixin}, it represents a {@link NormalizedNode} encapsulation which is not visible
+     * in RFC7950 XML encoding, and a further call to this method with the same {@code child} argument will provide the
+     * next step.
      *
      * @param child Child data tree QName
      * @return A child node, or null if not found
index 6a641670524703d2cf9b26ed3e82513f6ebaf243..bcc7e1583723b6362f10d25a700230eb4f4290cc 100644 (file)
@@ -21,6 +21,7 @@ import org.opendaylight.yangtools.yang.common.QNameModule;
 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.PathMixin;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
@@ -112,8 +113,8 @@ final class XpathStringParsingPathArgumentBuilder implements Mutable {
     private DataSchemaContextNode nextContextNode(final QName name) {
         current = current.getChild(name);
         checkValid(current != null, "%s is not correct schema node identifier.", name);
-        while (current.isMixin()) {
-            product.add(current.pathArgument());
+        while (current instanceof PathMixin mixin) {
+            product.add(mixin.mixinPathArgument());
             current = current.getChild(name);
         }
         stack.enterDataTree(name);
index d04f3c01bbd8cf0bd89d731db9e65208b7d8f656..a8cac8390b1b29f5e7538c2cc36fee4695cb0876 100644 (file)
@@ -54,11 +54,6 @@ public abstract class AbstractDataSchemaContextNode implements DataSchemaContext
         return pathArgument;
     }
 
-    @Override
-    public boolean isMixin() {
-        return false;
-    }
-
     @Override
     public boolean isKeyedEntry() {
         return false;
index 0d5ffb0ab0147970311c81f5f1cae379923630cf..3a321920231568051098bca26f2a84d5fb352f2a 100644 (file)
@@ -18,9 +18,10 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
  * representation of these nodes is similar to JSON encoding and therefore we have two {@link DataSchemaContextNode}
  * levels backed by a single {@link DataSchemaNode}.
  */
-abstract class AbstractListLikeContextNode extends AbstractMixinContextNode {
-    AbstractListLikeContextNode(final PathArgument pathArgument, final DataSchemaNode schema) {
-        super(pathArgument, schema);
+abstract sealed class AbstractListLikeContextNode extends AbstractMixinContextNode
+        permits UnkeyedListMixinContextNode, UnorderedLeafListMixinContextNode, UnorderedMapMixinContextNode {
+    AbstractListLikeContextNode(final DataSchemaNode schema) {
+        super(schema);
     }
 
     @Override
index b2295c9470d263aa5b863a420fd6c6f40486f2bd..422daa092a829c20720b37f565c861a8c2909cd3 100644 (file)
@@ -7,16 +7,19 @@
  */
 package org.opendaylight.yangtools.yang.data.util.impl.legacy;
 
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode.PathMixin;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
-abstract class AbstractMixinContextNode extends AbstractInteriorContextNode {
-    AbstractMixinContextNode(final PathArgument pathArgument, final DataSchemaNode schema) {
-        super(pathArgument, schema);
+public abstract sealed class AbstractMixinContextNode extends AbstractInteriorContextNode implements PathMixin
+        permits AbstractListLikeContextNode, ChoiceNodeContextNode {
+    AbstractMixinContextNode(final DataSchemaNode schema) {
+        super(NodeIdentifier.create(schema.getQName()), schema);
     }
 
     @Override
-    public final boolean isMixin() {
-        return true;
+    public PathArgument mixinPathArgument() {
+        return pathArgument();
     }
 }
\ No newline at end of file
index f92b30ef53821aa5028294c84be8a6b7daf86cce..bfe22cdc9613576ec95e0462721db599e981e0fe 100644 (file)
@@ -14,7 +14,6 @@ import java.util.Set;
 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.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
@@ -26,7 +25,7 @@ final class ChoiceNodeContextNode extends AbstractMixinContextNode {
     private final ImmutableMap<DataSchemaContextNode, QName> childToCase;
 
     ChoiceNodeContextNode(final ChoiceSchemaNode schema) {
-        super(NodeIdentifier.create(schema.getQName()), schema);
+        super(schema);
         final var childToCaseBuilder = ImmutableMap.<DataSchemaContextNode, QName>builder();
         final var byQNameBuilder = ImmutableMap.<QName, AbstractDataSchemaContextNode>builder();
         final var byArgBuilder = ImmutableMap.<PathArgument, AbstractDataSchemaContextNode>builder();
index 26cd4eac24b94f94be0c043113499ed347b890dd..ccd3825b7d4a0c6094c2550a571f4110cd8fc758 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.yangtools.yang.data.util.impl.legacy;
 
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
@@ -18,7 +17,7 @@ final class UnkeyedListMixinContextNode extends AbstractListLikeContextNode {
     private final UnkeyedListItemContextNode innerNode;
 
     UnkeyedListMixinContextNode(final ListSchemaNode list) {
-        super(NodeIdentifier.create(list.getQName()), list);
+        super(list);
         innerNode = new UnkeyedListItemContextNode(list);
     }
 
index bf0f4307e9ce4e21e56ae4f0170af0de641fea8d..afd643773bb514f10d61f0d4d0089ba424d2967e 100644 (file)
@@ -8,17 +8,17 @@
 package org.opendaylight.yangtools.yang.data.util.impl.legacy;
 
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 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.model.api.LeafListSchemaNode;
 
-class UnorderedLeafListMixinContextNode extends AbstractListLikeContextNode {
+sealed class UnorderedLeafListMixinContextNode extends AbstractListLikeContextNode
+        permits OrderedLeafListMixinContextNode {
     private final LeafListEntryContextNode innerOp;
 
     UnorderedLeafListMixinContextNode(final LeafListSchemaNode schema) {
-        super(NodeIdentifier.create(schema.getQName()), schema);
+        super(schema);
         innerOp = new LeafListEntryContextNode(schema);
     }
 
index bd63d90625f104be447418098df8d279be37ce29..45d8186bbe58911c8885229979e989bd9e81e50c 100644 (file)
@@ -9,16 +9,15 @@ package org.opendaylight.yangtools.yang.data.util.impl.legacy;
 
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 
-class UnorderedMapMixinContextNode extends AbstractListLikeContextNode {
+sealed class UnorderedMapMixinContextNode extends AbstractListLikeContextNode permits OrderedMapMixinContextNode {
     private final ListItemContextNode innerNode;
 
     UnorderedMapMixinContextNode(final ListSchemaNode list) {
-        super(NodeIdentifier.create(list.getQName()), list);
+        super(list);
         innerNode = new ListItemContextNode(list);
     }