Add StmtContext.findFirstSubstatementArgument() 96/93496/11
authormiroslav.kovac <miroslav.kovac@pantheon.tech>
Fri, 30 Oct 2020 11:36:14 +0000 (12:36 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 30 Oct 2020 18:39:13 +0000 (19:39 +0100)
Introduce utility methods to StmtContext, so that individual
implementations can provide optimized version, which does not
walk all children.

InferredStatementContext used this facility to defer to protype,
side-stepping the need to materialize substatements.

JIRA: YANGTOOLS-1157
Change-Id: I9e618d3a51f68ed03a76c718b657be38e5cedb5d
Signed-off-by: miroslav.kovac <miroslav.kovac@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/augment/AbstractAugmentStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextDefaults.java [new file with mode: 0644]
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java

index 08b632cb808c05f0691bebdaaf14fc65f6b29926..88e491e265bffc8893c17b92ccee9a63b78e8b0d 100644 (file)
@@ -30,6 +30,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.OnDemandSchemaTreeStorageNode;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextDefaults;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -164,6 +165,30 @@ final class InferredStatementContext<A, D extends DeclaredStatement<A>, E extend
         return hasEmptyEffectiveSubstatements();
     }
 
+    @Override
+    public <X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgument(
+            final @NonNull Class<Z> type) {
+        if (substatementsInitialized()) {
+            return StmtContextDefaults.findSubstatementArgument(this, type);
+        }
+
+        final Optional<X> templateArg = prototype.findSubstatementArgument(type);
+        if (templateArg.isEmpty()) {
+            return templateArg;
+        }
+        if (SchemaTreeEffectiveStatement.class.isAssignableFrom(type)) {
+            // X is known to be QName
+            return (Optional<X>) templateArg.map(template -> ((QName) template).bindTo(targetModule));
+        }
+        return templateArg;
+    }
+
+    @Override
+    public boolean hasSubstatement(final @NonNull Class<? extends EffectiveStatement<?, ?>> type) {
+        return substatementsInitialized() ? StmtContextDefaults.hasSubstatement(prototype, type)
+            : prototype.hasSubstatement(type);
+    }
+
     @Override
     public <D extends DeclaredStatement<QName>, E extends EffectiveStatement<QName, D>>
             StmtContext<QName, D, E> requestSchemaTreeChild(final QName qname) {
index 3925f2204601c6a78f5c68dee17692d07516a49b..79b6bcde02798126084c2706fd575e69a7abb0f0 100644 (file)
@@ -32,6 +32,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement;
 import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace;
 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.ArgumentUtils;
@@ -242,7 +243,7 @@ abstract class AbstractAugmentStatementSupport
     }
 
     private static boolean hasWhenSubstatement(final StmtContext<?, ?, ?> ctx) {
-        return StmtContextUtils.findFirstSubstatement(ctx, WhenStatement.class) != null;
+        return ctx.hasSubstatement(WhenEffectiveStatement.class);
     }
 
     private static void copyStatement(final Mutable<?, ?, ?> original, final StatementContextBase<?, ?, ?> target,
index 2ca1a018e96ffeedea1144da799f317441f5f2bf..337a5fba1a64da4313e4a0b9e8c30d1a94dd133b 100644 (file)
@@ -391,4 +391,38 @@ public interface StmtContext<A, D extends DeclaredStatement<A>, E extends Effect
 
         void setIsSupportedToBuildEffective(boolean isSupportedToBuild);
     }
+
+    /**
+     * Search of any child statement context of specified type and return its argument. If such a statement exists, it
+     * is assumed to have the right argument. Users should be careful to use this method for statements which have
+     * cardinality {@code 0..1}, otherwise this method can return any one of the statement's argument.
+     *
+     * <p>
+     * The default implementation defers to
+     * {@link StmtContextDefaults#findSubstatementArgument(StmtContext, Class)}, subclasses are expected to provide
+     * optimized implementation if possible.
+     *
+     * @param <X> Substatement argument type
+     * @param <Z> Substatement effective statement representation
+     * @param type Effective statement representation being look up
+     * @return {@link Optional#empty()} if no statement exists, otherwise the argument value
+     */
+    default <X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgument(
+            final @NonNull Class<Z> type) {
+        return StmtContextDefaults.findSubstatementArgument(this, type);
+    }
+
+    /**
+     * Check if there is any child statement context of specified type.
+     *
+     * <p>
+     * The default implementation defers to {@link StmtContextDefaults#hasSubstatement(StmtContext, Class)},
+     * subclasses are expected to provide optimized implementation if possible.
+     *
+     * @param type Effective statement representation being look up
+     * @return True if such a child statement exists, false otherwise
+     */
+    default boolean hasSubstatement(final @NonNull Class<? extends EffectiveStatement<?, ?>> type) {
+        return StmtContextDefaults.hasSubstatement(this, type);
+    }
 }
diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextDefaults.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextDefaults.java
new file mode 100644 (file)
index 0000000..a5692a8
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 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.parser.spi.meta;
+
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+/**
+ * Default implementations for various {@link StmtContext} methods. Code hosted here is meant for use by actual
+ * {@link StmtContext} implementations, not for general use by others.
+ */
+public final class StmtContextDefaults {
+    private StmtContextDefaults() {
+        // Hidden on purpose
+    }
+
+    /**
+     * Default implementation of {@link StmtContext#findSubstatementArgument(Class)}. See that method for API contract.
+     *
+     * @param <A> Substatement argument type
+     * @param <E> Substatement effective statement representation
+     * @param stmt Statement context to search
+     * @param type Effective statement representation being look up
+     * @return Effective statement argument, if found
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static <A, E extends EffectiveStatement<A, ?>> @NonNull Optional<A> findSubstatementArgument(
+            final @NonNull StmtContext<?, ?, ?> stmt, final @NonNull Class<E> type) {
+        return stmt.allSubstatementsStream()
+                .filter(ctx -> ((StmtContext) ctx).producesEffective(type))
+                .findAny()
+                .map(ctx -> (A) ctx.coerceStatementArgument());
+    }
+
+    /**
+     * Default implementation of {@link StmtContext#hasSubstatement(Class)}. See that method for API contract.
+     *
+     * @param stmt Statement context to search
+     * @param type Effective statement representation being look up
+     * @return True if a match is found, false otherwise
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static boolean hasSubstatement(final @NonNull StmtContext<?, ?, ?> stmt,
+            @SuppressWarnings("rawtypes") final @NonNull Class<? extends EffectiveStatement<?, ?>> type) {
+        return stmt.allSubstatementsStream().anyMatch(ctx -> ((StmtContext) ctx).producesEffective(type));
+    }
+}
index 49a8ad589eb1520d83246ef23690385f9d62898c..4b1678e2d37d20a27f440220587c22e16728ee7a 100644 (file)
@@ -29,7 +29,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.PresenceStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PresenceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement;
@@ -148,7 +148,9 @@ public final class StmtContextUtils {
      * @param <A> statement argument type
      * @param <D> declared statement type
      * @return statement context that was searched for or null if was not found
+     * @deprecated Use {@link StmtContext#findSubstatementArgument(Class)} instead.
      */
+    @Deprecated(forRemoval = true)
     public static <A, D extends DeclaredStatement<A>> StmtContext<A, ?, ?> findFirstSubstatement(
             final StmtContext<?, ?, ?> stmtContext, final Class<D> declaredType) {
         final StmtContext<A, ?, ?> effectiveSubstatement = findFirstEffectiveSubstatement(stmtContext, declaredType);
@@ -286,7 +288,7 @@ public final class StmtContextUtils {
     }
 
     private static boolean containsPresenceSubStmt(final StmtContext<?, ?, ?> stmtCtx) {
-        return findFirstSubstatement(stmtCtx, PresenceStatement.class) != null;
+        return stmtCtx.hasSubstatement(PresenceEffectiveStatement.class);
     }
 
     /**
@@ -376,12 +378,9 @@ public final class StmtContextUtils {
         StmtContext<?, ?, ?> current = ctx.coerceParentContext();
         StmtContext<?, ?, ?> parent = current.getParentContext();
         while (parent != null) {
-            if (ancestorType.equals(current.getPublicDefinition())) {
-                @SuppressWarnings("unchecked")
-                final Class<D> ancestorChildTypeClass = (Class<D>) ancestorChildType.getDeclaredRepresentationClass();
-                if (findFirstSubstatement(current, ancestorChildTypeClass) == null) {
-                    return false;
-                }
+            if (ancestorType.equals(current.getPublicDefinition())
+                    && !current.hasSubstatement(ancestorChildType.getEffectiveRepresentationClass())) {
+                return false;
             }
 
             current = parent;