package org.opendaylight.yangtools.yang.parser.stmt.reactor;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
+import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import java.util.Optional;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.yang.common.QNameModule;
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.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
import org.opendaylight.yangtools.yang.parser.spi.meta.ImplicitParentAwareStatementSupport;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.ExecutionOrder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
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.StatementSupport.CopyPolicy;
* @param <E> Effective Statement representation
*/
public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
- extends ReactorStmtCtx<A, D, E> {
+ extends ReactorStmtCtx<A, D, E> implements CopyHistory {
/**
* Event listener when an item is added to model namespace.
*/
private static final Logger LOG = LoggerFactory.getLogger(StatementContextBase.class);
- private final CopyHistory copyHistory;
+ //
+ // {@link CopyHistory} encoded as a single byte. We still have 4 bits unused.
+ //
+ private static final byte COPY_LAST_TYPE_MASK = 0x03;
+ private static final byte COPY_ADDED_BY_USES = 0x04;
+ private static final byte COPY_ADDED_BY_AUGMENTATION = 0x08;
+ private static final byte COPY_ORIGINAL = 0x00;
+
+ private final byte copyHistory;
+
+ static {
+ final int copyTypes = CopyType.values().length;
+ // This implies CopyType.ordinal() is <= COPY_TYPE_MASK
+ verify(copyTypes == COPY_LAST_TYPE_MASK + 1, "Unexpected %s CopyType values", copyTypes);
+ }
+
// Note: this field can strictly be derived in InferredStatementContext, but it forms the basis of many of our
// operations, hence we want to keep it close by.
private final @NonNull StatementDefinitionContext<A, D, E> definition;
+ // TODO: consider keying by Byte equivalent of ExecutionOrder
private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = ImmutableMultimap.of();
private List<StmtContext<?, ?, ?>> effectOfStatement = ImmutableList.of();
- private @Nullable ModelProcessingPhase completedPhase;
+ /**
+ * {@link ModelProcessingPhase.ExecutionOrder} value of current {@link ModelProcessingPhase} of this statement.
+ */
+ private byte executionOrder;
// Copy constructor used by subclasses to implement reparent()
StatementContextBase(final StatementContextBase<A, D, E> original) {
super(original);
this.copyHistory = original.copyHistory;
this.definition = original.definition;
- this.completedPhase = original.completedPhase;
+ this.executionOrder = original.executionOrder;
}
StatementContextBase(final StatementDefinitionContext<A, D, E> def) {
this.definition = requireNonNull(def);
- this.copyHistory = CopyHistory.original();
+ this.copyHistory = COPY_ORIGINAL;
}
- StatementContextBase(final StatementDefinitionContext<A, D, E> def, final CopyHistory copyHistory) {
+ StatementContextBase(final StatementDefinitionContext<A, D, E> def, final CopyType copyType) {
this.definition = requireNonNull(def);
- this.copyHistory = requireNonNull(copyHistory);
+ this.copyHistory = (byte) copyFlags(copyType);
}
- @Override
- public Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement() {
- return effectOfStatement;
+ StatementContextBase(final StatementContextBase<A, D, E> prototype, final CopyType copyType) {
+ this.definition = prototype.definition;
+ this.copyHistory = (byte) (copyFlags(copyType) | prototype.copyHistory & ~COPY_LAST_TYPE_MASK);
}
- @Override
- public void addAsEffectOfStatement(final StmtContext<?, ?, ?> ctx) {
- if (effectOfStatement.isEmpty()) {
- effectOfStatement = new ArrayList<>(1);
+ private static int copyFlags(final CopyType copyType) {
+ return historyFlags(copyType) | copyType.ordinal();
+ }
+
+ private static byte historyFlags(final CopyType copyType) {
+ switch (copyType) {
+ case ADDED_BY_AUGMENTATION:
+ return COPY_ADDED_BY_AUGMENTATION;
+ case ADDED_BY_USES:
+ return COPY_ADDED_BY_USES;
+ case ADDED_BY_USES_AUGMENTATION:
+ return COPY_ADDED_BY_AUGMENTATION | COPY_ADDED_BY_USES;
+ case ORIGINAL:
+ return COPY_ORIGINAL;
+ default:
+ throw new VerifyException("Unhandled type " + copyType);
}
- effectOfStatement.add(ctx);
+ }
+
+ @Override
+ public Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement() {
+ return effectOfStatement;
}
@Override
effectOfStatement.addAll(ctxs);
}
+ //
+ // CopyHistory integration
+ //
+
@Override
- public CopyHistory getCopyHistory() {
- return copyHistory;
+ public final CopyHistory history() {
+ return this;
}
@Override
- public ModelProcessingPhase getCompletedPhase() {
- return completedPhase;
+ public final boolean isAddedByUses() {
+ return (copyHistory & COPY_ADDED_BY_USES) != 0;
+ }
+
+ @Override
+ public final boolean isAugmenting() {
+ return (copyHistory & COPY_ADDED_BY_AUGMENTATION) != 0;
+ }
+
+ @Override
+ public final CopyType getLastOperation() {
+ return CopyType.values()[copyHistory & COPY_LAST_TYPE_MASK];
+ }
+
+ //
+ // Inference completion tracking
+ //
+
+ @Override
+ final byte executionOrder() {
+ return executionOrder;
}
// FIXME: this should be propagated through a correct constructor
@Deprecated
final void setCompletedPhase(final ModelProcessingPhase completedPhase) {
- this.completedPhase = completedPhase;
+ this.executionOrder = completedPhase.executionOrder();
}
@Override
- public final <K, V, T extends K, U extends V, N extends IdentifierNamespace<K, V>> void addToNs(
+ public final <K, V, T extends K, U extends V, N extends ParserNamespace<K, V>> void addToNs(
final Class<@NonNull N> type, final T key, final U value) {
addToNamespace(type, key, value);
}
static final Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements(
- final List<StatementContextBase<?, ?, ?>> effective) {
+ final List<ReactorStmtCtx<?, ?, ?>> effective) {
return effective instanceof ImmutableCollection ? effective : Collections.unmodifiableCollection(effective);
}
- private static List<StatementContextBase<?, ?, ?>> shrinkEffective(
- final List<StatementContextBase<?, ?, ?>> effective) {
+ private static List<ReactorStmtCtx<?, ?, ?>> shrinkEffective(final List<ReactorStmtCtx<?, ?, ?>> effective) {
return effective.isEmpty() ? ImmutableList.of() : effective;
}
public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef);
- static final List<StatementContextBase<?, ?, ?>> removeStatementFromEffectiveSubstatements(
- final List<StatementContextBase<?, ?, ?>> effective, final StatementDefinition statementDef) {
+ static final List<ReactorStmtCtx<?, ?, ?>> removeStatementFromEffectiveSubstatements(
+ final List<ReactorStmtCtx<?, ?, ?>> effective, final StatementDefinition statementDef) {
if (effective.isEmpty()) {
return effective;
}
public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef,
String statementArg);
- static final List<StatementContextBase<?, ?, ?>> removeStatementFromEffectiveSubstatements(
- final List<StatementContextBase<?, ?, ?>> effective, final StatementDefinition statementDef,
+ static final List<ReactorStmtCtx<?, ?, ?>> removeStatementFromEffectiveSubstatements(
+ final List<ReactorStmtCtx<?, ?, ?>> effective, final StatementDefinition statementDef,
final String statementArg) {
if (statementArg == null) {
return removeStatementFromEffectiveSubstatements(effective, statementDef);
return effective;
}
- final Iterator<StatementContextBase<?, ?, ?>> iterator = effective.iterator();
+ final Iterator<ReactorStmtCtx<?, ?, ?>> iterator = effective.iterator();
while (iterator.hasNext()) {
final Mutable<?, ?, ?> next = iterator.next();
if (statementDef.equals(next.publicDefinition()) && statementArg.equals(next.rawArgument())) {
*/
public abstract void addEffectiveSubstatement(Mutable<?, ?, ?> substatement);
- final List<StatementContextBase<?, ?, ?>> addEffectiveSubstatement(
- final List<StatementContextBase<?, ?, ?>> effective, final Mutable<?, ?, ?> substatement) {
+ final List<ReactorStmtCtx<?, ?, ?>> addEffectiveSubstatement(final List<ReactorStmtCtx<?, ?, ?>> effective,
+ final Mutable<?, ?, ?> substatement) {
verifyStatement(substatement);
- final List<StatementContextBase<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, 1);
- final StatementContextBase<?, ?, ?> stmt = (StatementContextBase<?, ?, ?>) substatement;
- final ModelProcessingPhase phase = completedPhase;
- if (phase != null) {
- ensureCompletedPhase(stmt, phase);
- }
+ final List<ReactorStmtCtx<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, 1);
+ final ReactorStmtCtx<?, ?, ?> stmt = (ReactorStmtCtx<?, ?, ?>) substatement;
+ ensureCompletedExecution(stmt);
resized.add(stmt);
return resized;
}
abstract void addEffectiveSubstatementsImpl(Collection<? extends Mutable<?, ?, ?>> statements);
- final List<StatementContextBase<?, ?, ?>> addEffectiveSubstatementsImpl(
- final List<StatementContextBase<?, ?, ?>> effective,
+ final List<ReactorStmtCtx<?, ?, ?>> addEffectiveSubstatementsImpl(final List<ReactorStmtCtx<?, ?, ?>> effective,
final Collection<? extends Mutable<?, ?, ?>> statements) {
- final List<StatementContextBase<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, statements.size());
- final Collection<? extends StatementContextBase<?, ?, ?>> casted =
- (Collection<? extends StatementContextBase<?, ?, ?>>) statements;
- final ModelProcessingPhase phase = completedPhase;
- if (phase != null) {
- for (StatementContextBase<?, ?, ?> stmt : casted) {
- ensureCompletedPhase(stmt, phase);
+ final List<ReactorStmtCtx<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, statements.size());
+ final Collection<? extends ReactorStmtCtx<?, ?, ?>> casted =
+ (Collection<? extends ReactorStmtCtx<?, ?, ?>>) statements;
+ if (executionOrder != ExecutionOrder.NULL) {
+ for (ReactorStmtCtx<?, ?, ?> stmt : casted) {
+ ensureCompletedExecution(stmt, executionOrder);
}
}
return resized;
}
- abstract Iterable<StatementContextBase<?, ?, ?>> effectiveChildrenToComplete();
+ abstract Iterable<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete();
// exposed for InferredStatementContext only
final void ensureCompletedPhase(final Mutable<?, ?, ?> stmt) {
verifyStatement(stmt);
- final ModelProcessingPhase phase = completedPhase;
- if (phase != null) {
- ensureCompletedPhase((StatementContextBase<?, ?, ?>) stmt, phase);
+ ensureCompletedExecution((ReactorStmtCtx<?, ?, ?>) stmt);
+ }
+
+ // Make sure target statement has transitioned at least to our phase (if we have one). This method is just before we
+ // take allow a statement to become our substatement. This is needed to ensure that every statement tree does not
+ // contain any statements which did not complete the same phase as the root statement.
+ private void ensureCompletedExecution(final ReactorStmtCtx<?, ?, ?> stmt) {
+ if (executionOrder != ExecutionOrder.NULL) {
+ ensureCompletedExecution(stmt, executionOrder);
}
}
- // Make sure target statement has transitioned at least to specified phase. This method is just before we take
- // allow a statement to become our substatement. This is needed to ensure that every statement tree does not contain
- // any statements which did not complete the same phase as the root statement.
- private static void ensureCompletedPhase(final StatementContextBase<?, ?, ?> stmt,
- final ModelProcessingPhase phase) {
- verify(stmt.tryToCompletePhase(phase), "Statement %s cannot complete phase %s", stmt, phase);
+ private static void ensureCompletedExecution(final ReactorStmtCtx<?, ?, ?> stmt, final byte executionOrder) {
+ verify(stmt.tryToCompletePhase(executionOrder), "Statement %s cannot complete phase %s", stmt, executionOrder);
}
private static void verifyStatement(final Mutable<?, ?, ?> stmt) {
- verify(stmt instanceof StatementContextBase, "Unexpected statement %s", stmt);
+ verify(stmt instanceof ReactorStmtCtx, "Unexpected statement %s", stmt);
}
- private List<StatementContextBase<?, ?, ?>> beforeAddEffectiveStatement(
- final List<StatementContextBase<?, ?, ?>> effective, final int toAdd) {
- // We cannot allow statement to be further mutated
- verify(completedPhase != ModelProcessingPhase.EFFECTIVE_MODEL, "Cannot modify finished statement at %s",
+ private List<ReactorStmtCtx<?, ?, ?>> beforeAddEffectiveStatement(final List<ReactorStmtCtx<?, ?, ?>> effective,
+ final int toAdd) {
+ // We cannot allow statement to be further mutated.
+ // TODO: we really want to say 'not NULL and not at or after EFFECTIVE_MODEL here. This will matter if we have
+ // a phase after EFFECTIVE_MODEL
+ verify(executionOrder != ExecutionOrder.EFFECTIVE_MODEL, "Cannot modify finished statement at %s",
sourceReference());
return beforeAddEffectiveStatementUnsafe(effective, toAdd);
}
- final List<StatementContextBase<?, ?, ?>> beforeAddEffectiveStatementUnsafe(
- final List<StatementContextBase<?, ?, ?>> effective, final int toAdd) {
+ final List<ReactorStmtCtx<?, ?, ?>> beforeAddEffectiveStatementUnsafe(final List<ReactorStmtCtx<?, ?, ?>> effective,
+ final int toAdd) {
final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
checkState(inProgressPhase == ModelProcessingPhase.FULL_DECLARATION
|| inProgressPhase == ModelProcessingPhase.EFFECTIVE_MODEL,
return effective.isEmpty() ? new ArrayList<>(toAdd) : effective;
}
- // Exposed for ReplicaStatementContext
@Override
- E createEffective() {
- return definition.getFactory().createEffective(new BaseCurrentEffectiveStmtCtx<>(this), streamDeclared(),
- streamEffective());
+ final E createEffective() {
+ final E result = createEffective(definition.getFactory());
+ if (result instanceof MutableStatement) {
+ getRoot().addMutableStmtToSeal((MutableStatement) result);
+ }
+ return result;
}
- abstract Stream<? extends StmtContext<?, ?, ?>> streamDeclared();
+ @NonNull E createEffective(final StatementFactory<A, D, E> factory) {
+ return createEffective(factory, this);
+ }
- abstract Stream<? extends StmtContext<?, ?, ?>> streamEffective();
+ // Creates EffectiveStatement through full materialization
+ static <A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> @NonNull E createEffective(
+ final StatementFactory<A, D, E> factory, final StatementContextBase<A, D, E> ctx) {
+ return factory.createEffective(ctx, ctx.streamDeclared(), ctx.streamEffective());
+ }
/**
- * Try to execute current {@link ModelProcessingPhase} of source parsing. If the phase has already been executed,
- * this method does nothing.
+ * Return a stream of declared statements which can be built into an {@link EffectiveStatement}, as per
+ * {@link StmtContext#buildEffective()} contract.
*
- * @param phase to be executed (completed)
- * @return true if phase was successfully completed
- * @throws SourceException when an error occurred in source parsing
+ * @return Stream of supported declared statements.
*/
- final boolean tryToCompletePhase(final ModelProcessingPhase phase) {
- return phase.isCompletedBy(completedPhase) || doTryToCompletePhase(phase);
- }
+ // FIXME: we really want to unify this with streamEffective(), under its name
+ abstract Stream<? extends @NonNull StmtContext<?, ?, ?>> streamDeclared();
+
+ /**
+ * Return a stream of inferred statements which can be built into an {@link EffectiveStatement}, as per
+ * {@link StmtContext#buildEffective()} contract.
+ *
+ * @return Stream of supported effective statements.
+ */
+ // FIXME: this method is currently a misnomer, but unifying with streamDeclared() would make this accurate again
+ abstract Stream<? extends @NonNull StmtContext<?, ?, ?>> streamEffective();
- private boolean doTryToCompletePhase(final ModelProcessingPhase phase) {
- final boolean finished = phaseMutation.isEmpty() ? true : runMutations(phase);
- if (completeChildren(phase) && finished) {
- onPhaseCompleted(phase);
+ @Override
+ final boolean doTryToCompletePhase(final byte targetOrder) {
+ final boolean finished = phaseMutation.isEmpty() ? true : runMutations(targetOrder);
+ if (completeChildren(targetOrder) && finished) {
+ onPhaseCompleted(targetOrder);
return true;
}
return false;
}
- private boolean completeChildren(final ModelProcessingPhase phase) {
+ private boolean completeChildren(final byte targetOrder) {
boolean finished = true;
for (final StatementContextBase<?, ?, ?> child : mutableDeclaredSubstatements()) {
- finished &= child.tryToCompletePhase(phase);
+ finished &= child.tryToCompletePhase(targetOrder);
}
- for (final StatementContextBase<?, ?, ?> child : effectiveChildrenToComplete()) {
- finished &= child.tryToCompletePhase(phase);
+ for (final ReactorStmtCtx<?, ?, ?> child : effectiveChildrenToComplete()) {
+ finished &= child.tryToCompletePhase(targetOrder);
}
return finished;
}
- private boolean runMutations(final ModelProcessingPhase phase) {
+ private boolean runMutations(final byte targetOrder) {
+ final ModelProcessingPhase phase = verifyNotNull(ModelProcessingPhase.ofExecutionOrder(targetOrder));
final Collection<ContextMutation> openMutations = phaseMutation.get(phase);
return openMutations.isEmpty() ? true : runMutations(phase, openMutations);
}
}
/**
- * Occurs on end of {@link ModelProcessingPhase} of source parsing.
+ * Occurs on end of {@link ModelProcessingPhase} of source parsing. This method must not be called with
+ * {@code executionOrder} equal to {@link ExecutionOrder#NULL}.
*
- * @param phase
- * that was to be completed (finished)
- * @throws SourceException
- * when an error occurred in source parsing
+ * @param phase that was to be completed (finished)
+ * @throws SourceException when an error occurred in source parsing
*/
- private void onPhaseCompleted(final ModelProcessingPhase phase) {
- completedPhase = phase;
+ private void onPhaseCompleted(final byte completedOrder) {
+ executionOrder = completedOrder;
+ if (completedOrder == ExecutionOrder.EFFECTIVE_MODEL) {
+ // We have completed effective model, substatements are guaranteed not to change
+ summarizeSubstatementPolicy();
+ }
+ final ModelProcessingPhase phase = verifyNotNull(ModelProcessingPhase.ofExecutionOrder(completedOrder));
final Collection<OnPhaseFinished> listeners = phaseListeners.get(phase);
if (!listeners.isEmpty()) {
runPhaseListeners(phase, listeners);
}
}
+ private void summarizeSubstatementPolicy() {
+ if (definition().support().copyPolicy() == CopyPolicy.EXACT_REPLICA || noSensitiveSubstatements()) {
+ setAllSubstatementsContextIndependent();
+ }
+ }
+
+ /**
+ * Determine whether any substatements are copy-sensitive as determined by {@link StatementSupport#copyPolicy()}.
+ * Only {@link CopyPolicy#CONTEXT_INDEPENDENT}, {@link CopyPolicy#EXACT_REPLICA} and {@link CopyPolicy#IGNORE} are
+ * copy-insensitive. Note that statements which are not {@link StmtContext#isSupportedToBuildEffective()} are all
+ * considered copy-insensitive.
+ *
+ * <p>
+ * Implementations are expected to call {@link #noSensitiveSubstatements()} to actually traverse substatement sets.
+ *
+ * @return True if no substatements require copy-sensitive handling
+ */
+ abstract boolean noSensitiveSubstatements();
+
+ /**
+ * Determine whether any of the provided substatements are context-sensitive for purposes of implementing
+ * {@link #noSensitiveSubstatements()}.
+ *
+ * @param substatements Substatements to check
+ * @return True if no substatements require context-sensitive handling
+ */
+ static boolean noSensitiveSubstatements(final Collection<? extends ReactorStmtCtx<?, ?, ?>> substatements) {
+ for (ReactorStmtCtx<?, ?, ?> stmt : substatements) {
+ if (stmt.isSupportedToBuildEffective()) {
+ if (!stmt.allSubstatementsContextIndependent()) {
+ // This is a recursive property
+ return false;
+ }
+
+ switch (stmt.definition().support().copyPolicy()) {
+ case CONTEXT_INDEPENDENT:
+ case EXACT_REPLICA:
+ case IGNORE:
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
private void runPhaseListeners(final ModelProcessingPhase phase, final Collection<OnPhaseFinished> listeners) {
final Iterator<OnPhaseFinished> listener = listeners.iterator();
while (listener.hasNext()) {
return definition;
}
- final <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type, final K key,
+ final <K, V, N extends ParserNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type, final K key,
final OnNamespaceItemAdded listener) {
final Object potential = getFromNamespace(type, key);
if (potential != null) {
});
}
- final <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type,
+ final <K, V, N extends ParserNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type,
final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
final OnNamespaceItemAdded listener) {
final Optional<Entry<K, V>> existing = getFromNamespace(type, criterion);
});
}
- final <K, V, N extends IdentifierNamespace<K, V>> void selectMatch(final Class<N> type,
+ final <K, V, N extends ParserNamespace<K, V>> void selectMatch(final Class<N> type,
final NamespaceKeyCriterion<K> criterion, final OnNamespaceItemAdded listener) {
final Optional<Entry<K, V>> optMatch = getFromNamespace(type, criterion);
checkState(optMatch.isPresent(), "Failed to find a match for criterion %s in namespace %s node %s", criterion,
listener.namespaceItemAdded(StatementContextBase.this, type, match.getKey(), match.getValue());
}
- final <K, V, N extends IdentifierNamespace<K, V>> void waitForPhase(final Object value, final Class<N> type,
+ final <K, V, N extends ParserNamespace<K, V>> void waitForPhase(final Object value, final Class<N> type,
final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
final OnNamespaceItemAdded listener) {
((StatementContextBase<?, ? ,?>) value).addPhaseCompletedListener(phase,
});
}
- private <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> getBehaviour(
+ private <K, V, N extends ParserNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> getBehaviour(
final Class<N> type) {
final NamespaceBehaviour<K, V, N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
checkArgument(behaviour instanceof NamespaceBehaviourWithListeners, "Namespace %s does not support listeners",
* @throws NullPointerException if any of the arguments is null
*/
void addPhaseCompletedListener(final ModelProcessingPhase phase, final OnPhaseFinished listener) {
- checkNotNull(phase, "Statement context processing phase cannot be null at: %s", sourceReference());
- checkNotNull(listener, "Statement context phase listener cannot be null at: %s", sourceReference());
+ requireNonNull(phase, "Statement context processing phase cannot be null");
+ requireNonNull(listener, "Statement context phase listener cannot be null");
- ModelProcessingPhase finishedPhase = completedPhase;
+ ModelProcessingPhase finishedPhase = ModelProcessingPhase.ofExecutionOrder(executionOrder);
while (finishedPhase != null) {
if (phase.equals(finishedPhase)) {
listener.phaseFinished(this, finishedPhase);
* @throws IllegalStateException when the mutation was registered after phase was completed
*/
final void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
- ModelProcessingPhase finishedPhase = completedPhase;
- while (finishedPhase != null) {
- checkState(!phase.equals(finishedPhase), "Mutation registered after phase was completed at: %s",
- sourceReference());
- finishedPhase = finishedPhase.getPreviousPhase();
- }
+ checkState(executionOrder < phase.executionOrder(), "Mutation registered after phase was completed at: %s",
+ sourceReference());
if (phaseMutation.isEmpty()) {
phaseMutation = newMultimap();
public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> parent, final CopyType type,
final QNameModule targetModule) {
checkEffectiveModelCompleted(this);
+ return Optional.ofNullable(copyAsChildOfImpl(parent, type, targetModule));
+ }
+ private ReactorStmtCtx<A, D, E> copyAsChildOfImpl(final Mutable<?, ?, ?> parent, final CopyType type,
+ final QNameModule targetModule) {
final StatementSupport<A, D, E> support = definition.support();
- final CopyPolicy policy = support.applyCopyPolicy(this, parent, type, targetModule);
+ final CopyPolicy policy = support.copyPolicy();
switch (policy) {
+ case EXACT_REPLICA:
+ return replicaAsChildOf(parent);
case CONTEXT_INDEPENDENT:
- if (hasEmptySubstatements()) {
- // This statement is context-independent and has no substatements -- hence it can be freely shared.
- return Optional.of(replicaAsChildOf(parent));
+ if (allSubstatementsContextIndependent()) {
+ return replicaAsChildOf(parent);
}
- // FIXME: YANGTOOLS-694: filter out all context-independent substatements, eliminate fall-through
+
// fall through
case DECLARED_COPY:
- // FIXME: YANGTOOLS-694: this is still to eager, we really want to copy as a lazily-instantiated
- // context, so that we can support building an effective statement without copying
- // anything -- we will typically end up not being inferred against. In that case,
- // this slim context should end up dealing with differences at buildContext()
- // time. This is a YANGTOOLS-1067 prerequisite (which will deal with what can and
- // cannot be shared across instances).
- return Optional.of(parent.childCopyOf(this, type, targetModule));
+ // FIXME: ugly cast
+ return (ReactorStmtCtx<A, D, E>) parent.childCopyOf(this, type, targetModule);
case IGNORE:
- return Optional.empty();
+ return null;
case REJECT:
throw new IllegalStateException("Statement " + support.getPublicView() + " should never be copied");
default:
}
}
+ @Override
+ final ReactorStmtCtx<?, ?, ?> asEffectiveChildOf(final StatementContextBase<?, ?, ?> parent, final CopyType type,
+ final QNameModule targetModule) {
+ final ReactorStmtCtx<A, D, E> copy = copyAsChildOfImpl(parent, type, targetModule);
+ if (copy == null) {
+ // The statement fizzled, this should never happen, perhaps a verify()?
+ return null;
+ }
+
+ parent.ensureCompletedPhase(copy);
+ return canReuseCurrent(copy) ? this : copy;
+ }
+
+ private boolean canReuseCurrent(final ReactorStmtCtx<A, D, E> copy) {
+ // Defer to statement factory to see if we can reuse this object. If we can and have only context-independent
+ // substatements we can reuse the object. More complex cases are handled indirectly via the copy.
+ return definition.getFactory().canReuseCurrent(copy, this, buildEffective().effectiveSubstatements())
+ && allSubstatementsContextIndependent();
+ }
+
@Override
public final Mutable<?, ?, ?> childCopyOf(final StmtContext<?, ?, ?> stmt, final CopyType type,
final QNameModule targetModule) {
}
@Override
- public final StatementContextBase<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
- checkArgument(parent instanceof StatementContextBase, "Unsupported parent %s", parent);
- return replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
- }
-
- final @NonNull StatementContextBase<A, D, E> replicaAsChildOf(final StatementContextBase<?, ?, ?> stmt) {
- return new ReplicaStatementContext<>(stmt, this);
+ final ReplicaStatementContext<A, D, E> replicaAsChildOf(final StatementContextBase<?, ?, ?> parent) {
+ return new ReplicaStatementContext<>(parent, this);
}
private static void checkEffectiveModelCompleted(final StmtContext<?, ?, ?> stmt) {
}
@Beta
+ // FIXME: this information should be exposed as a well-known Namespace
public final boolean hasImplicitParentSupport() {
return definition.getFactory() instanceof ImplicitParentAwareStatementSupport;
}
}
final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(optImplicit.get());
- final CopyType type = original.getCopyHistory().getLastOperation();
+ final CopyType type = original.history().getLastOperation();
final SubstatementContext<?, ?, ?> result = new SubstatementContext(original.getParentContext(), def,
original.sourceReference(), original.rawArgument(), original.argument(), type);