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;
return effectOfStatement;
}
- @Override
- public void addAsEffectOfStatement(final StmtContext<?, ?, ?> ctx) {
- if (effectOfStatement.isEmpty()) {
- effectOfStatement = new ArrayList<>(1);
- }
- effectOfStatement.add(ctx);
- }
-
@Override
public void addAsEffectOfStatement(final Collection<? extends StmtContext<?, ?, ?>> ctxs) {
if (ctxs.isEmpty()) {
final List<ReactorStmtCtx<?, ?, ?>> addEffectiveSubstatementsImpl(final List<ReactorStmtCtx<?, ?, ?>> effective,
final Collection<? extends Mutable<?, ?, ?>> statements) {
final List<ReactorStmtCtx<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, statements.size());
- final Collection<? extends StatementContextBase<?, ?, ?>> casted =
- (Collection<? extends StatementContextBase<?, ?, ?>>) statements;
+ final Collection<? extends ReactorStmtCtx<?, ?, ?>> casted =
+ (Collection<? extends ReactorStmtCtx<?, ?, ?>>) statements;
final ModelProcessingPhase phase = completedPhase;
if (phase != null) {
- for (StatementContextBase<?, ?, ?> stmt : casted) {
+ for (ReactorStmtCtx<?, ?, ?> stmt : casted) {
ensureCompletedPhase(stmt, phase);
}
}
return effective.isEmpty() ? new ArrayList<>(toAdd) : effective;
}
-
@Override
final E createEffective() {
- final E result = definition.getFactory().createEffective(this, streamDeclared(), streamEffective());
+ 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());
+ }
+
+ /**
+ * Return a stream of declared statements which can be built into an {@link EffectiveStatement}, as per
+ * {@link StmtContext#buildEffective()} contract.
+ *
+ * @return Stream of supported declared statements.
+ */
+ // 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();
@Override
final boolean doTryToCompletePhase(final ModelProcessingPhase phase) {
*/
private void onPhaseCompleted(final ModelProcessingPhase phase) {
completedPhase = phase;
+ if (phase == ModelProcessingPhase.EFFECTIVE_MODEL) {
+ summarizeSubstatementPolicy();
+ }
final Collection<OnPhaseFinished> listeners = phaseListeners.get(phase);
if (!listeners.isEmpty()) {
}
}
+ 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()) {
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);
}
- // ascertaining substatements could be quite costly, let's just fall through to declared copy and deal
- // shortcut it when we build the statements.
+
// 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 ReactorStmtCtx<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
- checkArgument(parent instanceof StatementContextBase, "Unsupported parent %s", parent);
- return replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
- }
-
- final @NonNull ReplicaStatementContext<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) {