Make DataSchemaContextTree.NodeAndStack a record
[yangtools.git] / data / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / DataSchemaContextTree.java
index df3e019b61ec30b8fcb85a3aa0fee966696a127b..07984925dcd9bf7e06adeb0676a251f0c7a611f0 100644 (file)
@@ -7,15 +7,19 @@
  */
 package org.opendaylight.yangtools.yang.data.util;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.concepts.CheckedValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveModelContextProvider;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
 /**
  * Semantic tree binding a {@link EffectiveModelContext} to a {@link NormalizedNode} tree. Since the layout of the
@@ -24,19 +28,26 @@ import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveModelContextPr
  * @author Robert Varga
  */
 public final class DataSchemaContextTree extends AbstractEffectiveModelContextProvider {
-    private static final LoadingCache<EffectiveModelContext, DataSchemaContextTree> TREES = CacheBuilder.newBuilder()
-            .weakKeys().weakValues().build(new CacheLoader<EffectiveModelContext, DataSchemaContextTree>() {
-                @Override
-                public DataSchemaContextTree load(final EffectiveModelContext key) {
-                    return new DataSchemaContextTree(key);
-                }
-            });
+    public record NodeAndStack(@NonNull DataSchemaContextNode<?> node, @NonNull SchemaInferenceStack stack) {
+        public NodeAndStack(final @NonNull DataSchemaContextNode<?> node, final @NonNull SchemaInferenceStack stack) {
+            this.node = requireNonNull(node);
+            this.stack = requireNonNull(stack);
+        }
+    }
+
+    private static final LoadingCache<EffectiveModelContext, @NonNull DataSchemaContextTree> TREES =
+        CacheBuilder.newBuilder().weakKeys().weakValues().build(new CacheLoader<>() {
+            @Override
+            public DataSchemaContextTree load(final EffectiveModelContext key) {
+                return new DataSchemaContextTree(key);
+            }
+        });
 
-    private final DataSchemaContextNode<?> root;
+    private final @NonNull ContainerContextNode root;
 
     private DataSchemaContextTree(final EffectiveModelContext ctx) {
         super(ctx);
-        root = DataSchemaContextNode.from(ctx);
+        root = new ContainerContextNode(ctx);
     }
 
     public static @NonNull DataSchemaContextTree from(final @NonNull EffectiveModelContext ctx) {
@@ -51,7 +62,30 @@ public final class DataSchemaContextTree extends AbstractEffectiveModelContextPr
      * @throws NullPointerException if {@code path} is null
      */
     public @NonNull Optional<@NonNull DataSchemaContextNode<?>> findChild(final @NonNull YangInstanceIdentifier path) {
-        return getRoot().findChild(path);
+        return root.findChild(path);
+    }
+
+    /**
+     * Find a child node as identified by an absolute {@link YangInstanceIdentifier} and return it along with a suitably
+     * initialized {@link SchemaInferenceStack}.
+     *
+     * @param path Path towards the child node
+     * @return A {@link NodeAndStack}, or empty when corresponding child is not found.
+     * @throws NullPointerException if {@code path} is null
+     */
+    public @NonNull CheckedValue<@NonNull NodeAndStack, @NonNull IllegalArgumentException> enterPath(
+            final YangInstanceIdentifier path) {
+        final var stack = SchemaInferenceStack.of((EffectiveModelContext) root.getDataSchemaNode());
+        DataSchemaContextNode<?> node = root;
+        for (var arg : path.getPathArguments()) {
+            final var child = node.enterChild(arg, stack);
+            if (child == null) {
+                return CheckedValue.ofException(new IllegalArgumentException("Failed to find " + arg + " in " + node));
+            }
+            node = child;
+        }
+
+        return CheckedValue.ofValue(new NodeAndStack(node, stack));
     }
 
     public @NonNull DataSchemaContextNode<?> getRoot() {