import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.ArrayList;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.util.OptionalBoolean;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
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.IdentifierNamespace;
import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
import org.slf4j.LoggerFactory;
public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
- extends NamespaceStorageSupport implements StmtContext.Mutable<A, D, E> {
+ extends NamespaceStorageSupport implements Mutable<A, D, E> {
/**
- * event listener when an item is added to model namespace.
+ * Event listener when an item is added to model namespace.
*/
interface OnNamespaceItemAdded extends EventListener {
/**
- * @throws SourceException
+ * Invoked whenever a new item is added to a namespace.
*/
void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key, Object value);
}
/**
- * event listener when a parsing {@link ModelProcessingPhase} is completed.
+ * Event listener when a parsing {@link ModelProcessingPhase} is completed.
*/
interface OnPhaseFinished extends EventListener {
/**
- * @throws SourceException
+ * Invoked whenever a processing phase has finished.
*/
boolean phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase);
}
/**
- * interface for all mutations within an {@link ModelActionBuilder.InferenceAction}.
+ * Interface for all mutations within an {@link ModelActionBuilder.InferenceAction}.
*/
interface ContextMutation {
private final StatementDefinitionContext<A, D, E> definition;
private final StatementSourceReference statementDeclSource;
+ private final StmtContext<?, ?, ?> originalCtx;
+ private final CopyHistory copyHistory;
private final String rawArgument;
private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
private Collection<StmtContext<?, ?, ?>> effectOfStatement = ImmutableList.of();
private StatementMap substatements = StatementMap.empty();
- private Boolean supportedByFeatures = null;
- private CopyHistory copyHistory = CopyHistory.original();
private boolean isSupportedToBuildEffective = true;
private ModelProcessingPhase completedPhase = null;
- private StmtContext<?, ?, ?> originalCtx;
private D declaredInstance;
private E effectiveInstance;
- private int order = 0;
+
+ // BooleanFields value
+ private byte supportedByFeatures;
StatementContextBase(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
final String rawArgument) {
this.definition = Preconditions.checkNotNull(def);
this.statementDeclSource = Preconditions.checkNotNull(ref);
this.rawArgument = def.internArgument(rawArgument);
+ this.copyHistory = CopyHistory.original();
+ this.originalCtx = null;
}
- StatementContextBase(final StatementContextBase<A, D, E> original) {
+ StatementContextBase(final StatementContextBase<A, D, E> original, final CopyType copyType) {
this.definition = Preconditions.checkNotNull(original.definition,
"Statement context definition cannot be null copying from: %s", original.getStatementSourceReference());
this.statementDeclSource = Preconditions.checkNotNull(original.statementDeclSource,
"Statement context statementDeclSource cannot be null copying from: %s",
original.getStatementSourceReference());
this.rawArgument = original.rawArgument;
+ this.copyHistory = CopyHistory.of(copyType, original.getCopyHistory());
+ this.originalCtx = original.getOriginalCtx().orElse(original);
}
@Override
@Override
public boolean isSupportedByFeatures() {
- if (supportedByFeatures == null) {
- final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class,
- SupportedFeatures.SUPPORTED_FEATURES);
- // If the set of supported features has not been provided, all features are supported by default.
- supportedByFeatures = supportedFeatures == null ? Boolean.TRUE
- : StmtContextUtils.checkFeatureSupport(this, supportedFeatures);
+ if (OptionalBoolean.isPresent(supportedByFeatures)) {
+ return OptionalBoolean.get(supportedByFeatures);
+ }
+
+ if (isIgnoringIfFeatures()) {
+ supportedByFeatures = OptionalBoolean.of(true);
+ return true;
}
- return supportedByFeatures.booleanValue();
+ final boolean isParentSupported = isParentSupportedByFeatures();
+ /*
+ * If parent is not supported, then this context is also not supported.
+ * So we do not need to check if-features statements of this context and
+ * we can return false immediately.
+ */
+ if (!isParentSupported) {
+ supportedByFeatures = OptionalBoolean.of(false);
+ return false;
+ }
+
+ /*
+ * If parent is supported, we need to check if-features statements of
+ * this context.
+ */
+ // If the set of supported features has not been provided, all features are supported by default.
+ final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class,
+ SupportedFeatures.SUPPORTED_FEATURES);
+ final boolean ret = supportedFeatures == null ? true
+ : StmtContextUtils.checkFeatureSupport(this, supportedFeatures);
+
+ supportedByFeatures = OptionalBoolean.of(ret);
+ return ret;
}
+ protected abstract boolean isParentSupportedByFeatures();
+
+ protected abstract boolean isIgnoringIfFeatures();
+
+ protected abstract boolean isIgnoringConfig();
+
@Override
public boolean isSupportedToBuildEffective() {
return isSupportedToBuildEffective;
}
@Override
- public void appendCopyHistory(final CopyType typeOfCopy, final CopyHistory toAppend) {
- copyHistory = copyHistory.append(typeOfCopy, toAppend);
- }
-
- @Override
- public StmtContext<?, ?, ?> getOriginalCtx() {
- return originalCtx;
- }
-
- @Override
- public void setOriginalCtx(final StmtContext<?, ?, ?> originalCtx) {
- this.originalCtx = originalCtx;
- }
-
- @Override
- public void setOrder(final int order) {
- this.order = order;
- }
-
- @Override
- public int getOrder() {
- return order;
+ public Optional<StmtContext<?, ?, ?>> getOriginalCtx() {
+ return Optional.ofNullable(originalCtx);
}
@Override
public abstract StatementContextBase<?, ?, ?> getParentContext();
/**
+ * Returns the model root for this statement.
+ *
* @return root context of statement
*/
@Nonnull
public abstract RootStatementContext<?, ?, ?> getRoot();
/**
+ * Returns the origin of the statement.
+ *
* @return origin of statement
*/
@Nonnull
}
/**
+ * Returns a reference to statement source.
+ *
* @return reference of statement source
*/
@Nonnull
return Collections.unmodifiableCollection(effective);
}
- public void removeStatementsFromEffectiveSubstatements(final Collection<? extends StmtContext<?, ?, ?>> substatements) {
+ public void removeStatementsFromEffectiveSubstatements(
+ final Collection<? extends StmtContext<?, ?, ?>> substatements) {
if (!effective.isEmpty()) {
effective.removeAll(substatements);
shrinkEffective();
}
/**
- * Removes a statement context from the effective substatements
- * based on its statement definition (i.e statement keyword) and raw (in String form) statement argument.
- * The statement context is removed only if both statement definition and statement argument match with
- * one of the effective substatements' statement definition and argument.
+ * Removes a statement context from the effective substatements based on its statement definition (i.e statement
+ * keyword) and raw (in String form) statement argument. The statement context is removed only if both statement
+ * definition and statement argument match with one of the effective substatements' statement definition
+ * and argument.
*
+ * <p>
* If the statementArg parameter is null, the statement context is removed based only on its statement definition.
*
* @param statementDef statement definition of the statement context to remove
}
/**
- * adds effective statement to collection of substatements
+ * Adds an effective statement to collection of substatements.
*
* @param substatement substatement
* @throws IllegalStateException
}
/**
- * adds effective statement to collection of substatements
+ * Adds an effective statement to collection of substatements.
*
* @param substatements substatements
* @throws IllegalStateException
* @param argument statement argument
* @return A new substatement
*/
- public final <CA, CD extends DeclaredStatement<CA>, CE extends EffectiveStatement<CA, CD>> StatementContextBase<CA, CD, CE> createSubstatement(
- final int offset, final StatementDefinitionContext<CA, CD, CE> def, final StatementSourceReference ref,
- final String argument) {
+ public final <CA, CD extends DeclaredStatement<CA>, CE extends EffectiveStatement<CA, CD>>
+ StatementContextBase<CA, CD, CE> createSubstatement(final int offset,
+ final StatementDefinitionContext<CA, CD, CE> def, final StatementSourceReference ref,
+ final String argument) {
final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
Preconditions.checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
"Declared statement cannot be added in effective phase at: %s", getStatementSourceReference());
- final Optional<StatementContextBase<?, ?, ?>> implicitStatement = definition.beforeSubStatementCreated(this,
- offset, def, ref, argument);
- if(implicitStatement.isPresent()) {
- final StatementContextBase<?, ?, ?> presentImplicitStmt = implicitStatement.get();
- return presentImplicitStmt.createSubstatement(offset, def, ref, argument);
+ final Optional<StatementSupport<?, ?, ?>> implicitParent = definition.getImplicitParentFor(def.getPublicView());
+ if (implicitParent.isPresent()) {
+ return createImplicitParent(offset, implicitParent.get(), ref, argument).createSubstatement(offset, def,
+ ref, argument);
}
final StatementContextBase<CA, CD, CE> ret = new SubstatementContext<>(this, def, ref, argument);
return ret;
}
+ private StatementContextBase<?, ?, ?> createImplicitParent(final int offset,
+ final StatementSupport<?, ?, ?> implicitParent, final StatementSourceReference ref, final String argument) {
+ final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(implicitParent);
+ return createSubstatement(offset, def, ImplicitSubstatement.of(ref), argument);
+ }
+
/**
* Lookup substatement by its offset in this statement.
*
/**
* Ends declared section of current node.
- *
- * @param ref
- * @throws SourceException
*/
void endDeclared(final StatementSourceReference ref, final ModelProcessingPhase phase) {
definition().onDeclarationFinished(this, phase);
}
/**
+ * Return the context in which this statement was defined.
+ *
* @return statement definition
*/
protected final StatementDefinitionContext<A, D, E> definition() {
}
/**
- * adds {@link OnPhaseFinished} listener for a {@link ModelProcessingPhase} end
- *
- * @throws SourceException
+ * Adds {@link OnPhaseFinished} listener for a {@link ModelProcessingPhase} end.
*/
void addPhaseCompletedListener(final ModelProcessingPhase phase, final OnPhaseFinished listener) {
-
Preconditions.checkNotNull(phase, "Statement context processing phase cannot be null at: %s",
getStatementSourceReference());
Preconditions.checkNotNull(listener, "Statement context phase listener cannot be null at: %s",
}
/**
- * adds {@link ContextMutation} to {@link ModelProcessingPhase}
+ * Adds a {@link ContextMutation} to a {@link ModelProcessingPhase}.
*
* @throws IllegalStateException
* when the mutation was registered after phase was completed
void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
ModelProcessingPhase finishedPhase = completedPhase;
while (finishedPhase != null) {
- if (phase.equals(finishedPhase)) {
- throw new IllegalStateException("Mutation registered after phase was completed at: " +
- getStatementSourceReference());
- }
+ Preconditions.checkState(!phase.equals(finishedPhase),
+ "Mutation registered after phase was completed at: %s", getStatementSourceReference());
finishedPhase = finishedPhase.getPreviousPhase();
}
addContextToNamespace(namespace, key, stmt);
}
+ @Override
+ public <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> Mutable<X, Y, Z> childCopyOf(
+ final StmtContext<X, Y, Z> stmt, final CopyType type, final QNameModule targetModule) {
+ Preconditions.checkState(stmt.getCompletedPhase() == ModelProcessingPhase.EFFECTIVE_MODEL,
+ "Attempted to copy statement %s which has completed phase %s", stmt, stmt.getCompletedPhase());
+
+ Preconditions.checkArgument(stmt instanceof SubstatementContext, "Unsupported statement %s", stmt);
+
+ final SubstatementContext<X, Y, Z> original = (SubstatementContext<X, Y, Z>)stmt;
+ final SubstatementContext<X, Y, Z> copy = new SubstatementContext<>(original, this, type, targetModule);
+
+ original.definition().onStatementAdded(copy);
+ original.copyTo(copy, type, targetModule);
+
+ return copy;
+ }
+
+ final void copyTo(final StatementContextBase<?, ?, ?> target, final CopyType typeOfCopy,
+ @Nullable final QNameModule targetModule) {
+ final Collection<Mutable<?, ?, ?>> buffer = new ArrayList<>(substatements.size() + effective.size());
+
+ for (final Mutable<?, ?, ?> stmtContext : substatements.values()) {
+ if (stmtContext.isSupportedByFeatures()) {
+ copySubstatement(stmtContext, target, typeOfCopy, targetModule, buffer);
+ }
+ }
+
+ for (final Mutable<?, ?, ?> stmtContext : effective) {
+ copySubstatement(stmtContext, target, typeOfCopy, targetModule, buffer);
+ }
+
+ target.addEffectiveSubstatements(buffer);
+ }
+
+ private void copySubstatement(final Mutable<?, ?, ?> stmtContext, final Mutable<?, ?, ?> target,
+ final CopyType typeOfCopy, final QNameModule newQNameModule, final Collection<Mutable<?, ?, ?>> buffer) {
+ if (needToCopyByUses(stmtContext)) {
+ final Mutable<?, ?, ?> copy = target.childCopyOf(stmtContext, typeOfCopy, newQNameModule);
+ LOG.debug("Copying substatement {} for {} as", stmtContext, this, copy);
+ buffer.add(copy);
+ } else if (isReusedByUses(stmtContext)) {
+ LOG.debug("Reusing substatement {} for {}", stmtContext, this);
+ buffer.add(stmtContext);
+ } else {
+ LOG.debug("Skipping statement {}", stmtContext);
+ }
+ }
+
+ // FIXME: revise this, as it seems to be wrong
+ private static final Set<YangStmtMapping> NOCOPY_FROM_GROUPING_SET = ImmutableSet.of(
+ YangStmtMapping.DESCRIPTION,
+ YangStmtMapping.REFERENCE,
+ YangStmtMapping.STATUS);
+ private static final Set<YangStmtMapping> REUSED_DEF_SET = ImmutableSet.of(
+ YangStmtMapping.TYPE,
+ YangStmtMapping.TYPEDEF,
+ YangStmtMapping.USES);
+
+ private static boolean needToCopyByUses(final StmtContext<?, ?, ?> stmtContext) {
+ final StatementDefinition def = stmtContext.getPublicDefinition();
+ if (REUSED_DEF_SET.contains(def)) {
+ LOG.debug("Will reuse {} statement {}", def, stmtContext);
+ return false;
+ }
+ if (NOCOPY_FROM_GROUPING_SET.contains(def)) {
+ return !YangStmtMapping.GROUPING.equals(stmtContext.getParentContext().getPublicDefinition());
+ }
+
+ LOG.debug("Will copy {} statement {}", def, stmtContext);
+ return true;
+ }
+
+ private static boolean isReusedByUses(final StmtContext<?, ?, ?> stmtContext) {
+ return REUSED_DEF_SET.contains(stmtContext.getPublicDefinition());
+ }
+
@Override
public final String toString() {
return addToStringAttributes(MoreObjects.toStringHelper(this).omitNullValues()).toString();