X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-reactor%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Freactor%2FStatementContextBase.java;h=a331d6b6d91619da119fcc3323aa94dee5a478a5;hb=cd04351669d5921088a73a275954ba78336c1a44;hp=cd07b95b1cb51e30d3054050f5d6434d6234f96a;hpb=3174ac0dc4fb109977fc21f95c82c07e4392172c;p=yangtools.git diff --git a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java index cd07b95b1c..a331d6b6d9 100644 --- a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java +++ b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java @@ -8,7 +8,6 @@ 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 java.util.Objects.requireNonNull; @@ -44,6 +43,7 @@ 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; @@ -129,14 +129,6 @@ public abstract class StatementContextBase, E 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> ctxs) { if (ctxs.isEmpty()) { @@ -293,11 +285,11 @@ public abstract class StatementContextBase, E final List> addEffectiveSubstatementsImpl(final List> effective, final Collection> statements) { final List> resized = beforeAddEffectiveStatement(effective, statements.size()); - final Collection> casted = - (Collection>) statements; + final Collection> casted = + (Collection>) statements; final ModelProcessingPhase phase = completedPhase; if (phase != null) { - for (StatementContextBase stmt : casted) { + for (ReactorStmtCtx stmt : casted) { ensureCompletedPhase(stmt, phase); } } @@ -346,19 +338,42 @@ public abstract class StatementContextBase, E 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> streamDeclared(); + @NonNull E createEffective(final StatementFactory factory) { + return createEffective(factory, this); + } - abstract Stream> streamEffective(); + // Creates EffectiveStatement through full materialization + static , E extends EffectiveStatement> @NonNull E createEffective( + final StatementFactory factory, final StatementContextBase 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> 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> streamEffective(); @Override final boolean doTryToCompletePhase(final ModelProcessingPhase phase) { @@ -421,6 +436,9 @@ public abstract class StatementContextBase, E */ private void onPhaseCompleted(final ModelProcessingPhase phase) { completedPhase = phase; + if (phase == ModelProcessingPhase.EFFECTIVE_MODEL) { + summarizeSubstatementPolicy(); + } final Collection listeners = phaseListeners.get(phase); if (!listeners.isEmpty()) { @@ -428,6 +446,53 @@ public abstract class StatementContextBase, E } } + 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. + * + *

+ * 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> 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 listeners) { final Iterator listener = listeners.iterator(); while (listener.hasNext()) { @@ -541,8 +606,8 @@ public abstract class StatementContextBase, E * @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; while (finishedPhase != null) { @@ -595,20 +660,27 @@ public abstract class StatementContextBase, E public Optional> copyAsChildOf(final Mutable parent, final CopyType type, final QNameModule targetModule) { checkEffectiveModelCompleted(this); + return Optional.ofNullable(copyAsChildOfImpl(parent, type, targetModule)); + } + private ReactorStmtCtx copyAsChildOfImpl(final Mutable parent, final CopyType type, + final QNameModule targetModule) { final StatementSupport support = definition.support(); final CopyPolicy policy = support.copyPolicy(); switch (policy) { + case EXACT_REPLICA: + return replicaAsChildOf(parent); case CONTEXT_INDEPENDENT: - if (substatementsContextIndependent()) { - return Optional.of(replicaAsChildOf(parent)); + if (allSubstatementsContextIndependent()) { + return replicaAsChildOf(parent); } // fall through case DECLARED_COPY: - return Optional.of(parent.childCopyOf(this, type, targetModule)); + // FIXME: ugly cast + return (ReactorStmtCtx) 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: @@ -616,35 +688,24 @@ public abstract class StatementContextBase, E } } - private boolean substatementsContextIndependent() { - // FIXME: YANGTOOLS-1195: we really want to compute (and cache) the summary for substatements. - // - // For now we just check if there are any substatements, but we really want to ask: - // - // Are all substatements (recursively) CONTEXT_INDEPENDENT as well? - // - // Which is something we want to compute once and store. This needs to be implemented. - return hasEmptySubstatements(); - } - - // FIXME: YANGTOOLS-1195: this method is unused, but should be called from InferredStatementContext at the very - // least. It should return @NonNull -- either 'E' or EffectiveStmtCtx.Current'. Perhaps its arguments need - // to be adjusted, too. - final void asEffectiveChildOf(final Mutable parent, final CopyType type, final QNameModule targetModule) { - checkEffectiveModelCompleted(this); - - final StatementSupport support = definition.support(); - final StmtContext effective = support.effectiveCopyOf(this, parent, type, targetModule); - if (effective == this) { - LOG.debug("Should reuse {}", this); - return; + @Override + final ReactorStmtCtx asEffectiveChildOf(final StatementContextBase parent, final CopyType type, + final QNameModule targetModule) { + final ReactorStmtCtx copy = copyAsChildOfImpl(parent, type, targetModule); + if (copy == null) { + // The statement fizzled, this should never happen, perhaps a verify()? + return null; } - // FIXME: YANGTOOLS-1195: here is probably where we want to do some statement reuse: even if the parent is - // affected, some substatements may not -- in which case we want to reuse them. This - // probably needs to be a callout of some kind. - // FIXME: YANGTOOLS-1067: an incremental improvement to that is that if no substatements changed, we want to - // be reusing the entire List and pass that as substatements. + parent.ensureCompletedPhase(copy); + return canReuseCurrent(copy) ? this : copy; + } + + private boolean canReuseCurrent(final ReactorStmtCtx 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 @@ -693,13 +754,8 @@ public abstract class StatementContextBase, E } @Override - public final ReactorStmtCtx replicaAsChildOf(final Mutable parent) { - checkArgument(parent instanceof StatementContextBase, "Unsupported parent %s", parent); - return replicaAsChildOf((StatementContextBase) parent); - } - - final @NonNull ReplicaStatementContext replicaAsChildOf(final StatementContextBase stmt) { - return new ReplicaStatementContext<>(stmt, this); + final ReplicaStatementContext replicaAsChildOf(final StatementContextBase parent) { + return new ReplicaStatementContext<>(parent, this); } private static void checkEffectiveModelCompleted(final StmtContext stmt) {