Clean up DataSchemaContextNode.Composite 95/106095/2
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 21 May 2023 10:22:56 +0000 (12:22 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 21 May 2023 11:19:54 +0000 (13:19 +0200)
Fix naming of methods to be consistent with the rest our codebase. Also
document behaviour and eliminate duplicate code.

JIRA: YANGTOOLS-1413
Change-Id: I31bdd01a8bcb2ab8046bdbe7880a422c1e2e8dc0
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
16 files changed:
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/DataSchemaContextTree.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/model/AbstractCompositeContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/AbstractDataSchemaContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/AbstractListLikeContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/AbstractMixinContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/ChoiceContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/ContainerContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/DataContainerContextNode.java [deleted file]
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/LeafListContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/ListContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/ListItemContextNode.java
data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/MapContextNode.java
data/yang-data-util/src/test/java/org/opendaylight/yangtools/yang/data/util/impl/model/YT1412Test.java

index f853563c5e773b540fc90359a62aa0d689085d88..109a16876e41ae2ce348bbe88d84b3021dadb39c 100644 (file)
@@ -49,7 +49,7 @@ public abstract class AbstractStringInstanceIdentifierCodec extends AbstractName
         DataSchemaContextNode current = getDataContextTree().getRoot();
         QNameModule lastModule = null;
         for (var arg : data.getPathArguments()) {
-            current = current instanceof Composite composite ? composite.getChild(arg) : null;
+            current = current instanceof Composite composite ? composite.childByArg(arg) : null;
             checkArgument(current != null, "Invalid input %s: schema for argument %s (after %s) not found", data, arg,
                     sb);
 
index 0478e048615b465399956a0fa18c919d592cd3e3..04abc1fd045f3fef3eaadab72347ba80dde2e9de 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.data.util;
 
-import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -22,7 +21,6 @@ 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.DataSchemaContextNode.Composite;
-import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode.PathMixin;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode.SimpleValue;
 import org.opendaylight.yangtools.yang.data.util.impl.model.AbstractCompositeContextNode;
 import org.opendaylight.yangtools.yang.data.util.impl.model.AbstractDataSchemaContextNode;
@@ -40,19 +38,19 @@ 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.
  */
-public sealed interface DataSchemaContextNode permits AbstractDataSchemaContextNode, Composite, PathMixin, SimpleValue {
+public sealed interface DataSchemaContextNode permits AbstractDataSchemaContextNode, Composite, SimpleValue {
     /**
      * A {@link DataSchemaContextNode} containing other {@link DataSchemaContextNode}s.
      */
-    sealed interface Composite extends DataSchemaContextNode permits AbstractCompositeContextNode {
+    sealed interface Composite extends DataSchemaContextNode permits PathMixin, AbstractCompositeContextNode {
         /**
          * Find a child node identifier by its {@link PathArgument}.
          *
-         * @param child Child path argument
-         * @return A child node, or null if not found
+         * @param arg Child path argument
+         * @return A child node, or {@code null} if not found
+         * @throws NullPointerException if {@code arg} is {@code null}
          */
-        // FIXME: YANGTOOLS-1413: document PathArgument type mismatch, nullness and also rename it to 'childForArg'
-        @Nullable DataSchemaContextNode getChild(PathArgument child);
+        @Nullable DataSchemaContextNode childByArg(PathArgument arg);
 
         /**
          * Find a child node identifier by its {code data tree} {@link QName}. This method returns intermediate nodes
@@ -61,38 +59,33 @@ public sealed interface DataSchemaContextNode permits AbstractDataSchemaContextN
          * 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
+         * @param qname Child data tree QName
+         * @return A child node, or {@code null} if not found
+         * @throws NullPointerException if {@code arg} is {@code null}
          */
-        // FIXME: YANGTOOLS-1413: document child == null, also rename to 'childForQName'
-        @Nullable DataSchemaContextNode getChild(QName child);
+        @Nullable DataSchemaContextNode childByQName(QName qname);
 
         /**
          * Find a child node as identified by a {@link YangInstanceIdentifier} relative to this node.
          *
          * @param path Path towards the child node
          * @return Child node if present, or empty when corresponding child is not found.
-         * @throws NullPointerException if {@code path} is null
+         * @throws NullPointerException if {@code path} is {@code null}
          */
-        // FIXME: YANGTOOLS-1413: rename add a childForPath() method and rename this to 'findChildForPath'
-        default @NonNull Optional<@NonNull DataSchemaContextNode> findChild(
-                final @NonNull YangInstanceIdentifier path) {
+        default @Nullable DataSchemaContextNode childByPath(final @NonNull YangInstanceIdentifier path) {
             final var it = path.getPathArguments().iterator();
             if (!it.hasNext()) {
-                return Optional.of(this);
+                return this;
             }
 
             var current = this;
             while (true) {
-                final var child = current.getChild(it.next());
-                if (child == null) {
-                    return Optional.empty();
-                }
-                if (!it.hasNext()) {
-                    return Optional.of(child);
+                final var child = current.childByArg(it.next());
+                if (child == null || !it.hasNext()) {
+                    return child;
                 }
                 if (!(child instanceof Composite compositeChild)) {
-                    return Optional.empty();
+                    return null;
                 }
                 current = compositeChild;
             }
@@ -140,7 +133,7 @@ public sealed interface DataSchemaContextNode permits AbstractDataSchemaContextN
     * <p>
     * This trait is important for XML codec, but also for JSON encoding of {@link YangInstanceIdentifier}.
     */
-    sealed interface PathMixin extends DataSchemaContextNode permits AbstractMixinContextNode {
+    sealed interface PathMixin extends Composite permits AbstractMixinContextNode {
         /**
          * The mixed-in {@link NodeIdentifier}.
          *
index 1e119c7be8c3e72f66ec8fbd1c4da6fcfccf3d59..ce6e52945b315a9cd15a9b162cc045c5bc72605d 100644 (file)
@@ -62,7 +62,9 @@ public final class DataSchemaContextTree extends AbstractEffectiveModelContextPr
      * @throws NullPointerException if {@code path} is null
      */
     public @NonNull Optional<@NonNull DataSchemaContextNode> findChild(final @NonNull YangInstanceIdentifier path) {
-        return root.findChild(path);
+        // Optional.ofNullable() inline due to annotations
+        final var child = root.childByPath(path);
+        return child == null ? Optional.empty() : Optional.of(child);
     }
 
     /**
index 29b9998a31f834fc641d1e8ecf5123f34bac1452..4e2955f60133f471a633bba00734964683b98183 100644 (file)
@@ -113,19 +113,19 @@ final class XpathStringParsingPathArgumentBuilder implements Mutable {
         return computeIdentifierWithPredicate(name);
     }
 
-    private DataSchemaContextNode nextContextNode(final QName name) {
-        current = getChild(current, name);
-        checkValid(current != null, "%s is not correct schema node identifier.", name);
+    private DataSchemaContextNode nextContextNode(final QName qname) {
+        current = getChild(current, qname);
+        checkValid(current != null, "%s is not correct schema node identifier.", qname);
         while (current instanceof PathMixin mixin) {
             product.add(mixin.mixinPathStep());
-            current = getChild(current, name);
+            current = getChild(current, qname);
         }
-        stack.enterDataTree(name);
+        stack.enterDataTree(qname);
         return current;
     }
 
-    private static DataSchemaContextNode getChild(final DataSchemaContextNode parent, final QName name) {
-        return parent instanceof Composite composite ? composite.getChild(name) : null;
+    private static DataSchemaContextNode getChild(final DataSchemaContextNode parent, final QName qname) {
+        return parent instanceof Composite composite ? composite.childByQName(qname) : null;
     }
 
     /**
@@ -176,7 +176,7 @@ final class XpathStringParsingPathArgumentBuilder implements Mutable {
                     type -> resolveLeafref(currentSchema.getQName(), type), keyValue);
                 return new NodeWithValue<>(name, value);
             }
-            final var keyNode = currentNode instanceof Composite composite ? composite.getChild(key) : null;
+            final var keyNode = currentNode instanceof Composite composite ? composite.childByQName(key) : null;
             if (keyNode == null) {
                 throw iae("%s is not correct schema node identifier.", key);
             }
index 6e9d1091526684a2148602ad8383237bc587f82c..16c9b0607a7d941d8cd17936e62c281bfb95ed59 100644 (file)
@@ -9,35 +9,85 @@ package org.opendaylight.yangtools.yang.data.util.impl.model;
 
 import static java.util.Objects.requireNonNull;
 
-import org.eclipse.jdt.annotation.NonNull;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 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.data.util.DataSchemaContextNode.Composite;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
 public abstract sealed class AbstractCompositeContextNode extends AbstractDataSchemaContextNode implements Composite
-        permits AbstractMixinContextNode, DataContainerContextNode {
-    AbstractCompositeContextNode(final NodeIdentifier pathStep, final DataSchemaNode schema) {
+        permits ListItemContextNode, ContainerContextNode {
+    // FIXME: ImmutableMaps with compare-and-swap updates
+    private final ConcurrentMap<PathArgument, AbstractDataSchemaContextNode> byArg = new ConcurrentHashMap<>();
+    private final ConcurrentMap<QName, AbstractDataSchemaContextNode> byQName = new ConcurrentHashMap<>();
+    private final DataNodeContainer container;
+
+    AbstractCompositeContextNode(final NodeIdentifier pathStep, final DataNodeContainer container,
+            final DataSchemaNode schema) {
         super(pathStep, schema);
+        this.container = requireNonNull(container);
     }
 
     @Override
-    public final DataSchemaContextNode enterChild(final SchemaInferenceStack stack, final QName child) {
-        return enterChild(requireNonNull(child), requireNonNull(stack));
+    public final AbstractDataSchemaContextNode childByArg(final PathArgument arg) {
+        final var existing = byArg.get(requireNonNull(arg));
+        if (existing != null) {
+            return existing;
+        }
+        return register(fromLocalSchema(arg));
     }
 
     @Override
-    public final DataSchemaContextNode enterChild(final SchemaInferenceStack stack,
-            final PathArgument child) {
-        return enterChild(requireNonNull(child), requireNonNull(stack));
+    public final AbstractDataSchemaContextNode childByQName(final QName qname) {
+        var existing = byQName.get(requireNonNull(qname));
+        if (existing != null) {
+            return existing;
+        }
+        return register(fromLocalSchemaAndQName(container, qname));
     }
 
-    abstract @Nullable DataSchemaContextNode enterChild(@NonNull QName child, @NonNull SchemaInferenceStack stack);
+    @Override
+    public final DataSchemaContextNode enterChild(final SchemaInferenceStack stack, final QName qname) {
+        return pushToStack(stack, childByQName(qname));
+    }
 
-    abstract @Nullable DataSchemaContextNode enterChild(@NonNull PathArgument child,
-        @NonNull SchemaInferenceStack stack);
-}
\ No newline at end of file
+    @Override
+    public final DataSchemaContextNode enterChild(final SchemaInferenceStack stack, final PathArgument arg) {
+        return pushToStack(stack, childByArg(arg));
+    }
+
+    private static @Nullable DataSchemaContextNode pushToStack(final SchemaInferenceStack stack,
+            final @Nullable AbstractDataSchemaContextNode child) {
+        requireNonNull(stack);
+        if (child != null) {
+            child.pushToStack(stack);
+        }
+        return child;
+    }
+
+    private AbstractDataSchemaContextNode fromLocalSchema(final PathArgument child) {
+        return fromSchemaAndQNameChecked(container, child.getNodeType());
+    }
+
+    private static AbstractDataSchemaContextNode fromLocalSchemaAndQName(final DataNodeContainer schema,
+            final QName child) {
+        return fromSchemaAndQNameChecked(schema, child);
+    }
+
+    private AbstractDataSchemaContextNode register(final AbstractDataSchemaContextNode potential) {
+        if (potential != null) {
+            // FIXME: use putIfAbsent() to make sure we do not perform accidental overrwrites
+            byArg.put(potential.getPathStep(), potential);
+            for (QName qname : potential.qnameIdentifiers()) {
+                byQName.put(qname, potential);
+            }
+        }
+        return potential;
+    }
+}
index c35ae3cb9cc1475ce25e95f200a9402554c60d6e..4de531c4b686a73a7f84b8b05cefdc3101d52ccb 100644 (file)
@@ -35,7 +35,8 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
  * since the mapping is not one-to-one.
  */
 public abstract sealed class AbstractDataSchemaContextNode implements DataSchemaContextNode
-        permits AbstractCompositeContextNode, LeafContextNode, LeafListItemContextNode, OpaqueContextNode {
+        permits AbstractMixinContextNode, AbstractCompositeContextNode,
+                LeafContextNode, LeafListItemContextNode, OpaqueContextNode {
     private final @Nullable NodeIdentifier pathStep;
 
     final @NonNull DataSchemaNode dataSchemaNode;
@@ -69,16 +70,16 @@ public abstract sealed class AbstractDataSchemaContextNode implements DataSchema
         stack.enterSchemaTree(dataSchemaNode.getQName());
     }
 
-    static DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
+    static AbstractDataSchemaContextNode fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) {
+        return lenientOf(findChildSchemaNode(schema, child));
+    }
+
+    private static DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
         final DataSchemaNode potential = parent.dataChildByName(child);
         return potential == null ? findChoice(Iterables.filter(parent.getChildNodes(), ChoiceSchemaNode.class), child)
                 : potential;
     }
 
-    static AbstractDataSchemaContextNode fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) {
-        return lenientOf(findChildSchemaNode(schema, child));
-    }
-
     // FIXME: this looks like it should be a Predicate on a stream with findFirst()
     private static ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) {
         for (ChoiceSchemaNode choice : choices) {
@@ -113,7 +114,7 @@ public abstract sealed class AbstractDataSchemaContextNode implements DataSchema
     }
 
     // FIXME: do we tolerate null argument? do we tolerate unknown subclasses?
-    static @Nullable AbstractDataSchemaContextNode lenientOf(final @Nullable DataSchemaNode schema) {
+    private static @Nullable AbstractDataSchemaContextNode lenientOf(final @Nullable DataSchemaNode schema) {
         if (schema instanceof ContainerLike containerLike) {
             return new ContainerContextNode(containerLike);
         } else if (schema instanceof ListSchemaNode list) {
index 7e58b03aaa6be3854672ebf4a8810762a7ffd3fb..895b208a2843101c8105bac6f3fefa3885a70775 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.data.util.impl.model;
 
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
@@ -19,19 +22,29 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
  * levels backed by a single {@link DataSchemaNode}.
  */
 abstract sealed class AbstractListLikeContextNode extends AbstractMixinContextNode
-        permits ListContextNode, LeafListContextNode, MapContextNode {
-    AbstractListLikeContextNode(final DataSchemaNode schema) {
+        permits LeafListContextNode, ListContextNode, MapContextNode {
+    private final @NonNull AbstractDataSchemaContextNode child;
+
+    AbstractListLikeContextNode(final DataSchemaNode schema, final AbstractDataSchemaContextNode child) {
         super(schema);
+        this.child = requireNonNull(child);
+    }
+
+    @Override
+    public final AbstractDataSchemaContextNode childByQName(final QName qname) {
+        return qname.equals(dataSchemaNode.getQName()) ? child : null;
     }
 
+    // Stack is already pointing to the corresponding statement, now we are just working with the child
     @Override
-    final DataSchemaContextNode enterChild(final QName child, final SchemaInferenceStack stack) {
-        // Stack is already pointing to the corresponding statement, now we are just working with the child
-        return getChild(child);
+    public final AbstractDataSchemaContextNode enterChild(final SchemaInferenceStack stack, final QName qname) {
+        requireNonNull(stack);
+        return childByQName(qname);
     }
 
     @Override
-    final DataSchemaContextNode enterChild(final PathArgument child, final SchemaInferenceStack stack) {
-        return getChild(child);
+    public final DataSchemaContextNode enterChild(final SchemaInferenceStack stack, final PathArgument arg) {
+        requireNonNull(stack);
+        return childByArg(arg);
     }
 }
index 08d0c93d321ffde8df4a6e6b20550a288740b288..5c3a84e229ac638a4699d639f1b3af53c671f03a 100644 (file)
@@ -11,7 +11,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode.PathMixin;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
-public abstract sealed class AbstractMixinContextNode extends AbstractCompositeContextNode implements PathMixin
+public abstract sealed class AbstractMixinContextNode extends AbstractDataSchemaContextNode implements PathMixin
         permits AbstractListLikeContextNode, ChoiceContextNode {
     AbstractMixinContextNode(final DataSchemaNode schema) {
         super(NodeIdentifier.create(schema.getQName()), schema);
index 3c452efb3f1aa56799218a17bf3b2809b570205a..4d55778cac0387894b6fd21002feb2b98428861a 100644 (file)
@@ -8,19 +8,21 @@
 package org.opendaylight.yangtools.yang.data.util.impl.model;
 
 import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableMap;
 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;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
 final class ChoiceContextNode extends AbstractMixinContextNode {
-    private final ImmutableMap<PathArgument, AbstractDataSchemaContextNode> byArg;
+    private final ImmutableMap<NodeIdentifier, AbstractDataSchemaContextNode> byArg;
     private final ImmutableMap<QName, AbstractDataSchemaContextNode> byQName;
     private final ImmutableMap<DataSchemaContextNode, QName> childToCase;
 
@@ -28,7 +30,7 @@ final class ChoiceContextNode extends AbstractMixinContextNode {
         super(schema);
         final var childToCaseBuilder = ImmutableMap.<DataSchemaContextNode, QName>builder();
         final var byQNameBuilder = ImmutableMap.<QName, AbstractDataSchemaContextNode>builder();
-        final var byArgBuilder = ImmutableMap.<PathArgument, AbstractDataSchemaContextNode>builder();
+        final var byArgBuilder = ImmutableMap.<NodeIdentifier, AbstractDataSchemaContextNode>builder();
 
         for (var caze : schema.getCases()) {
             for (var cazeChild : caze.getChildNodes()) {
@@ -47,13 +49,13 @@ final class ChoiceContextNode extends AbstractMixinContextNode {
     }
 
     @Override
-    public AbstractDataSchemaContextNode getChild(final PathArgument child) {
-        return byArg.get(child);
+    public AbstractDataSchemaContextNode childByArg(final PathArgument arg) {
+        return byArg.get(requireNonNull(arg));
     }
 
     @Override
-    public AbstractDataSchemaContextNode getChild(final QName child) {
-        return byQName.get(child);
+    public AbstractDataSchemaContextNode childByQName(final QName child) {
+        return byQName.get(requireNonNull(child));
     }
 
     @Override
@@ -62,13 +64,13 @@ final class ChoiceContextNode extends AbstractMixinContextNode {
     }
 
     @Override
-    DataSchemaContextNode enterChild(final QName child, final SchemaInferenceStack stack) {
-        return pushToStack(getChild(child), stack);
+    public DataSchemaContextNode enterChild(final SchemaInferenceStack stack, final QName qname) {
+        return pushToStack(stack, childByQName(qname));
     }
 
     @Override
-    DataSchemaContextNode enterChild(final PathArgument child, final SchemaInferenceStack stack) {
-        return pushToStack(getChild(child), stack);
+    public DataSchemaContextNode enterChild(final SchemaInferenceStack stack, final PathArgument arg) {
+        return pushToStack(stack, childByArg(arg));
     }
 
     @Override
@@ -76,8 +78,9 @@ final class ChoiceContextNode extends AbstractMixinContextNode {
         stack.enterChoice(dataSchemaNode.getQName());
     }
 
-    private @Nullable DataSchemaContextNode pushToStack(final @Nullable AbstractDataSchemaContextNode child,
-            final @NonNull SchemaInferenceStack stack) {
+    private @Nullable DataSchemaContextNode pushToStack(final SchemaInferenceStack stack,
+            final @Nullable AbstractDataSchemaContextNode child) {
+        requireNonNull(stack);
         if (child != null) {
             final var caseName = verifyNotNull(childToCase.get(child), "No case statement for %s in %s", child, this);
             stack.enterSchemaTree(caseName);
index a688b12b0d32fcf797c10ce61098831d756946ac..d0df8ebabdc792368d4b1ea59c833a197270bb4c 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.yangtools.yang.data.util.impl.model;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.ContainerLike;
 
-public final class ContainerContextNode extends DataContainerContextNode {
+public final class ContainerContextNode extends AbstractCompositeContextNode {
     public ContainerContextNode(final ContainerLike schema) {
         super(NodeIdentifier.create(schema.getQName()), schema, schema);
     }
diff --git a/data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/DataContainerContextNode.java b/data/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/impl/model/DataContainerContextNode.java
deleted file mode 100644 (file)
index 0bc4139..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.data.util.impl.model;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-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.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
-
-abstract sealed class DataContainerContextNode extends AbstractCompositeContextNode
-        permits ListItemContextNode, ContainerContextNode {
-    private final ConcurrentMap<PathArgument, AbstractDataSchemaContextNode> byArg = new ConcurrentHashMap<>();
-    private final ConcurrentMap<QName, AbstractDataSchemaContextNode> byQName = new ConcurrentHashMap<>();
-    private final DataNodeContainer container;
-
-    DataContainerContextNode(final NodeIdentifier pathStep, final DataNodeContainer container,
-            final DataSchemaNode schema) {
-        super(pathStep, schema);
-        this.container = requireNonNull(container);
-    }
-
-    @Override
-    public final AbstractDataSchemaContextNode getChild(final PathArgument child) {
-        final var existing = byArg.get(child);
-        if (existing != null) {
-            return existing;
-        }
-        return register(fromLocalSchema(child));
-    }
-
-    @Override
-    public final AbstractDataSchemaContextNode getChild(final QName child) {
-        var existing = byQName.get(child);
-        if (existing != null) {
-            return existing;
-        }
-        return register(fromLocalSchemaAndQName(container, child));
-    }
-
-    @Override
-    final DataSchemaContextNode enterChild(final QName child, final SchemaInferenceStack stack) {
-        return pushToStack(getChild(child), stack);
-    }
-
-    @Override
-    final DataSchemaContextNode enterChild(final PathArgument child, final SchemaInferenceStack stack) {
-        return pushToStack(getChild(child), stack);
-    }
-
-    private static @Nullable DataSchemaContextNode pushToStack(final @Nullable AbstractDataSchemaContextNode child,
-            final @NonNull SchemaInferenceStack stack) {
-        if (child != null) {
-            child.pushToStack(stack);
-        }
-        return child;
-    }
-
-    private AbstractDataSchemaContextNode fromLocalSchema(final PathArgument child) {
-        return fromSchemaAndQNameChecked(container, child.getNodeType());
-    }
-
-    private static AbstractDataSchemaContextNode fromLocalSchemaAndQName(final DataNodeContainer schema,
-            final QName child) {
-        return fromSchemaAndQNameChecked(schema, child);
-    }
-
-    private AbstractDataSchemaContextNode register(final AbstractDataSchemaContextNode potential) {
-        if (potential != null) {
-            // FIXME: use putIfAbsent() to make sure we do not perform accidental overrwrites
-            byArg.put(potential.getPathStep(), potential);
-            for (QName qname : potential.qnameIdentifiers()) {
-                byQName.put(qname, potential);
-            }
-        }
-        return potential;
-    }
-}
index 3fefd95df4511849fd35ffebb76ead7e56db21d6..7cd323cb8bdc92cae5005d7466811bd23f9374d4 100644 (file)
@@ -7,29 +7,19 @@
  */
 package org.opendaylight.yangtools.yang.data.util.impl.model;
 
-import org.opendaylight.yangtools.yang.common.QName;
+import static java.util.Objects.requireNonNull;
+
 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;
 
 final class LeafListContextNode extends AbstractListLikeContextNode {
-    private final LeafListItemContextNode innerOp;
-
     LeafListContextNode(final LeafListSchemaNode schema) {
-        super(schema);
-        innerOp = new LeafListItemContextNode(schema);
-    }
-
-    @Override
-    public DataSchemaContextNode getChild(final PathArgument child) {
-        // FIXME: 10.0.0: reject null and invalid
-        return child instanceof NodeWithValue ? innerOp : null;
+        super(schema, new LeafListItemContextNode(schema));
     }
 
     @Override
-    public DataSchemaContextNode getChild(final QName child) {
-        // FIXME: requireNonNull, common code with UnkeyedListMixinNode
-        return dataSchemaNode.getQName().equals(child) ? innerOp : null;
+    public AbstractDataSchemaContextNode childByArg(final PathArgument arg) {
+        return requireNonNull(arg) instanceof NodeWithValue ? childByQName(arg.getNodeType()) : null;
     }
 }
index d4eb41c493f6bb93a4c82aa0f2c958f207fca24b..ff9b5b092bb617e818000467574d7f721bd206c1 100644 (file)
@@ -7,37 +7,21 @@
  */
 package org.opendaylight.yangtools.yang.data.util.impl.model;
 
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.QName;
+import static java.util.Objects.requireNonNull;
+
 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;
 
 final class ListContextNode extends AbstractListLikeContextNode {
-    private final ListItemContextNode innerNode;
-
     ListContextNode(final ListSchemaNode schema) {
-        super(schema);
         // FIXME: yeah, NodeIdentifier is being used for individual nodes, but it really should not
         //        (they are not addressable)
-        innerNode = new ListItemContextNode(NodeIdentifier.create(schema.getQName()), schema);
+        super(schema, new ListItemContextNode(NodeIdentifier.create(schema.getQName()), schema));
     }
 
     @Override
-    public DataSchemaContextNode getChild(final PathArgument child) {
-        // FIXME: 10.0.0: checkArgument() on PathArgument
-        return innerNodeIfMatch(child.getNodeType());
-    }
-
-    @Override
-    public DataSchemaContextNode getChild(final QName child) {
-        return innerNodeIfMatch(child);
-    }
-
-    // FIXME: dead ringers in other AbstractMixinContextNode subclasses
-    private @Nullable DataSchemaContextNode innerNodeIfMatch(final QName qname) {
-        // FIXME: 10.0.0: requireNonNull(qname)
-        return dataSchemaNode.getQName().equals(qname) ? innerNode : null;
+    public AbstractDataSchemaContextNode childByArg(final PathArgument arg) {
+        return requireNonNull(arg) instanceof NodeIdentifier ? childByQName(arg.getNodeType()) : null;
     }
 }
index b75073c2296c2d66452abc6b1474deac9e0584f2..47ed32d3fa202448021335b287ad4b8ba39e135e 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Individual list items -- be {@link MapEntryNode} or {@link UnkeyedListEntryNode}.
  */
-final class ListItemContextNode extends DataContainerContextNode {
+final class ListItemContextNode extends AbstractCompositeContextNode {
     ListItemContextNode(final NodeIdentifier pathStep, final ListSchemaNode schema) {
         super(pathStep, schema, schema);
     }
index 343b29c2d618439c5118f5189e232e20d4c89e68..a93e96386cbf8f0eebb9bc7e60992bd6ba76e505 100644 (file)
@@ -7,34 +7,19 @@
  */
 package org.opendaylight.yangtools.yang.data.util.impl.model;
 
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.QName;
+import static java.util.Objects.requireNonNull;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 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;
 
 final class MapContextNode extends AbstractListLikeContextNode {
-    private final ListItemContextNode innerNode;
-
     MapContextNode(final ListSchemaNode list) {
-        super(list);
-        innerNode = new ListItemContextNode(null, list);
+        super(list, new ListItemContextNode(null, list));
     }
 
     @Override
-    public DataSchemaContextNode getChild(final PathArgument child) {
-        // FIXME: validate PathArgument type
-        return innerNodeIfMatch(child.getNodeType());
-    }
-
-    @Override
-    public DataSchemaContextNode getChild(final QName child) {
-        return innerNodeIfMatch(child);
-    }
-
-    // FIXME: dead ringers in other AbstractMixinContextNode subclasses
-    private @Nullable DataSchemaContextNode innerNodeIfMatch(final QName qname) {
-        // FIXME: 10.0.0: requireNonNull(qname)
-        return dataSchemaNode.getQName().equals(qname) ? innerNode : null;
+    public AbstractDataSchemaContextNode childByArg(final PathArgument arg) {
+        return requireNonNull(arg) instanceof NodeIdentifierWithPredicates ? childByQName(arg.getNodeType()) : null;
     }
 }
index a6f85bf4bf953dabe3734286b7e0a84974226eba..825eacc126534374c4d7bdfaedcc3e9f90311fcc 100644 (file)
@@ -54,13 +54,13 @@ class YT1412Test {
         final var one = assertInstanceOf(ContainerContextNode.class, CONTEXT.getRoot().enterChild(stack, ONE));
         assertInstanceOf(ContainerEffectiveStatement.class, stack.currentStatement());
 
-        final var two = assertInstanceOf(ChoiceContextNode.class, one.enterChild(FOUR, stack));
+        final var two = assertInstanceOf(ChoiceContextNode.class, one.enterChild(stack, FOUR));
         assertInstanceOf(ChoiceEffectiveStatement.class, stack.currentStatement());
 
-        final var three = assertInstanceOf(ChoiceContextNode.class, two.enterChild(FOUR, stack));
+        final var three = assertInstanceOf(ChoiceContextNode.class, two.enterChild(stack, FOUR));
         assertInstanceOf(ChoiceEffectiveStatement.class, stack.currentStatement());
 
-        assertInstanceOf(LeafContextNode.class, three.enterChild(FOUR, stack));
+        assertInstanceOf(LeafContextNode.class, three.enterChild(stack, FOUR));
         assertInstanceOf(LeafEffectiveStatement.class, stack.currentStatement());
 
         assertEquals(Absolute.of(ONE, TWO, THREE, THREE, FOUR, FOUR), stack.toSchemaNodeIdentifier());
@@ -71,10 +71,10 @@ class YT1412Test {
         final var one = assertInstanceOf(ContainerContextNode.class, CONTEXT.getRoot().enterChild(stack, ONE));
         assertInstanceOf(ContainerEffectiveStatement.class, stack.currentStatement());
 
-        final var five = assertInstanceOf(ListContextNode.class, one.enterChild(FIVE, stack));
+        final var five = assertInstanceOf(ListContextNode.class, one.enterChild(stack, FIVE));
         assertInstanceOf(ListEffectiveStatement.class, stack.currentStatement());
 
-        assertInstanceOf(ListItemContextNode.class, five.enterChild(FIVE, stack));
+        assertInstanceOf(ListItemContextNode.class, five.enterChild(stack, FIVE));
         assertInstanceOf(ListEffectiveStatement.class, stack.currentStatement());
 
         assertEquals(Absolute.of(ONE, FIVE), stack.toSchemaNodeIdentifier());
@@ -85,13 +85,13 @@ class YT1412Test {
         final var one = assertInstanceOf(ContainerContextNode.class, CONTEXT.getRoot().enterChild(stack, ONE));
         assertInstanceOf(ContainerEffectiveStatement.class, stack.currentStatement());
 
-        final var two = assertInstanceOf(ChoiceContextNode.class, one.enterChild(SIX, stack));
+        final var two = assertInstanceOf(ChoiceContextNode.class, one.enterChild(stack, SIX));
         assertInstanceOf(ChoiceEffectiveStatement.class, stack.currentStatement());
 
-        final var three = assertInstanceOf(ChoiceContextNode.class, two.enterChild(SIX, stack));
+        final var three = assertInstanceOf(ChoiceContextNode.class, two.enterChild(stack, SIX));
         assertInstanceOf(ChoiceEffectiveStatement.class, stack.currentStatement());
 
-        assertInstanceOf(LeafContextNode.class, three.enterChild(SIX, stack));
+        assertInstanceOf(LeafContextNode.class, three.enterChild(stack, SIX));
         assertInstanceOf(LeafEffectiveStatement.class, stack.currentStatement());
 
         assertEquals(Absolute.of(ONE, TWO, THREE, THREE, SIX, SIX), stack.toSchemaNodeIdentifier());