/*
- * 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.
+ * 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.
*
- * This class is intended to be subclassed by developers, who want to
- * introduce support of statement to parser.
- *
- * @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();
- }
+ protected abstract @NonNull D createEmptyDeclared(@NonNull StmtContext<A, D, ?> ctx);
- @Nonnull
@Override
- public final Class<? extends EffectiveStatement<?,?>> getEffectiveRepresentationClass() {
- return type.getEffectiveRepresentationClass();
+ public 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 final StatementDefinition getPublicView() {
- return type;
- }
+ protected abstract @NonNull E createEffective(@NonNull Current<A, D> stmt,
+ @NonNull ImmutableList<? extends EffectiveStatement<?, ?>> substatements);
@Override
- public Optional<StatementSupport<?, ?, ?>> getImplicitParentFor(final StatementDefinition stmtDef) {
- // NOOP for most implementations and also no implicit parent
- return Optional.empty();
- }
-
- @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.
*
- * Subclasses of this class may override this method to perform actions on
- * this event or register 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}
- *
- * Subclasses of this class may override this method to perform actions on
- * this event or register 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}
- *
- * Subclasses of this class may override this method to perform actions on
- * this event or register 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.
*
- * Subclasses of this class may override this method to perform actions on
- * this event or register 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);
+ substatementsInit.addAll(effect);
+ }
+ }
- @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();
}