Un-deprecate CopyableNode, AddedByUsesAware
[yangtools.git] / yang / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / AbstractStatementSupport.java
index fb2d0e32824e2b1c93a55c7db761f41ed525206d..c3ed5edfcbf82224b4667ca417a017d0ec9ef9d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ * 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,
  */
 package org.opendaylight.yangtools.yang.parser.spi.meta;
 
-import com.google.common.base.Preconditions;
-import java.util.Optional;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.QName;
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
 
 /**
- * Class providing necessary support for processing a YANG statement. This class is intended to be subclassed
- * by developers who want to add semantic support for a statement to a parser reactor.
+ * Baseline implementation class for common {@link StatementSupport} implementations. This class performs many of the
+ * its duties in the canonical way -- taking away some amount of freedom for common functionality.
  *
- * @param <A>
- *            Argument type
- * @param <D>
- *            Declared Statement representation
- * @param <E>
- *            Effective Statement representation
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @param <E> Effective Statement representation
  */
-public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
-        implements StatementDefinition, StatementFactory<A, D, E>, StatementSupport<A, D, E> {
-
-    private final StatementDefinition type;
-
-    protected AbstractStatementSupport(final StatementDefinition publicDefinition) {
-        Preconditions.checkArgument(publicDefinition != this);
-        this.type = Preconditions.checkNotNull(publicDefinition);
+@Beta
+public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>,
+        E extends EffectiveStatement<A, D>> extends StatementSupport<A, D, E> {
+    protected AbstractStatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
+        super(publicDefinition, policy);
     }
 
-    @Nonnull
     @Override
-    public final QName getStatementName() {
-        return type.getStatementName();
+    public final D createDeclared(final StmtContext<A, D, ?> ctx) {
+        final ImmutableList<? extends DeclaredStatement<?>> substatements = ctx.declaredSubstatements().stream()
+                .map(StmtContext::declared)
+                .collect(ImmutableList.toImmutableList());
+        return substatements.isEmpty() ? createEmptyDeclared(ctx) : createDeclared(ctx, substatements);
     }
 
-    @Override
-    public final QName getArgumentName() {
-        return type.getArgumentName();
-    }
+    protected abstract @NonNull D createDeclared(@NonNull StmtContext<A, D, ?> ctx,
+            @NonNull ImmutableList<? extends DeclaredStatement<?>> substatements);
 
-    @Nonnull
-    @Override
-    public final Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
-        return type.getDeclaredRepresentationClass();
-    }
-
-    @Nonnull
-    @Override
-    public final Class<? extends EffectiveStatement<?,?>> getEffectiveRepresentationClass() {
-        return type.getEffectiveRepresentationClass();
-    }
+    protected abstract @NonNull D createEmptyDeclared(@NonNull StmtContext<A, D, ?> ctx);
 
     @Override
-    public final StatementDefinition getPublicView() {
-        return type;
+    public final E createEffective(final Current<A, D> stmt,
+            final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
+            final Stream<? extends StmtContext<?, ?, ?>> inferredSubstatements) {
+        final ImmutableList<? extends EffectiveStatement<?, ?>> substatements =
+                buildEffectiveSubstatements(stmt, statementsToBuild(stmt,
+                    declaredSubstatements(declaredSubstatements, inferredSubstatements)));
+        return createEffective(stmt, substatements);
     }
 
-    @Override
-    public Optional<StatementSupport<?, ?, ?>> getImplicitParentFor(final StatementDefinition stmtDef) {
-        // NOOP for most implementations and also no implicit parent
-        return Optional.empty();
-    }
+    protected abstract @NonNull E createEffective(@NonNull Current<A, D> stmt,
+            @NonNull ImmutableList<? extends EffectiveStatement<?, ?>> substatements);
 
     @Override
-    public void onStatementAdded(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
+    public E copyEffective(final Current<A, D> stmt, final E original) {
+        // Most implementations are only interested in substatements. copyOf() here should be a no-op
+        return createEffective(stmt, ImmutableList.copyOf(original.effectiveSubstatements()));
     }
 
     /**
-     * {@inheritDoc}.
+     * Give statement support a hook to transform statement contexts before they are built. Default implementation
+     * does nothing, but note {@code augment} statement performs a real transformation.
      *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     * @param ctx Effective capture of this statement's significant state
+     * @param substatements Substatement contexts which have been determined to be built
+     * @return Substatement context which are to be actually built
      */
-    @Override
-    public void onPreLinkageDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
+    protected List<? extends StmtContext<?, ?, ?>> statementsToBuild(final Current<A, D> ctx,
+            final List<? extends StmtContext<?, ?, ?>> substatements) {
+        return substatements;
     }
 
-    /**
-     * {@inheritDoc}.
-     *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
-     */
-    @Override
-    public void onLinkageDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
+    // FIXME: add documentation
+    public static final <E extends EffectiveStatement<?, ?>> @Nullable E findFirstStatement(
+            final Collection<? extends EffectiveStatement<?, ?>> statements, final Class<E> type) {
+        for (EffectiveStatement<?, ?> stmt : statements) {
+            if (type.isInstance(stmt)) {
+                return type.cast(stmt);
+            }
+        }
+        return null;
     }
 
-    /**
-     * {@inheritDoc}.
-     *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
-     */
-    @Override
-    public void onStatementDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
+    // FIXME: add documentation
+    public static final <A, E extends EffectiveStatement<A, ?>> A findFirstArgument(
+            final Collection<? extends EffectiveStatement<?, ?>> statements, final Class<@NonNull E> type,
+                    final A defValue) {
+        final @Nullable E stmt = findFirstStatement(statements, type);
+        return stmt != null ? stmt.argument() : defValue;
     }
 
     /**
-     * {@inheritDoc}.
+     * Create a set of substatements. This method is split out so it can be overridden in subclasses adjust the
+     * resulting statements.
      *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     * @param stmt Current statement context
+     * @param substatements proposed substatements
+     * @return Built effective substatements
      */
-    @Override
-    public void onFullDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        final SubstatementValidator validator = getSubstatementValidator();
-        if (validator != null) {
-            validator.validate(stmt);
-        }
+    protected @NonNull ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
+            final Current<A, D> stmt, final List<? extends StmtContext<?, ?, ?>> substatements) {
+        return substatements.stream().map(StmtContext::buildEffective).collect(ImmutableList.toImmutableList());
     }
 
-    @Override
-    public boolean isArgumentYinElement() {
-        return getPublicView().isArgumentYinElement();
-    }
+    private static @NonNull List<StmtContext<?, ?, ?>> declaredSubstatements(
+            final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
+            final Stream<? extends StmtContext<?, ?, ?>> effectiveSubstatements) {
+        /*
+         * This dance is required to ensure that effects of 'uses' nodes are applied in the same order as
+         * the statements were defined -- i.e. if we have something like this:
+         *
+         * container foo {
+         *   uses bar;
+         *   uses baz;
+         * }
+         *
+         * grouping baz {
+         *   leaf baz {
+         *     type string;
+         *   }
+         * }
+         *
+         * grouping bar {
+         *   leaf bar {
+         *     type string;
+         *   }
+         * }
+         *
+         * The reactor would first inline 'uses baz' as that definition is the first one completely resolved and then
+         * inline 'uses bar'. Here we are iterating in declaration order re-inline the statements.
+         *
+         * FIXME: 7.0.0: this really should be handled by UsesStatementSupport such that 'uses baz' would have a
+         *               prerequisite of a resolved 'uses bar'.
+         */
+        final List<StmtContext<?, ?, ?>> declaredInit = declaredSubstatements
+            .filter(StmtContext::isSupportedByFeatures)
+            .collect(Collectors.toList());
+
+        final List<StmtContext<?, ?, ?>> substatementsInit = new ArrayList<>();
+        Set<StmtContext<?, ?, ?>> filteredStatements = null;
+        for (final StmtContext<?, ?, ?> declaredSubstatement : declaredInit) {
+            substatementsInit.add(declaredSubstatement);
+
+            // FIXME: YANGTOOLS-1161: we need to integrate this functionality into the reactor, so that this
+            //                        transformation is something reactor's declared statements already take into
+            //                        account.
+            final Collection<? extends StmtContext<?, ?, ?>> effect = declaredSubstatement.getEffectOfStatement();
+            if (!effect.isEmpty()) {
+                if (filteredStatements == null) {
+                    filteredStatements = new HashSet<>();
+                }
+                filteredStatements.addAll(effect);
+                // Note: we need to filter here to exclude unsupported statements
+                effect.stream().filter(StmtContext::isSupportedToBuildEffective).forEach(substatementsInit::add);
+            }
+        }
 
-    @Override
-    public boolean hasArgumentSpecificSupports() {
-        // Most of statement supports don't have any argument specific
-        // supports, so return 'false'.
-        return false;
-    }
+        final Stream<? extends StmtContext<?, ?, ?>> effective;
+        if (filteredStatements != null) {
+            final Set<StmtContext<?, ?, ?>> filtered = filteredStatements;
+            effective = effectiveSubstatements.filter(stmt -> !filtered.contains(stmt));
+        } else {
+            effective = effectiveSubstatements;
+        }
 
-    @Override
-    public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
-        // Most of statement supports don't have any argument specific
-        // supports, so return null.
-        return null;
+        substatementsInit.addAll(effective.collect(Collectors.toList()));
+        return substatementsInit;
     }
-
-    /**
-     * Returns corresponding substatement validator of a statement support.
-     *
-     * @return substatement validator or null, if substatement validator is not
-     *         defined
-     */
-    @Nullable
-    protected abstract SubstatementValidator getSubstatementValidator();
 }