From: Robert Varga Date: Thu, 26 Oct 2023 19:30:37 +0000 (+0200) Subject: Modernize SchemaInferenceStack X-Git-Tag: v12.0.0~75 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=7f33d6b45cf6f17a502d546a41b0f9d2c767f7a1;p=yangtools.git Modernize SchemaInferenceStack Use local variable type inference and instanceof patterns to reduce the number of explicit type declarations and casts. Also (mostly) migrate away from verify()/checkState()/checkArgument(), exposing further branches that should be tested and a potentially-dead code. Change-Id: I656bdc230393f736f57b80f8256fd726079edf9e Signed-off-by: Robert Varga --- diff --git a/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java b/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java index 5ad2966934..f42464450f 100644 --- a/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java +++ b/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java @@ -8,7 +8,6 @@ package org.opendaylight.yangtools.yang.model.util; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Verify.verify; import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; @@ -22,15 +21,12 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.util.ArrayDeque; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; -import java.util.Optional; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.concepts.Mutable; import org.opendaylight.yangtools.rfc8040.model.api.YangDataEffectiveStatement; -import org.opendaylight.yangtools.yang.common.AbstractQName; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.common.UnresolvedQName.Unqualified; @@ -42,7 +38,6 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.PathExpression; import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps; import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps; -import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps; import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference; import org.opendaylight.yangtools.yang.model.api.Status; import org.opendaylight.yangtools.yang.model.api.TypeAware; @@ -69,8 +64,6 @@ import org.opendaylight.yangtools.yang.model.spi.DefaultSchemaTreeInference; import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStep; import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep; -import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step; -import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis; import org.slf4j.LoggerFactory; /** @@ -214,7 +207,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * @throws IllegalArgumentException if {@code path} cannot be resolved in the effective model */ public static @NonNull SchemaInferenceStack of(final EffectiveModelContext effectiveModel, final Absolute path) { - final SchemaInferenceStack ret = new SchemaInferenceStack(effectiveModel); + final var ret = new SchemaInferenceStack(effectiveModel); path.getNodeIdentifiers().forEach(ret::enterSchemaTree); return ret; } @@ -298,8 +291,8 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex */ public static @NonNull SchemaInferenceStack ofDataTreePath(final EffectiveModelContext effectiveModel, final QName... path) { - final SchemaInferenceStack ret = new SchemaInferenceStack(effectiveModel); - for (QName qname : path) { + final var ret = new SchemaInferenceStack(effectiveModel); + for (var qname : path) { ret.enterDataTree(qname); } return ret; @@ -432,14 +425,14 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * @throws IllegalArgumentException if the corresponding choice cannot be found */ public @NonNull ChoiceEffectiveStatement enterChoice(final QName nodeIdentifier) { - final QName nodeId = requireNonNull(nodeIdentifier); - final EffectiveStatement parent = deque.peekLast(); + final var nodeId = requireNonNull(nodeIdentifier); + final var parent = deque.peekLast(); if (parent instanceof ChoiceEffectiveStatement choice) { return enterChoice(choice, nodeId); } // Fall back to schema tree lookup. Note if it results in non-choice, we rewind before reporting an error - final SchemaTreeEffectiveStatement result = enterSchemaTree(nodeId); + final var result = enterSchemaTree(nodeId); if (result instanceof ChoiceEffectiveStatement choice) { return choice; } @@ -453,10 +446,10 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex // choice -> choice transition, we have to deal with intermediate case nodes private @NonNull ChoiceEffectiveStatement enterChoice(final @NonNull ChoiceEffectiveStatement parent, - final QName nodeIdentifier) { - for (EffectiveStatement stmt : parent.effectiveSubstatements()) { + final @NonNull QName nodeIdentifier) { + for (var stmt : parent.effectiveSubstatements()) { if (stmt instanceof CaseEffectiveStatement caze) { - final Optional optMatch = caze.findSchemaTreeNode(nodeIdentifier) + final var optMatch = caze.findSchemaTreeNode(nodeIdentifier) .filter(ChoiceEffectiveStatement.class::isInstance) .map(ChoiceEffectiveStatement.class::cast); if (optMatch.isPresent()) { @@ -507,7 +500,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex clear(); } - final Iterator it = nodeIdentifier.getNodeIdentifiers().iterator(); + final var it = nodeIdentifier.getNodeIdentifiers().iterator(); SchemaTreeEffectiveStatement ret; do { ret = enterSchemaTree(it.next()); @@ -550,15 +543,18 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * @throws IllegalStateException if this stack is not empty */ public @NonNull YangDataEffectiveStatement enterYangData(final YangDataName name) { - final EffectiveStatement parent = deque.peekLast(); - checkState(parent == null, "Cannot lookup yang-data in a non-empty stack"); + if (!isEmpty()) { + throw new IllegalStateException("Cannot lookup yang-data in a non-empty stack"); + } final var checkedName = requireNonNull(name); final var namespace = name.module(); - final ModuleEffectiveStatement module = effectiveModel.getModuleStatements().get(namespace); - checkArgument(module != null, "Module for %s not found", namespace); + final var module = effectiveModel.getModuleStatements().get(namespace); + if (module == null) { + throw new IllegalArgumentException("Module for " + namespace + " not found"); + } - final YangDataEffectiveStatement ret = module.streamEffectiveSubstatements(YangDataEffectiveStatement.class) + final var ret = module.streamEffectiveSubstatements(YangDataEffectiveStatement.class) .filter(stmt -> checkedName.equals(stmt.argument())) .findFirst() .orElseThrow( @@ -575,7 +571,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * @throws NoSuchElementException if this stack is empty */ public @NonNull EffectiveStatement exit() { - final EffectiveStatement prev = deque.removeLast(); + final var prev = deque.removeLast(); if (prev instanceof GroupingEffectiveStatement) { --groupingDepth; } @@ -596,29 +592,40 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * a {@link DataTreeAwareEffectiveStatement} */ public @NonNull DataTreeEffectiveStatement exitToDataTree() { - final EffectiveStatement child = exit(); - checkState(child instanceof DataTreeEffectiveStatement, "Unexpected current %s", child); - EffectiveStatement parent = deque.peekLast(); + final var child = exit(); + if (!(child instanceof DataTreeEffectiveStatement ret)) { + throw new IllegalStateException("Unexpected current " + child); + } + + var parent = deque.peekLast(); while (parent instanceof ChoiceEffectiveStatement || parent instanceof CaseEffectiveStatement) { deque.pollLast(); parent = deque.peekLast(); } - checkState(parent == null || parent instanceof DataTreeAwareEffectiveStatement, "Unexpected parent %s", parent); - return (DataTreeEffectiveStatement) child; + if (parent == null || parent instanceof DataTreeAwareEffectiveStatement) { + return ret; + } + throw new IllegalStateException("Unexpected parent " + parent); } @Override public TypeDefinition resolveLeafref(final LeafrefTypeDefinition type) { - final SchemaInferenceStack tmp = copy(); + final var tmp = copy(); - LeafrefTypeDefinition current = type; + var current = type; while (true) { - final EffectiveStatement resolved = tmp.resolvePathExpression(current.getPathStatement()); - checkState(resolved instanceof TypeAware, "Unexpected result %s resultion of %s", resolved, type); - final TypeDefinition result = ((TypedDataSchemaNode) resolved).getType(); + final var resolved = tmp.resolvePathExpression(current.getPathStatement()); + if (!(resolved instanceof TypeAware typeAware)) { + throw new IllegalStateException("Unexpected result " + resolved + " resultion of " + type); + } + + final var result = typeAware.getType(); if (result instanceof LeafrefTypeDefinition leafref) { - checkArgument(result != type, "Resolution of %s loops back onto itself via %s", type, current); + if (result == type) { + throw new IllegalArgumentException( + "Resolution of " + type + " loops back onto itself via " + current); + } current = leafref; } else { return result; @@ -639,7 +646,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * @throws VerifyException if path expression is invalid */ public @NonNull EffectiveStatement resolvePathExpression(final PathExpression path) { - final Steps steps = path.getSteps(); + final var steps = path.getSteps(); if (steps instanceof LocationPathSteps location) { return resolveLocationPath(location.getLocationPath()); } else if (steps instanceof DerefSteps deref) { @@ -650,16 +657,21 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } private @NonNull EffectiveStatement resolveDeref(final DerefSteps deref) { - final EffectiveStatement leafRefSchemaNode = currentStatement(); - final YangLocationPath.Relative derefArg = deref.getDerefArgument(); - final EffectiveStatement derefStmt = resolveLocationPath(derefArg); - checkArgument(derefStmt != null, "Cannot find deref(%s) target node %s in context of %s", - derefArg, leafRefSchemaNode); - checkArgument(derefStmt instanceof TypedDataSchemaNode, "deref(%s) resolved to non-typed %s", derefArg, - derefStmt); + final var leafRefSchemaNode = currentStatement(); + final var derefArg = deref.getDerefArgument(); + final var derefStmt = resolveLocationPath(derefArg); + if (derefStmt == null) { + // FIXME: dead code? + throw new IllegalArgumentException( + "Cannot find deref(" + derefArg + ") target node in context of %s" + leafRefSchemaNode); + } + if (!(derefStmt instanceof TypedDataSchemaNode typed)) { + throw new IllegalArgumentException( + "deref(" + derefArg + ") resolved to non-typed " + derefStmt + " in context of " + leafRefSchemaNode); + } // We have a deref() target, decide what to do about it - final TypeDefinition targetType = ((TypedDataSchemaNode) derefStmt).getType(); + final var targetType = typed.getType(); if (targetType instanceof InstanceIdentifierTypeDefinition) { // Static inference breaks down, we cannot determine where this points to // FIXME: dedicated exception, users can recover from it, derive from IAE @@ -667,10 +679,13 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } // deref() is defined only for instance-identifier and leafref types, handle the latter - checkArgument(targetType instanceof LeafrefTypeDefinition, "Illegal target type %s", targetType); + if (!(targetType instanceof LeafrefTypeDefinition leafref)) { + throw new IllegalArgumentException("Illegal target type " + targetType); + } - final PathExpression dereferencedLeafRefPath = ((LeafrefTypeDefinition) targetType).getPathStatement(); - EffectiveStatement derefNode = resolvePathExpression(dereferencedLeafRefPath); + final var dereferencedLeafRefPath = leafref.getPathStatement(); + final var derefNode = resolvePathExpression(dereferencedLeafRefPath); + // FIXME: revisit these checks checkArgument(derefStmt != null, "Can not find target node of dereferenced node %s", derefStmt); checkArgument(derefNode instanceof LeafSchemaNode, "Unexpected %s reference in %s", deref, dereferencedLeafRefPath); @@ -679,14 +694,14 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex private @NonNull EffectiveStatement resolveLocationPath(final YangLocationPath path) { // get the default namespace before we clear and loose our deque - final QNameModule defaultNamespace = deque.isEmpty() ? null : ((QName) deque.peekLast().argument()).getModule(); + final var defaultNamespace = deque.isEmpty() ? null : ((QName) deque.peekLast().argument()).getModule(); if (path.isAbsolute()) { clear(); } EffectiveStatement current = null; - for (Step step : path.getSteps()) { - final YangXPathAxis axis = step.getAxis(); + for (var step : path.getSteps()) { + final var axis = step.getAxis(); switch (axis) { case PARENT -> { verify(step instanceof AxisStep, "Unexpected parent step %s", step); @@ -697,8 +712,11 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } } case CHILD -> { - verify(step instanceof QNameStep, "Unexpected child step %s", step); - current = enterChild((QNameStep) step, defaultNamespace); + if (step instanceof QNameStep qnameStep) { + current = enterChild(qnameStep, defaultNamespace); + } else { + throw new VerifyException("Unexpected child step " + step); + } } default -> throw new VerifyException("Unexpected step " + step); } @@ -708,12 +726,14 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } private @NonNull EffectiveStatement enterChild(final QNameStep step, final QNameModule defaultNamespace) { - final AbstractQName toResolve = step.getQName(); + final var toResolve = step.getQName(); final QName qname; - if (toResolve instanceof QName) { - qname = (QName) toResolve; + if (toResolve instanceof QName qnameToResolve) { + qname = qnameToResolve; } else if (toResolve instanceof Unqualified unqual) { - checkArgument(defaultNamespace != null, "Can not find target module of step %s", step); + if (defaultNamespace == null) { + throw new IllegalArgumentException("Can not find target module of step " + step); + } qname = unqual.bindTo(defaultNamespace); } else { throw new VerifyException("Unexpected child step QName " + toResolve); @@ -737,7 +757,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * @throws IllegalStateException if current state cannot be converted to a {@link SchemaTreeInference} */ public @NonNull SchemaTreeInference toSchemaTreeInference() { - checkState(inInstantiatedContext(), "Cannot convert uninstantiated context %s", this); + checkInInstantiatedContext(); return DefaultSchemaTreeInference.unsafeOf(getEffectiveModelContext(), reconstructDeque().stream() .map(stmt -> (SchemaTreeEffectiveStatement) stmt) .collect(ImmutableList.toImmutableList())); @@ -754,23 +774,29 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * @throws IllegalStateException if current state is not instantiated */ public @NonNull Absolute toSchemaNodeIdentifier() { - checkState(inInstantiatedContext(), "Cannot convert uninstantiated context %s", this); + checkInInstantiatedContext(); return Absolute.of(simplePathFromRoot()); } + private void checkInInstantiatedContext() { + if (!inInstantiatedContext()) { + throw new IllegalStateException("Cannot convert uninstantiated context " + this); + } + } + @Override public String toString() { return MoreObjects.toStringHelper(this).add("path", deque).toString(); } private @NonNull GroupingEffectiveStatement pushGrouping(final @NonNull QName nodeIdentifier) { - final EffectiveStatement parent = deque.peekLast(); + final var parent = deque.peekLast(); return parent != null ? pushGrouping(parent, nodeIdentifier) : pushFirstGrouping(nodeIdentifier); } private @NonNull GroupingEffectiveStatement pushGrouping(final @NonNull EffectiveStatement parent, final @NonNull QName nodeIdentifier) { - final GroupingEffectiveStatement ret = parent.streamEffectiveSubstatements(GroupingEffectiveStatement.class) + final var ret = parent.streamEffectiveSubstatements(GroupingEffectiveStatement.class) .filter(stmt -> nodeIdentifier.equals(stmt.argument())) .findFirst() .orElseThrow(() -> notPresent(parent, "Grouping", nodeIdentifier)); @@ -780,52 +806,56 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } private @NonNull GroupingEffectiveStatement pushFirstGrouping(final @NonNull QName nodeIdentifier) { - final ModuleEffectiveStatement module = getModule(nodeIdentifier); - final GroupingEffectiveStatement ret = pushGrouping(module, nodeIdentifier); + final var module = getModule(nodeIdentifier); + final var ret = pushGrouping(module, nodeIdentifier); currentModule = module; return ret; } private @NonNull SchemaTreeEffectiveStatement pushSchema(final @NonNull QName nodeIdentifier) { - final EffectiveStatement parent = deque.peekLast(); + final var parent = deque.peekLast(); return parent != null ? pushSchema(parent, nodeIdentifier) : pushFirstSchema(nodeIdentifier); } private @NonNull SchemaTreeEffectiveStatement pushSchema(final EffectiveStatement parent, final @NonNull QName nodeIdentifier) { - checkState(parent instanceof SchemaTreeAwareEffectiveStatement, "Cannot descend schema tree at %s", parent); - return pushSchema((SchemaTreeAwareEffectiveStatement) parent, nodeIdentifier); + if (parent instanceof SchemaTreeAwareEffectiveStatement schemaTreeParent) { + return pushSchema(schemaTreeParent, nodeIdentifier); + } + throw new IllegalStateException("Cannot descend schema tree at " + parent); } private @NonNull SchemaTreeEffectiveStatement pushSchema( final @NonNull SchemaTreeAwareEffectiveStatement parent, final @NonNull QName nodeIdentifier) { - final SchemaTreeEffectiveStatement ret = parent.findSchemaTreeNode(nodeIdentifier) + final var ret = parent.findSchemaTreeNode(nodeIdentifier) .orElseThrow(() -> notPresent(parent, "Schema tree child ", nodeIdentifier)); deque.addLast(ret); return ret; } private @NonNull SchemaTreeEffectiveStatement pushFirstSchema(final @NonNull QName nodeIdentifier) { - final ModuleEffectiveStatement module = getModule(nodeIdentifier); - final SchemaTreeEffectiveStatement ret = pushSchema(module, nodeIdentifier); + final var module = getModule(nodeIdentifier); + final var ret = pushSchema(module, nodeIdentifier); currentModule = module; return ret; } private @NonNull DataTreeEffectiveStatement pushData(final @NonNull QName nodeIdentifier) { - final EffectiveStatement parent = deque.peekLast(); + final var parent = deque.peekLast(); return parent != null ? pushData(parent, nodeIdentifier) : pushFirstData(nodeIdentifier); } private @NonNull DataTreeEffectiveStatement pushData(final EffectiveStatement parent, final @NonNull QName nodeIdentifier) { - checkState(parent instanceof DataTreeAwareEffectiveStatement, "Cannot descend data tree at %s", parent); - return pushData((DataTreeAwareEffectiveStatement) parent, nodeIdentifier); + if (parent instanceof DataTreeAwareEffectiveStatement dataTreeParent) { + return pushData(dataTreeParent, nodeIdentifier); + } + throw new IllegalStateException("Cannot descend data tree at " + parent); } private @NonNull DataTreeEffectiveStatement pushData(final @NonNull DataTreeAwareEffectiveStatement parent, final @NonNull QName nodeIdentifier) { - final DataTreeEffectiveStatement ret = parent.findDataTreeNode(nodeIdentifier) + final var ret = parent.findDataTreeNode(nodeIdentifier) .orElseThrow(() -> notPresent(parent, "Data tree child", nodeIdentifier)); deque.addLast(ret); clean = false; @@ -833,21 +863,21 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } private @NonNull DataTreeEffectiveStatement pushFirstData(final @NonNull QName nodeIdentifier) { - final ModuleEffectiveStatement module = getModule(nodeIdentifier); - final DataTreeEffectiveStatement ret = pushData(module, nodeIdentifier); + final var module = getModule(nodeIdentifier); + final var ret = pushData(module, nodeIdentifier); currentModule = module; return ret; } private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull QName nodeIdentifier) { - final EffectiveStatement parent = deque.peekLast(); + final var parent = deque.peekLast(); return parent != null ? pushTypedef(parent, nodeIdentifier) : pushFirstTypedef(nodeIdentifier); } private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull EffectiveStatement parent, final @NonNull QName nodeIdentifier) { if (parent instanceof TypedefAwareEffectiveStatement aware) { - final TypedefEffectiveStatement ret = aware.findTypedef(nodeIdentifier) + final var ret = aware.findTypedef(nodeIdentifier) .orElseThrow(() -> notPresent(parent, "Typedef", nodeIdentifier)); deque.addLast(ret); return ret; @@ -856,15 +886,17 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } private @NonNull TypedefEffectiveStatement pushFirstTypedef(final @NonNull QName nodeIdentifier) { - final ModuleEffectiveStatement module = getModule(nodeIdentifier); - final TypedefEffectiveStatement ret = pushTypedef(module, nodeIdentifier); + final var module = getModule(nodeIdentifier); + final var 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); + final var module = effectiveModel.getModuleStatements().get(nodeIdentifier.getModule()); + if (module == null) { + throw new IllegalArgumentException("Module for " + nodeIdentifier + " not found"); + } return module; } @@ -876,9 +908,10 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex private Collection qnames() { return Collections2.transform(deque, stmt -> { - final Object argument = stmt.argument(); - verify(argument instanceof QName, "Unexpected statement %s", stmt); - return (QName) argument; + if (stmt.argument() instanceof QName qname) { + return qname; + } + throw new VerifyException("Unexpected statement " + stmt); }); } @@ -891,8 +924,8 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex private SchemaInferenceStack reconstructSchemaInferenceStack() { // Let's walk all statements and decipher them into a temporary stack - final SchemaInferenceStack tmp = new SchemaInferenceStack(effectiveModel, deque.size()); - for (EffectiveStatement stmt : deque) { + final var tmp = new SchemaInferenceStack(effectiveModel, deque.size()); + for (var stmt : deque) { // Order of checks is significant if (stmt instanceof DataTreeEffectiveStatement dataTree) { tmp.resolveDataTreeSteps(dataTree.argument()); @@ -918,7 +951,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } private void resolveChoiceSteps(final @NonNull QName nodeIdentifier) { - final EffectiveStatement parent = deque.peekLast(); + final var parent = deque.peekLast(); if (parent instanceof ChoiceEffectiveStatement choice) { resolveChoiceSteps(choice, nodeIdentifier); } else { @@ -928,10 +961,9 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex private void resolveChoiceSteps(final @NonNull ChoiceEffectiveStatement parent, final @NonNull QName nodeIdentifier) { - for (EffectiveStatement stmt : parent.effectiveSubstatements()) { + for (var stmt : parent.effectiveSubstatements()) { if (stmt instanceof CaseEffectiveStatement caze) { - final SchemaTreeEffectiveStatement found = caze.findSchemaTreeNode(nodeIdentifier).orElse(null); - if (found instanceof ChoiceEffectiveStatement) { + if (caze.findSchemaTreeNode(nodeIdentifier).orElse(null) instanceof ChoiceEffectiveStatement found) { deque.addLast(caze); deque.addLast(found); return; @@ -942,16 +974,16 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex } private void resolveDataTreeSteps(final @NonNull QName nodeIdentifier) { - final EffectiveStatement parent = deque.peekLast(); - if (parent != null) { - verify(parent instanceof SchemaTreeAwareEffectiveStatement, "Unexpected parent %s", parent); - resolveDataTreeSteps((SchemaTreeAwareEffectiveStatement) parent, nodeIdentifier); - return; + final var parent = deque.peekLast(); + if (parent == null) { + final var module = getModule(nodeIdentifier); + resolveDataTreeSteps(module, nodeIdentifier); + currentModule = module; + } else if (parent instanceof SchemaTreeAwareEffectiveStatement schemaTreeParent) { + resolveDataTreeSteps(schemaTreeParent, nodeIdentifier); + } else { + throw new VerifyException("Unexpected parent " + parent); } - - final ModuleEffectiveStatement module = getModule(nodeIdentifier); - resolveDataTreeSteps(module, nodeIdentifier); - currentModule = module; } private void resolveDataTreeSteps(final @NonNull SchemaTreeAwareEffectiveStatement parent, @@ -963,7 +995,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex // that implies that a data tree parent must satisfy schema tree queries with data tree children, // so a successful lookup of 'data tree parent -> child' and 'schema tree parent -> child' has to be the same // for a direct lookup. - final SchemaTreeEffectiveStatement found = parent.findSchemaTreeNode(nodeIdentifier).orElse(null); + final var found = parent.findSchemaTreeNode(nodeIdentifier).orElse(null); if (found instanceof DataTreeEffectiveStatement) { // ... and it did, we are done deque.addLast(found); @@ -973,7 +1005,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex // Alright, so now it's down to filtering choice/case statements. For that we keep some globally-reused state // and employ a recursive match. final var match = new ArrayDeque>(); - for (EffectiveStatement stmt : parent.effectiveSubstatements()) { + for (var stmt : parent.effectiveSubstatements()) { if (stmt instanceof ChoiceEffectiveStatement choice && searchChoice(match, choice, nodeIdentifier)) { deque.addAll(match); return; @@ -986,7 +1018,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex private static boolean searchCase(final @NonNull ArrayDeque> result, final @NonNull CaseEffectiveStatement parent, final @NonNull QName nodeIdentifier) { result.addLast(parent); - for (EffectiveStatement stmt : parent.effectiveSubstatements()) { + for (var stmt : parent.effectiveSubstatements()) { if (stmt instanceof DataTreeEffectiveStatement dataTree && nodeIdentifier.equals(stmt.argument())) { result.addLast(dataTree); return true; @@ -1002,7 +1034,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex private static boolean searchChoice(final @NonNull ArrayDeque> result, final @NonNull ChoiceEffectiveStatement parent, final @NonNull QName nodeIdentifier) { result.addLast(parent); - for (EffectiveStatement stmt : parent.effectiveSubstatements()) { + for (var stmt : parent.effectiveSubstatements()) { if (stmt instanceof CaseEffectiveStatement caze && searchCase(result, caze, nodeIdentifier)) { return true; } @@ -1034,8 +1066,8 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex return "module " + module.argument().bindTo(module.localQNameModule()); } else { // Shorthand for QNames, should provide enough context - final Object arg = parent.argument(); - return "parent " + (arg instanceof QName ? arg : parent); + final var arg = parent.argument(); + return "parent " + (arg instanceof QName qname ? qname : parent); } } } diff --git a/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStackTest.java b/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStackTest.java index ccf51e90f8..7694d771e7 100644 --- a/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStackTest.java +++ b/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStackTest.java @@ -14,10 +14,12 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.Revision; import org.opendaylight.yangtools.yang.common.XMLNamespace; @@ -33,53 +35,77 @@ import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis; +@ExtendWith(MockitoExtension.class) class SchemaInferenceStackTest { - private static EffectiveModelContext context; + static final EffectiveModelContext CONTEXT = YangParserTestUtils.parseYangResourceDirectory("/schema-context-util"); + private static Module myModule; + @Mock + private PathExpression expr; + @BeforeAll - static void beforeClass() { - context = YangParserTestUtils.parseYangResourceDirectory("/schema-context-util"); - myModule = context.findModule(XMLNamespace.of("uri:my-module"), Revision.of("2014-10-07")).orElseThrow(); + static void beforeAll() { + myModule = CONTEXT.findModule(XMLNamespace.of("uri:my-module"), Revision.of("2014-10-07")).orElseThrow(); } @Test void findDataSchemaNodeTest() { - final var importedModule = context.findModule(XMLNamespace.of("uri:imported-module"), + final var importedModule = CONTEXT.findModule(XMLNamespace.of("uri:imported-module"), Revision.of("2014-10-07")).orElseThrow(); - final QName myImportedContainer = QName.create(importedModule.getQNameModule(), "my-imported-container"); - final QName myImportedLeaf = QName.create(importedModule.getQNameModule(), "my-imported-leaf"); + final var myImportedContainer = QName.create(importedModule.getQNameModule(), "my-imported-container"); + final var myImportedLeaf = QName.create(importedModule.getQNameModule(), "my-imported-leaf"); final var testNode = assertInstanceOf(ContainerSchemaNode.class, importedModule.getDataChildByName(myImportedContainer)).getDataChildByName(myImportedLeaf); - final var expr = mock(PathExpression.class); - doReturn(true).when(expr).isAbsolute(); doReturn(new LocationPathSteps(YangLocationPath.absolute( YangXPathAxis.CHILD.asStep(myImportedContainer), YangXPathAxis.CHILD.asStep(myImportedLeaf)))) .when(expr).getSteps(); - assertEquals(testNode, SchemaInferenceStack.of(context).resolvePathExpression(expr)); + assertEquals(testNode, SchemaInferenceStack.of(CONTEXT).resolvePathExpression(expr)); } @Test void findDataSchemaNodeTest2() { - final QName myLeafInGrouping2 = QName.create(myModule.getQNameModule(), "my-leaf-in-gouping2"); - final var expr = mock(PathExpression.class); - doReturn(true).when(expr).isAbsolute(); + final var myLeafInGrouping2 = QName.create(myModule.getQNameModule(), "my-leaf-in-gouping2"); doReturn(new LocationPathSteps(YangLocationPath.relative(YangXPathAxis.CHILD.asStep(myLeafInGrouping2)))) .when(expr).getSteps(); final var grouping = getGroupingByName(myModule, "my-grouping"); - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); assertSame(grouping, stack.enterGrouping(grouping.getQName())); assertEquals(grouping.getDataChildByName(myLeafInGrouping2), stack.resolvePathExpression(expr)); } + @Test + void enterDataTreeNegativeTest() { + final var stack = SchemaInferenceStack.of(CONTEXT); + final var myContainer = QName.create(myModule.getQNameModule(), "my-container"); + stack.enterDataTree(myContainer); + assertNotNull(stack.enterTypedef(QName.create(myModule.getQNameModule(), "my-typedef-in-container"))); + final var ex = assertThrows(IllegalStateException.class, () -> stack.enterDataTree(myContainer)); + assertEquals("Cannot descend data tree at " + + "TypedefEffectiveStatementImpl{argument=(uri:my-module?revision=2014-10-07)my-typedef-in-container}", + ex.getMessage()); + } + + @Test + void enterSchemaTreeNegativeTest() { + final var stack = SchemaInferenceStack.of(CONTEXT); + final var myContainer = QName.create(myModule.getQNameModule(), "my-container"); + stack.enterDataTree(myContainer); + assertNotNull(stack.enterTypedef(QName.create(myModule.getQNameModule(), "my-typedef-in-container"))); + final var ex = assertThrows(IllegalStateException.class, () -> stack.enterSchemaTree(myContainer)); + assertEquals("Cannot descend schema tree at " + + "TypedefEffectiveStatementImpl{argument=(uri:my-module?revision=2014-10-07)my-typedef-in-container}", + ex.getMessage()); + } + @Test void enterGroupingNegativeTest() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); assertNotExistentGrouping(stack, "module (uri:my-module?revision=2014-10-07)my-module"); stack.enterDataTree(QName.create(myModule.getQNameModule(), "my-container")); assertNotExistentGrouping(stack, "schema parent (uri:my-module?revision=2014-10-07)my-container"); @@ -87,14 +113,15 @@ class SchemaInferenceStackTest { @Test void enterNestedTypedefTest() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); stack.enterDataTree(QName.create(myModule.getQNameModule(), "my-container")); assertNotNull(stack.enterTypedef(QName.create(myModule.getQNameModule(), "my-typedef-in-container"))); + assertNotExistentTypedef(stack, "parent (uri:my-module?revision=2014-10-07)my-typedef-in-container"); } @Test void enterTypedefNegativeTest() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); assertNotExistentTypedef(stack, "module (uri:my-module?revision=2014-10-07)my-module"); stack.enterDataTree(QName.create(myModule.getQNameModule(), "my-container")); assertNotExistentTypedef(stack, "schema parent (uri:my-module?revision=2014-10-07)my-container"); @@ -102,20 +129,20 @@ class SchemaInferenceStackTest { @Test void rootIsCurrent() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); assertEquals(Status.CURRENT, stack.effectiveStatus()); } @Test void myGroupingIsCurrent() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); stack.enterGrouping(QName.create(myModule.getQNameModule(), "my-grouping")); assertEquals(Status.CURRENT, stack.effectiveStatus()); } @Test void myLeafInContainerIsDeprecated() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); stack.enterDataTree(QName.create(myModule.getQNameModule(), "my-container")); stack.enterDataTree(QName.create(myModule.getQNameModule(), "my-leaf-in-container")); assertEquals(Status.DEPRECATED, stack.effectiveStatus()); @@ -123,7 +150,7 @@ class SchemaInferenceStackTest { @Test void twoInGroupingIsObsolete() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); stack.enterGrouping(QName.create(myModule.getQNameModule(), "my-name")); stack.enterDataTree(QName.create(myModule.getQNameModule(), "two")); assertEquals(Status.OBSOLETE, stack.effectiveStatus()); @@ -131,7 +158,7 @@ class SchemaInferenceStackTest { @Test void twoInMyNameInputIsObsolete() { - final var stack = SchemaInferenceStack.of(context); + final var stack = SchemaInferenceStack.of(CONTEXT); stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "my-name")); stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "input")); stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "my-choice")); @@ -141,20 +168,20 @@ class SchemaInferenceStackTest { } private static void assertNotExistentGrouping(final SchemaInferenceStack stack, final String parentDesc) { - final QName nonExistent = QName.create(myModule.getQNameModule(), "non-existent"); + final var nonExistent = QName.create(myModule.getQNameModule(), "non-existent"); assertEquals("Grouping (uri:my-module?revision=2014-10-07)non-existent not present in " + parentDesc, assertThrows(IllegalArgumentException.class, () -> stack.enterGrouping(nonExistent)).getMessage()); } private static void assertNotExistentTypedef(final SchemaInferenceStack stack, final String parentDesc) { - final QName nonExistent = QName.create(myModule.getQNameModule(), "non-existent"); + final var nonExistent = QName.create(myModule.getQNameModule(), "non-existent"); assertEquals("Typedef (uri:my-module?revision=2014-10-07)non-existent not present in " + parentDesc, assertThrows(IllegalArgumentException.class, () -> stack.enterTypedef(nonExistent)).getMessage()); } private static GroupingDefinition getGroupingByName(final DataNodeContainer dataNodeContainer, final String name) { for (var grouping : dataNodeContainer.getGroupings()) { - if (grouping.getQName().getLocalName().equals(name)) { + if (name.equals(grouping.getQName().getLocalName())) { return grouping; } } diff --git a/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1414Test.java b/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1414Test.java index 2f0ef53746..084f6c5123 100644 --- a/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1414Test.java +++ b/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1414Test.java @@ -30,8 +30,10 @@ class YT1414Test { @Test void testToFromSchemaTreeInference() { - final var stack = SchemaInferenceStack.of( - YangParserTestUtils.parseYangResourceDirectory("/schema-context-util")); + final var stack = SchemaInferenceStack.of(SchemaInferenceStackTest.CONTEXT); + final var ex = assertThrows(IllegalStateException.class, stack::toSchemaTreeInference); + assertEquals("Cannot convert uninstantiated context SchemaInferenceStack{path=[]}", ex.getMessage()); + stack.enterSchemaTree(MY_LIST_ID); final var inference = assertInstanceOf(DefaultSchemaTreeInference.class, stack.toSchemaTreeInference()); assertEquals(MY_LIST_ID, inference.toSchemaNodeIdentifier());