Add DataSchemaContextNode/SchemaInferenceStack integration
[yangtools.git] / data / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / DataSchemaContextTree.java
index 1a66488615db13892e747a172ee0225e60b39305..ccdd646082ef2dcf9053fc32de908dfc8956b5c1 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,6 +28,25 @@ import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveModelContextPr
  * @author Robert Varga
  */
 public final class DataSchemaContextTree extends AbstractEffectiveModelContextProvider {
+    // FIXME: record once we have JDK17+
+    public static final class NodeAndStack {
+        private final @NonNull DataSchemaContextNode<?> node;
+        private final @NonNull SchemaInferenceStack stack;
+
+        NodeAndStack(final DataSchemaContextNode<?> node, final @NonNull SchemaInferenceStack stack) {
+            this.node = requireNonNull(node);
+            this.stack = requireNonNull(stack);
+        }
+
+        public @NonNull DataSchemaContextNode<?> node() {
+            return node;
+        }
+
+        public @NonNull SchemaInferenceStack stack() {
+            return stack;
+        }
+    }
+
     private static final LoadingCache<EffectiveModelContext, @NonNull DataSchemaContextTree> TREES =
         CacheBuilder.newBuilder().weakKeys().weakValues().build(new CacheLoader<>() {
             @Override
@@ -54,6 +77,29 @@ public final class DataSchemaContextTree extends AbstractEffectiveModelContextPr
         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() {
         return root;
     }