From a35bc120deb6e129708040f381810bbb199b4a2d Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Fri, 12 Feb 2021 16:20:56 +0100 Subject: [PATCH] Add SchemaTreeInference SchemaTreeInference is a nice inference point, firmly rooted in RFC7950 concepts. Also wire it to SchemaInferenceStack, which can support it quite easily. JIRA: YANGTOOLS-1240 Change-Id: I746e5a4c17af3e4ca17c24dc15b7cb3533b48d8f Signed-off-by: Robert Varga --- yang/yang-model-api/pom.xml | 31 ++++++++ .../api/EffectiveStatementInference.java | 6 +- .../yang/model/api/SchemaTreeInference.java | 47 +++++++++++++ .../AbstractEffectiveStatementInference.java | 23 ++++-- .../model/spi/DefaultSchemaTreeInference.java | 70 +++++++++++++++++++ .../yang/model/util/SchemaInferenceStack.java | 34 ++++++++- 6 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaTreeInference.java create mode 100644 yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/DefaultSchemaTreeInference.java diff --git a/yang/yang-model-api/pom.xml b/yang/yang-model-api/pom.xml index bfb946bab1..d3589f4bb4 100644 --- a/yang/yang-model-api/pom.xml +++ b/yang/yang-model-api/pom.xml @@ -39,4 +39,35 @@ guava + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + apiNote + a + API Note: + + + implSpec + a + Implementation Requirements: + + + implNote + a + Implementation Note: + + + + + + + diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/EffectiveStatementInference.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/EffectiveStatementInference.java index fa4af32886..95e2e6416f 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/EffectiveStatementInference.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/EffectiveStatementInference.java @@ -21,9 +21,11 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; @Beta public interface EffectiveStatementInference extends EffectiveModelContextProvider, Immutable { /** - * An {@code Unmodifiable} {@link List} of {@link EffectiveStatement}s, ordered in some meaningful way. + * An {@code Unmodifiable} {@link List} of {@link EffectiveStatement}s, ordered in some meaningful way. Precise + * semantics of the statement order is clarified by individual {@link EffectiveStatementInference} specializations. * + * @see SchemaTreeInference * @return A List of EffectiveStatements */ - @NonNull List<@NonNull EffectiveStatement> statementPath(); + @NonNull List> statementPath(); } diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaTreeInference.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaTreeInference.java new file mode 100644 index 0000000000..004749bb6c --- /dev/null +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaTreeInference.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.model.api; + +import com.google.common.collect.ImmutableList; +import java.util.List; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement; + +/** + * An {@link EffectiveStatementInference} consisting purely of steps along the {@code schema tree} axis, so that it + * represents a {@code schema tree node} based on resolution of {@code absolute-schema-nodeid} as specified by + * RFC7950 section 6.5. + */ +public interface SchemaTreeInference extends EffectiveStatementInference { + /** + * {@inheritDoc} + * + *

+ * The statement path is always composed on {@link SchemaTreeEffectiveStatement}s and contains at least one element. + * The path is ordered from conceptual YANG root, i.e. the first element corresponds to the first element in + * {@link SchemaNodeIdentifier.Absolute#firstNodeIdentifier()}. + */ + @Override + List<@NonNull SchemaTreeEffectiveStatement> statementPath(); + + /** + * Return the {@link SchemaNodeIdentifier.Absolute} which resulted in this inference. + * + * @implSpec + * Default implementation interprets {@link #statementPath()}'s arguments as the ordered source of + * {@link SchemaNodeIdentifier.Absolute} steps. + * + * @return An absolute SchemaNodeIdentifier + */ + default SchemaNodeIdentifier.Absolute toSchemaNodeIdentifier() { + return SchemaNodeIdentifier.Absolute.of(statementPath().stream() + .map(SchemaTreeEffectiveStatement::argument) + .collect(ImmutableList.toImmutableList())); + } +} diff --git a/yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/AbstractEffectiveStatementInference.java b/yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/AbstractEffectiveStatementInference.java index 529f058fd1..8dd25e29e0 100644 --- a/yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/AbstractEffectiveStatementInference.java +++ b/yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/AbstractEffectiveStatementInference.java @@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.model.spi; import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.ImmutableList; import java.util.List; import org.eclipse.jdt.annotation.NonNull; @@ -18,27 +19,35 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; /** - * A simple capture of an {@link EffectiveModelContext} and a list of paths. No further guarantees are made. + * A simple capture of an {@link EffectiveModelContext} and a list of {@link EffectiveStatement}s. No further guarantees + * are made. + * + * @param T constituent {@link EffectiveStatement} type */ @Beta -public abstract class AbstractEffectiveStatementInference extends AbstractEffectiveModelContextProvider - implements EffectiveStatementInference { - private final @NonNull List> path; +public abstract class AbstractEffectiveStatementInference> + extends AbstractEffectiveModelContextProvider implements EffectiveStatementInference { + private final @NonNull List path; protected AbstractEffectiveStatementInference(final @NonNull EffectiveModelContext modelContext, - final @NonNull ImmutableList> path) { + final @NonNull ImmutableList path) { super(modelContext); this.path = requireNonNull(path); } protected AbstractEffectiveStatementInference(final @NonNull EffectiveModelContext modelContext, - final @NonNull List> path) { + final @NonNull List path) { super(modelContext); this.path = ImmutableList.copyOf(path); } @Override - public final List> statementPath() { + public final List statementPath() { return path; } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return super.addToStringAttributes(helper).add("statements", path); + } } diff --git a/yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/DefaultSchemaTreeInference.java b/yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/DefaultSchemaTreeInference.java new file mode 100644 index 0000000000..84c3f5f508 --- /dev/null +++ b/yang/yang-model-spi/src/main/java/org/opendaylight/yangtools/yang/model/spi/DefaultSchemaTreeInference.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.model.spi; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference; +import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement; +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; + +/** + * Default implementation of a a {@link SchemaTreeInference}. Guaranteed to be consistent with its + * {@link #getEffectiveModelContext()}. + */ +@Beta +@NonNullByDefault +public final class DefaultSchemaTreeInference + extends AbstractEffectiveStatementInference> implements SchemaTreeInference { + private DefaultSchemaTreeInference(final EffectiveModelContext modelContext, + final ImmutableList> path) { + super(modelContext, path); + } + + /** + * Create a new instance. + * + * @param modelContext Associated {@link EffectiveModelContext} + * @param path An absolute schema node identifier + * @return A new instance + */ + public static DefaultSchemaTreeInference of(final EffectiveModelContext modelContext, final Absolute path) { + final List steps = path.getNodeIdentifiers(); + final QName first = steps.get(0); + final ModuleEffectiveStatement module = modelContext.findModuleStatement(first.getModule()).orElseThrow( + () -> new IllegalArgumentException("No module for " + first)); + + final ImmutableList.Builder> builder = + ImmutableList.builderWithExpectedSize(steps.size()); + SchemaTreeAwareEffectiveStatement parent = module; + final Iterator it = steps.iterator(); + while (true) { + final QName qname = it.next(); + final SchemaTreeEffectiveStatement found = parent.findSchemaTreeNode(qname).orElseThrow( + () -> new IllegalArgumentException("Cannot resolve step " + qname + " in " + builder.build())); + if (it.hasNext()) { + checkArgument(found instanceof SchemaTreeAwareEffectiveStatement, "Cannot resolve steps %s past %s", + steps, found); + parent = (SchemaTreeAwareEffectiveStatement) found; + } else { + break; + } + } + + return new DefaultSchemaTreeInference(modelContext, builder.build()); + } +} diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java index 1ca82186d9..bbf05d54fe 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java @@ -31,6 +31,7 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider; import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement; @@ -42,6 +43,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absol import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement; import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveStatementInference; +import org.opendaylight.yangtools.yang.model.spi.DefaultSchemaTreeInference; /** * A state tracking utility for walking {@link EffectiveModelContext}'s contents along schema/grouping namespaces. This @@ -61,7 +63,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex * {@link #statementPath()} is implementation-specific. */ @Beta - public static final class Inference extends AbstractEffectiveStatementInference { + public static final class Inference extends AbstractEffectiveStatementInference> { private final ModuleEffectiveStatement currentModule; private final int groupingDepth; private final boolean clean; @@ -161,9 +163,25 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex public static @NonNull SchemaInferenceStack ofInference(final EffectiveStatementInference inference) { if (inference.statementPath().isEmpty()) { return new SchemaInferenceStack(inference.getEffectiveModelContext()); + } else if (inference instanceof SchemaTreeInference) { + return ofInference((SchemaTreeInference) inference); + } else if (inference instanceof Inference) { + return ((Inference) inference).toSchemaInferenceStack(); + } else { + throw new IllegalArgumentException("Unsupported Inference " + inference); } - checkArgument(inference instanceof Inference, "Inference %s not supported", inference); - return ((Inference) inference).toSchemaInferenceStack(); + } + + /** + * Create a new stack from an {@link SchemaTreeInference}. + * + * @param inference SchemaTreeInference to use for initialization + * @return A new stack + * @throws NullPointerException if {@code inference} is null + * @throws IllegalArgumentException if {@code inference} cannot be resolved to a valid stack + */ + public static @NonNull SchemaInferenceStack ofInference(final SchemaTreeInference inference) { + return of(inference.getEffectiveModelContext(), inference.toSchemaNodeIdentifier()); } /** @@ -356,6 +374,16 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex return new Inference(effectiveModel, deque.descendingIterator(), currentModule, groupingDepth, clean); } + /** + * Return an {@link SchemaTreeInference} equivalent of current state. + * + * @return An {@link SchemaTreeInference} + * @throws IllegalStateException if current state cannot be converted to a {@link SchemaTreeInference} + */ + public @NonNull SchemaTreeInference toSchemaTreeInference() { + return DefaultSchemaTreeInference.of(getEffectiveModelContext(), toSchemaNodeIdentifier()); + } + /** * Convert current state into an absolute schema node identifier. * -- 2.36.6