Add SchemaInferenceStack.ofSchemaPath()
[yangtools.git] / model / yang-model-util / src / main / java / org / opendaylight / yangtools / yang / model / util / SchemaInferenceStack.java
index 86e026ecffa4c9a7026617d2d9e7cf29779da961..91610e67880b98740ba212baeae3229fb408c143 100644 (file)
@@ -55,6 +55,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveStatementInference;
@@ -244,7 +245,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
 
     /**
      * Create a new stack backed by an effective model, pointing to specified schema node identified by an absolute
-     * {@link SchemaPath} and its {@link SchemaPath#getPathFromRoot()}.
+     * {@link SchemaPath} and its {@link SchemaPath#getPathFromRoot()} interpreted as a schema node identifier.
      *
      * @param effectiveModel EffectiveModelContext to which this stack is attached
      * @return A new stack
@@ -261,6 +262,39 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
         return ret;
     }
 
+    /**
+     * Create a new stack backed by an effective model, pointing to specified schema node identified by an absolute
+     * {@link SchemaPath} and its {@link SchemaPath#getPathFromRoot()}, interpreted as a series of steps along primarily
+     * schema tree, with grouping namespace being the alternative lookup.
+     *
+     * @param effectiveModel EffectiveModelContext to which this stack is attached
+     * @return A new stack
+     * @throws NullPointerException {@code effectiveModel} is null
+     * @throws IllegalArgumentException if {@code path} cannot be resolved in the effective model or if it is not an
+     *                                  absolute path.
+     */
+    @Deprecated
+    public static @NonNull SchemaInferenceStack ofSchemaPath(final EffectiveModelContext effectiveModel,
+            final SchemaPath path) {
+        checkArgument(path.isAbsolute(), "Cannot operate on relative path %s", path);
+        final SchemaInferenceStack ret = new SchemaInferenceStack(effectiveModel);
+
+        for (QName step : path.getPathFromRoot()) {
+            try {
+                ret.enterSchemaTree(step);
+            } catch (IllegalArgumentException schemaEx) {
+                try {
+                    ret.enterGrouping(step);
+                } catch (IllegalArgumentException ex) {
+                    ex.addSuppressed(schemaEx);
+                    throw ex;
+                }
+            }
+        }
+
+        return ret;
+    }
+
     @Override
     public EffectiveModelContext getEffectiveModelContext() {
         return effectiveModel;
@@ -305,13 +339,24 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
     }
 
     /**
-     * Check if the stack is in instantiated context. This indicates the stack is non-empty and there is no grouping
-     * (or similar construct) present in the stack.
+     * Check if the stack is in instantiated context. This indicates the stack is non-empty and there are only screma
+     * tree statements in the stack.
      *
-     * @return False if the stack is empty or contains a grouping, true otherwise.
+     * @return False if the stack is empty or contains a statement which is not a {@link SchemaTreeEffectiveStatement},
+     *         true otherwise.
      */
     public boolean inInstantiatedContext() {
-        return groupingDepth == 0 && !deque.isEmpty();
+        return groupingDepth == 0 && !deque.isEmpty()
+            && deque.stream().allMatch(SchemaTreeEffectiveStatement.class::isInstance);
+    }
+
+    /**
+     * Check if the stack is in a {@code grouping} context.
+     *
+     * @return False if the stack contains a grouping.
+     */
+    public boolean inGrouping() {
+        return groupingDepth != 0;
     }
 
     /**
@@ -329,7 +374,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
      * {@link #enterSchemaTree(QName)}, except it handles the use case where traversal ignores actual {@code case}
      * intermediate schema tree children.
      *
-     * @param nodeIdentifier Node identifier of the grouping to enter
+     * @param nodeIdentifier Node identifier of the choice to enter
      * @return Resolved choice
      * @throws NullPointerException if {@code nodeIdentifier} is null
      * @throws IllegalArgumentException if the corresponding choice cannot be found
@@ -427,6 +472,18 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
         return pushData(requireNonNull(nodeIdentifier));
     }
 
+    /**
+     * Lookup a {@code typedef} by its node identifier and push it to the stack.
+     *
+     * @param nodeIdentifier Node identifier of the typedef to enter
+     * @return Resolved choice
+     * @throws NullPointerException if {@code nodeIdentifier} is null
+     * @throws IllegalArgumentException if the corresponding typedef cannot be found
+     */
+    public @NonNull TypedefEffectiveStatement enterTypedef(final QName nodeIdentifier) {
+        return pushTypedef(requireNonNull(nodeIdentifier));
+    }
+
     /**
      * Pop the current statement from the stack.
      *
@@ -457,7 +514,12 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
     public @NonNull DataTreeEffectiveStatement<?> exitToDataTree() {
         final EffectiveStatement<?, ?> child = exit();
         checkState(child instanceof DataTreeEffectiveStatement, "Unexpected current %s", child);
-        final EffectiveStatement<?, ?> parent = deque.peekFirst();
+        EffectiveStatement<?, ?> parent = deque.peekFirst();
+        while (parent instanceof ChoiceEffectiveStatement || parent instanceof CaseEffectiveStatement) {
+            deque.pollFirst();
+            parent = deque.peekFirst();
+        }
+
         checkState(parent == null || parent instanceof DataTreeAwareEffectiveStatement, "Unexpected parent %s", parent);
         return (DataTreeEffectiveStatement<?>) child;
     }
@@ -718,6 +780,29 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
         return ret;
     }
 
+    private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull QName nodeIdentifier) {
+        final EffectiveStatement<?, ?> parent = deque.peekFirst();
+        return parent != null ? pushTypedef(parent, nodeIdentifier) : pushFirstTypedef(nodeIdentifier);
+    }
+
+    private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull EffectiveStatement<?, ?> parent,
+            final @NonNull QName nodeIdentifier) {
+        // TODO: 8.0.0: revisit this once we have TypedefNamespace working
+        final TypedefEffectiveStatement ret = parent.streamEffectiveSubstatements(TypedefEffectiveStatement.class)
+            .filter(stmt -> nodeIdentifier.equals(stmt.argument()))
+            .findFirst()
+            .orElseThrow(() -> new IllegalArgumentException("Grouping " + nodeIdentifier + " not present"));
+        deque.push(ret);
+        return ret;
+    }
+
+    private @NonNull TypedefEffectiveStatement pushFirstTypedef(final @NonNull QName nodeIdentifier) {
+        final ModuleEffectiveStatement module = getModule(nodeIdentifier);
+        final TypedefEffectiveStatement ret = pushTypedef(module, nodeIdentifier);
+        currentModule = module;
+        return ret;
+    }
+
     private @NonNull ModuleEffectiveStatement getModule(final @NonNull QName nodeIdentifier) {
         final ModuleEffectiveStatement module = effectiveModel.getModuleStatements().get(nodeIdentifier.getModule());
         checkArgument(module != null, "Module for %s not found", nodeIdentifier);
@@ -756,6 +841,8 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
                 tmp.enterSchemaTree(((SchemaTreeEffectiveStatement<?> )stmt).argument());
             } else if (stmt instanceof GroupingEffectiveStatement) {
                 tmp.enterGrouping(((GroupingEffectiveStatement) stmt).argument());
+            } else if (stmt instanceof TypedefEffectiveStatement) {
+                tmp.enterTypedef(((TypedefEffectiveStatement) stmt).argument());
             } else {
                 throw new VerifyException("Unexpected statement " + stmt);
             }