From 745c91d1d247bcf241dff2e3a2cd881d28d873d2 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sun, 26 Jan 2020 01:22:11 +0100 Subject: [PATCH] Defer copy decisions to StatementSupport Core reactor should have no knowledge of specific statements, but rather should provide general facilities for statements to decide what they need to do. A typical example of this are description/reference/status statements, which are never inlined from a grouping parent (as they relate to the grouping, not the copy target). Add StatementSupport.copyAsChildOf() and implement above case in terms of the new method. Furthermore move support code to UsesStatementSupport and make it use the same mechanics -- eliminating NOCOPY_FROM_GROUPING_SET in the process of doing so. JIRA: YANGTOOLS-694 Change-Id: I446266249dfe3f1bcac310bd16aece5185b40fb6 Signed-off-by: Robert Varga --- .../reactor/AbstractResumedStatement.java | 2 +- .../reactor/InferredStatementContext.java | 22 +- .../stmt/reactor/StatementContextBase.java | 21 +- .../reactor/StatementDefinitionContext.java | 20 +- .../DescriptionStatementSupport.java | 14 +- .../reference/ReferenceStatementSupport.java | 14 +- .../stmt/status/StatusStatementSupport.java | 15 +- .../rfc7950/stmt/uses/UsesStatementImpl.java | 220 ------------------ .../stmt/uses/UsesStatementSupport.java | 192 ++++++++++++++- .../spi/meta/AbstractStatementSupport.java | 24 +- .../spi/meta/ForwardingStatementSupport.java | 8 + .../parser/spi/meta/StatementSupport.java | 67 +++--- .../yang/parser/spi/meta/StmtContext.java | 5 + .../parser/spi/meta/StmtContextUtils.java | 13 ++ 14 files changed, 334 insertions(+), 303 deletions(-) diff --git a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/AbstractResumedStatement.java b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/AbstractResumedStatement.java index db3202a522..2123c35788 100644 --- a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/AbstractResumedStatement.java +++ b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/AbstractResumedStatement.java @@ -55,7 +55,7 @@ abstract class AbstractResumedStatement, E ext final String rawArgument) { super(def); this.statementDeclSource = requireNonNull(ref); - this.rawArgument = def.internArgument(rawArgument); + this.rawArgument = def.support().internArgument(rawArgument); } AbstractResumedStatement(final StatementDefinitionContext def, final StatementSourceReference ref, diff --git a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java index 1d7a057805..3398f2edd5 100644 --- a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java +++ b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java @@ -150,15 +150,11 @@ final class InferredStatementContext, E extend // FIXME: This is messy and is probably wrong in some corner case. Even if it is correct, the way how it is correct // relies on hard-coded maps. At the end of the day, the logic needs to be controlled by statement's // StatementSupport. - // FIXME: YANGTOOLS-652: these maps look very much like those in UsesStatementImpl + // FIXME: YANGTOOLS-652: this map looks very much like UsesStatementSupport.TOP_REUSED_DEF_SET private static final ImmutableSet REUSED_DEF_SET = ImmutableSet.of( YangStmtMapping.TYPE, YangStmtMapping.TYPEDEF, YangStmtMapping.USES); - private static final ImmutableSet NOCOPY_FROM_GROUPING_SET = ImmutableSet.of( - YangStmtMapping.DESCRIPTION, - YangStmtMapping.REFERENCE, - YangStmtMapping.STATUS); private void copySubstatement(final Mutable substatement, final Collection> buffer) { final StatementDefinition def = substatement.getPublicDefinition(); @@ -169,22 +165,8 @@ final class InferredStatementContext, E extend buffer.add(substatement); return; } - // FIXME: YANGTOOLS-652: formerly known as "needToCopyByUses" (note inverted check, though) - if (NOCOPY_FROM_GROUPING_SET.contains(def)) { - // This is to say: if parent of source context is a grouping, ignore this statement. - if (YangStmtMapping.GROUPING.equals(substatement.coerceParentContext().getPublicDefinition())) { - LOG.debug("Skipping grouping statement {}", substatement); - return; - } - } - // FIXME: YANGTOOLS-694: we are forcing a copy here, hence even statements not affected by parent, copyType - // or targetModule (and don't forget its substatements!). This really should be a callout - // to StatementSupport. Note if that callout is allowed to return an Optional, it can - // take care at least of the 'grouping from uses' case above. - final Mutable copy = childCopyOf(substatement, childCopyType, targetModule); - LOG.debug("Copying substatement {} for {} as {}", substatement, this, copy); - buffer.add(copy); + substatement.copyAsChildOf(this, childCopyType, targetModule).ifPresent(buffer::add); } // Statement copy mess ends here 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 6a50e47d4f..32f546d618 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 @@ -765,12 +765,17 @@ public abstract class StatementContextBase, E addContextToNamespace(namespace, key, stmt); } + @Override + public Optional> copyAsChildOf(final Mutable parent, final CopyType type, + final QNameModule targetModule) { + checkEffectiveModelCompleted(this); + return definition.support().copyAsChildOf(this, parent, type, targetModule); + } + @Override public , Z extends EffectiveStatement> Mutable childCopyOf( final StmtContext stmt, final CopyType type, final QNameModule targetModule) { - checkState(stmt.getCompletedPhase() == ModelProcessingPhase.EFFECTIVE_MODEL, - "Attempted to copy statement %s which has completed phase %s", stmt, stmt.getCompletedPhase()); - + checkEffectiveModelCompleted(stmt); checkArgument(stmt instanceof StatementContextBase, "Unsupported statement %s", stmt); return childCopyOf((StatementContextBase)stmt, type, targetModule); } @@ -812,6 +817,12 @@ public abstract class StatementContextBase, E return result; } + private static void checkEffectiveModelCompleted(final StmtContext stmt) { + final ModelProcessingPhase phase = stmt.getCompletedPhase(); + checkState(phase == ModelProcessingPhase.EFFECTIVE_MODEL, + "Attempted to copy statement %s which has completed phase %s", stmt, phase); + } + @Beta public final boolean hasImplicitParentSupport() { return definition.getFactory() instanceof ImplicitParentAwareStatementSupport; @@ -897,7 +908,7 @@ public abstract class StatementContextBase, E if (fl != 0) { return fl == SET_IGNORE_CONFIG; } - if (definition.isIgnoringConfig() || parent.isIgnoringConfig()) { + if (definition.support().isIgnoringConfig() || parent.isIgnoringConfig()) { flags |= SET_IGNORE_CONFIG; return true; } @@ -918,7 +929,7 @@ public abstract class StatementContextBase, E if (fl != 0) { return fl == SET_IGNORE_IF_FEATURE; } - if (definition.isIgnoringIfFeatures() || parent.isIgnoringIfFeatures()) { + if (definition.support().isIgnoringIfFeatures() || parent.isIgnoringIfFeatures()) { flags |= SET_IGNORE_IF_FEATURE; return true; } diff --git a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java index 570da62a64..b7df52b3c6 100644 --- a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java +++ b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java @@ -109,7 +109,7 @@ public class StatementDefinitionContext, E ext return toStringHelper.add("statement", getStatementName()); } - @NonNull StatementDefinitionContext getSubDefinitionSpecificForArgument(final String argument) { + final @NonNull StatementDefinitionContext getSubDefinitionSpecificForArgument(final String argument) { if (!hasArgumentSpecificSubDefinitions()) { return this; } @@ -125,15 +125,15 @@ public class StatementDefinitionContext, E ext return potential; } - boolean hasArgumentSpecificSubDefinitions() { - return support.hasArgumentSpecificSupports(); + final StatementSupport support() { + return support; } - String internArgument(final String rawArgument) { - return support.internArgument(rawArgument); + final boolean hasArgumentSpecificSubDefinitions() { + return support.hasArgumentSpecificSupports(); } - StatementDefinitionContext getAsUnknownStatementDefinition( + final StatementDefinitionContext getAsUnknownStatementDefinition( final StatementDefinitionContext yangStmtDef) { if (unknownStmtDefsOfYangStmts != null) { final StatementDefinitionContext existing = unknownStmtDefsOfYangStmts.get(yangStmtDef); @@ -152,12 +152,4 @@ public class StatementDefinitionContext, E ext } return ret; } - - boolean isIgnoringIfFeatures() { - return support.isIgnoringIfFeatures(); - } - - boolean isIgnoringConfig() { - return support.isIgnoringConfig(); - } } diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/description/DescriptionStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/description/DescriptionStatementSupport.java index f83401f7de..2fdc3de240 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/description/DescriptionStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/description/DescriptionStatementSupport.java @@ -8,13 +8,18 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.description; import com.google.common.collect.ImmutableList; +import java.util.Optional; +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.stmt.DescriptionEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStringStatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; 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.meta.SubstatementValidator; public final class DescriptionStatementSupport @@ -36,6 +41,13 @@ public final class DescriptionStatementSupport return value; } + @Override + public Optional> copyAsChildOf(final Mutable stmt, + final Mutable parent, final CopyType type, final QNameModule targetModule) { + return StmtContextUtils.isChildOfGrouping(stmt) ? Optional.empty() + : super.copyAsChildOf(stmt, parent, type, targetModule); + } + @Override protected SubstatementValidator getSubstatementValidator() { return SUBSTATEMENT_VALIDATOR; @@ -66,4 +78,4 @@ public final class DescriptionStatementSupport final DescriptionStatement declared) { return new EmptyDescriptionEffectiveStatement(declared); } -} \ No newline at end of file +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/reference/ReferenceStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/reference/ReferenceStatementSupport.java index 28ba59ab0f..365e4ce284 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/reference/ReferenceStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/reference/ReferenceStatementSupport.java @@ -8,13 +8,18 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.reference; import com.google.common.collect.ImmutableList; +import java.util.Optional; +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.stmt.ReferenceEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStringStatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; 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.meta.SubstatementValidator; public final class ReferenceStatementSupport @@ -37,6 +42,13 @@ public final class ReferenceStatementSupport return value; } + @Override + public Optional> copyAsChildOf(final Mutable stmt, + final Mutable parent, final CopyType type, final QNameModule targetModule) { + return StmtContextUtils.isChildOfGrouping(stmt) ? Optional.empty() + : super.copyAsChildOf(stmt, parent, type, targetModule); + } + @Override protected SubstatementValidator getSubstatementValidator() { return SUBSTATEMENT_VALIDATOR; @@ -67,4 +79,4 @@ public final class ReferenceStatementSupport final ReferenceStatement declared) { return new EmptyReferenceEffectiveStatement(declared); } -} \ No newline at end of file +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/status/StatusStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/status/StatusStatementSupport.java index b0e14c755f..d39fd6f0b2 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/status/StatusStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/status/StatusStatementSupport.java @@ -8,7 +8,9 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.status; import com.google.common.collect.ImmutableList; +import java.util.Optional; import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.model.api.Status; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; @@ -16,7 +18,10 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; 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.meta.SubstatementValidator; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; @@ -80,6 +85,13 @@ public final class StatusStatementSupport } } + @Override + public Optional> copyAsChildOf(final Mutable stmt, + final Mutable parent, final CopyType type, final QNameModule targetModule) { + return StmtContextUtils.isChildOfGrouping(stmt) ? Optional.empty() + : super.copyAsChildOf(stmt, parent, type, targetModule); + } + @Override protected SubstatementValidator getSubstatementValidator() { return SUBSTATEMENT_VALIDATOR; @@ -131,5 +143,4 @@ public final class StatusStatementSupport return new EmptyStatusEffectiveStatement(declared); } } - -} \ No newline at end of file +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementImpl.java index 922e296857..0c302199c7 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementImpl.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementImpl.java @@ -7,233 +7,13 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.uses; -import com.google.common.base.Verify; -import com.google.common.collect.ImmutableSet; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Optional; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.common.YangVersion; -import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; -import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; -import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; -import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement; -import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace; -import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.YangValidationBundles; import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement; -import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; -import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; 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.ModuleCtxToModuleQName; -import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; -import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace; -import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType; -import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; final class UsesStatementImpl extends AbstractDeclaredStatement implements UsesStatement { - private static final Logger LOG = LoggerFactory.getLogger(UsesStatementImpl.class); - UsesStatementImpl(final StmtContext context) { super(context); } - - /** - * Copy statements from a grouping to a target node. - * - * @param sourceGrpStmtCtx - * source grouping statement context - * @param targetCtx - * target context - * @param usesNode - * uses node - * @throws SourceException - * instance of SourceException - */ - static void copyFromSourceToTarget(final Mutable sourceGrpStmtCtx, - final StatementContextBase targetCtx, - final Mutable usesNode) { - final Collection> declared = sourceGrpStmtCtx.mutableDeclaredSubstatements(); - final Collection> effective = sourceGrpStmtCtx.mutableEffectiveSubstatements(); - final Collection> buffer = new ArrayList<>(declared.size() + effective.size()); - final QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceGrpStmtCtx); - - for (final Mutable original : declared) { - if (original.isSupportedByFeatures()) { - copyStatement(original, targetCtx, newQNameModule, buffer); - } - } - - for (final Mutable original : effective) { - copyStatement(original, targetCtx, newQNameModule, buffer); - } - - targetCtx.addEffectiveSubstatements(buffer); - usesNode.addAsEffectOfStatement(buffer); - } - - private static void copyStatement(final Mutable original, - final StatementContextBase targetCtx, final QNameModule targetModule, - final Collection> buffer) { - if (needToCopyByUses(original)) { - final Mutable copy = targetCtx.childCopyOf(original, CopyType.ADDED_BY_USES, targetModule); - buffer.add(copy); - } else if (isReusedByUsesOnTop(original)) { - buffer.add(original); - } - } - - // FIXME: YANGTOOLS-652: these maps look very much like those in InferredStatementContext - private static final ImmutableSet TOP_REUSED_DEF_SET = ImmutableSet.of( - YangStmtMapping.TYPE, - YangStmtMapping.TYPEDEF); - - private static boolean isReusedByUsesOnTop(final StmtContext stmtContext) { - return TOP_REUSED_DEF_SET.contains(stmtContext.getPublicDefinition()); - } - - private static final ImmutableSet NOCOPY_FROM_GROUPING_SET = ImmutableSet.of( - YangStmtMapping.DESCRIPTION, - YangStmtMapping.REFERENCE, - YangStmtMapping.STATUS); - private static final ImmutableSet REUSED_DEF_SET = ImmutableSet.of( - YangStmtMapping.TYPE, - YangStmtMapping.TYPEDEF, - YangStmtMapping.USES); - - public static boolean needToCopyByUses(final StmtContext stmtContext) { - final StatementDefinition def = stmtContext.getPublicDefinition(); - if (REUSED_DEF_SET.contains(def)) { - LOG.trace("Will reuse {} statement {}", def, stmtContext); - return false; - } - if (NOCOPY_FROM_GROUPING_SET.contains(def)) { - return !YangStmtMapping.GROUPING.equals(stmtContext.coerceParentContext().getPublicDefinition()); - } - - LOG.trace("Will copy {} statement {}", def, stmtContext); - return true; - } - - public static void resolveUsesNode(final Mutable usesNode, - final StmtContext targetNodeStmtCtx) { - for (final Mutable subStmtCtx : usesNode.mutableDeclaredSubstatements()) { - if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class) - && areFeaturesSupported(subStmtCtx)) { - performRefine(subStmtCtx, targetNodeStmtCtx); - } - } - } - - private static boolean areFeaturesSupported(final StmtContext subStmtCtx) { - /* - * In case of Yang 1.1, checks whether features are supported. - */ - return !YangVersion.VERSION_1_1.equals(subStmtCtx.getRootVersion()) || subStmtCtx.isSupportedByFeatures(); - } - - private static void performRefine(final Mutable subStmtCtx, final StmtContext usesParentCtx) { - final Object refineArgument = subStmtCtx.getStatementArgument(); - InferenceException.throwIf(!(refineArgument instanceof SchemaNodeIdentifier), - subStmtCtx.getStatementSourceReference(), - "Invalid refine argument %s. It must be instance of SchemaNodeIdentifier.", refineArgument); - - final Optional> optRefineTargetCtx = ChildSchemaNodeNamespace.findNode( - usesParentCtx, (SchemaNodeIdentifier) refineArgument); - InferenceException.throwIf(!optRefineTargetCtx.isPresent(), subStmtCtx.getStatementSourceReference(), - "Refine target node %s not found.", refineArgument); - - final StmtContext refineTargetNodeCtx = optRefineTargetCtx.get(); - if (StmtContextUtils.isUnknownStatement(refineTargetNodeCtx)) { - LOG.trace("Refine node '{}' in uses '{}' has target node unknown statement '{}'. " - + "Refine has been skipped. At line: {}", subStmtCtx.getStatementArgument(), - subStmtCtx.coerceParentContext().getStatementArgument(), - refineTargetNodeCtx.getStatementArgument(), subStmtCtx.getStatementSourceReference()); - subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx); - return; - } - - Verify.verify(refineTargetNodeCtx instanceof StatementContextBase); - addOrReplaceNodes(subStmtCtx, (StatementContextBase) refineTargetNodeCtx); - subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx); - } - - private static void addOrReplaceNodes(final Mutable subStmtCtx, - final StatementContextBase refineTargetNodeCtx) { - for (final Mutable refineSubstatementCtx : subStmtCtx.mutableDeclaredSubstatements()) { - if (isSupportedRefineSubstatement(refineSubstatementCtx)) { - addOrReplaceNode(refineSubstatementCtx, refineTargetNodeCtx); - } - } - } - - private static void addOrReplaceNode(final Mutable refineSubstatementCtx, - final StatementContextBase refineTargetNodeCtx) { - - final StatementDefinition refineSubstatementDef = refineSubstatementCtx.getPublicDefinition(); - - SourceException.throwIf(!isSupportedRefineTarget(refineSubstatementCtx, refineTargetNodeCtx), - refineSubstatementCtx.getStatementSourceReference(), - "Error in module '%s' in the refine of uses '%s': can not perform refine of '%s' for the target '%s'.", - refineSubstatementCtx.getRoot().getStatementArgument(), - refineSubstatementCtx.coerceParentContext().getStatementArgument(), - refineSubstatementCtx.getPublicDefinition(), refineTargetNodeCtx.getPublicDefinition()); - - if (isAllowedToAddByRefine(refineSubstatementDef)) { - refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx); - } else { - refineTargetNodeCtx.removeStatementFromEffectiveSubstatements(refineSubstatementDef); - refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx); - } - } - - private static final ImmutableSet ALLOWED_TO_ADD_BY_REFINE_DEF_SET = - ImmutableSet.of(YangStmtMapping.MUST); - - private static boolean isAllowedToAddByRefine(final StatementDefinition publicDefinition) { - return ALLOWED_TO_ADD_BY_REFINE_DEF_SET.contains(publicDefinition); - } - - private static boolean isSupportedRefineSubstatement(final StmtContext refineSubstatementCtx) { - final Collection supportedRefineSubstatements = refineSubstatementCtx.getFromNamespace( - ValidationBundlesNamespace.class, ValidationBundleType.SUPPORTED_REFINE_SUBSTATEMENTS); - - return supportedRefineSubstatements == null || supportedRefineSubstatements.isEmpty() - || supportedRefineSubstatements.contains(refineSubstatementCtx.getPublicDefinition()) - || StmtContextUtils.isUnknownStatement(refineSubstatementCtx); - } - - private static boolean isSupportedRefineTarget(final StmtContext refineSubstatementCtx, - final StmtContext refineTargetNodeCtx) { - final Collection supportedRefineTargets = YangValidationBundles.SUPPORTED_REFINE_TARGETS - .get(refineSubstatementCtx.getPublicDefinition()); - - return supportedRefineTargets == null || supportedRefineTargets.isEmpty() - || supportedRefineTargets.contains(refineTargetNodeCtx.getPublicDefinition()); - } - - - private static QNameModule getNewQNameModule(final StmtContext targetCtx, - final StmtContext stmtContext) { - if (targetCtx.getParentContext() == null) { - return targetCtx.getFromNamespace(ModuleCtxToModuleQName.class, targetCtx); - } - if (targetCtx.getPublicDefinition() == YangStmtMapping.AUGMENT) { - return StmtContextUtils.getRootModuleQName(targetCtx); - } - - final Object targetStmtArgument = targetCtx.getStatementArgument(); - final Object sourceStmtArgument = stmtContext.getStatementArgument(); - if (targetStmtArgument instanceof QName && sourceStmtArgument instanceof QName) { - return ((QName) targetStmtArgument).getModule(); - } - - return null; - } } diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementSupport.java index 2c3af93469..7a97693107 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementSupport.java @@ -7,13 +7,25 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.uses; +import com.google.common.base.Verify; +import com.google.common.collect.ImmutableSet; +import java.util.ArrayList; import java.util.Collection; +import java.util.Optional; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; +import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement; +import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace; +import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.YangValidationBundles; import org.opendaylight.yangtools.yang.parser.spi.GroupingNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction; @@ -24,10 +36,17 @@ 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.meta.SubstatementValidator; +import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; +import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace; +import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType; import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public final class UsesStatementSupport extends AbstractQNameStatementSupport { + private static final Logger LOG = LoggerFactory.getLogger(UsesStatementSupport.class); private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping .USES) .addAny(YangStmtMapping.AUGMENT) @@ -77,8 +96,8 @@ public final class UsesStatementSupport final StatementContextBase sourceGrpStmtCtx = (StatementContextBase) sourceGroupingPre.resolve(ctx); - UsesStatementImpl.copyFromSourceToTarget(sourceGrpStmtCtx, targetNodeStmtCtx, usesNode); - UsesStatementImpl.resolveUsesNode(usesNode, targetNodeStmtCtx); + copyFromSourceToTarget(sourceGrpStmtCtx, targetNodeStmtCtx, usesNode); + resolveUsesNode(usesNode, targetNodeStmtCtx); StmtContextUtils.validateIfFeatureAndWhenOnListKeys(usesNode); } @@ -105,4 +124,171 @@ public final class UsesStatementSupport protected SubstatementValidator getSubstatementValidator() { return SUBSTATEMENT_VALIDATOR; } -} \ No newline at end of file + + /** + * Copy statements from a grouping to a target node. + * + * @param sourceGrpStmtCtx + * source grouping statement context + * @param targetCtx + * target context + * @param usesNode + * uses node + * @throws SourceException + * instance of SourceException + */ + private static void copyFromSourceToTarget(final Mutable sourceGrpStmtCtx, + final StatementContextBase targetCtx, + final Mutable usesNode) { + final Collection> declared = sourceGrpStmtCtx.mutableDeclaredSubstatements(); + final Collection> effective = sourceGrpStmtCtx.mutableEffectiveSubstatements(); + final Collection> buffer = new ArrayList<>(declared.size() + effective.size()); + final QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceGrpStmtCtx); + + for (final Mutable original : declared) { + if (original.isSupportedByFeatures()) { + copyStatement(original, targetCtx, newQNameModule, buffer); + } + } + + for (final Mutable original : effective) { + copyStatement(original, targetCtx, newQNameModule, buffer); + } + + targetCtx.addEffectiveSubstatements(buffer); + usesNode.addAsEffectOfStatement(buffer); + } + + // FIXME: YANGTOOLS-652: this map looks very much like InferredStatementContext.REUSED_DEF_SET + private static final ImmutableSet TOP_REUSED_DEF_SET = ImmutableSet.of( + YangStmtMapping.TYPE, + YangStmtMapping.TYPEDEF); + + private static void copyStatement(final Mutable original, + final StatementContextBase targetCtx, final QNameModule targetModule, + final Collection> buffer) { + final StatementDefinition def = original.getPublicDefinition(); + if (TOP_REUSED_DEF_SET.contains(def)) { + buffer.add(original); + return; + } + // Do not propagate uses, as their effects have been accounted for in effective statements + // FIXME: YANGTOOLS-652: this check is different from InferredStatementContext. Why is that? We should express + // a common condition in our own implementation of copyAsChildOf() + if (!YangStmtMapping.USES.equals(def)) { + original.copyAsChildOf(targetCtx, CopyType.ADDED_BY_USES, targetModule).ifPresent(buffer::add); + } + } + + private static QNameModule getNewQNameModule(final StmtContext targetCtx, + final StmtContext stmtContext) { + if (targetCtx.getParentContext() == null) { + return targetCtx.getFromNamespace(ModuleCtxToModuleQName.class, targetCtx); + } + if (targetCtx.getPublicDefinition() == YangStmtMapping.AUGMENT) { + return StmtContextUtils.getRootModuleQName(targetCtx); + } + + final Object targetStmtArgument = targetCtx.getStatementArgument(); + final Object sourceStmtArgument = stmtContext.getStatementArgument(); + if (targetStmtArgument instanceof QName && sourceStmtArgument instanceof QName) { + return ((QName) targetStmtArgument).getModule(); + } + + return null; + } + + private static void resolveUsesNode(final Mutable usesNode, + final StmtContext targetNodeStmtCtx) { + for (final Mutable subStmtCtx : usesNode.mutableDeclaredSubstatements()) { + if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class) + && areFeaturesSupported(subStmtCtx)) { + performRefine(subStmtCtx, targetNodeStmtCtx); + } + } + } + + private static boolean areFeaturesSupported(final StmtContext subStmtCtx) { + /* + * In case of Yang 1.1, checks whether features are supported. + */ + return !YangVersion.VERSION_1_1.equals(subStmtCtx.getRootVersion()) || subStmtCtx.isSupportedByFeatures(); + } + + private static void performRefine(final Mutable subStmtCtx, final StmtContext usesParentCtx) { + final Object refineArgument = subStmtCtx.getStatementArgument(); + InferenceException.throwIf(!(refineArgument instanceof SchemaNodeIdentifier), + subStmtCtx.getStatementSourceReference(), + "Invalid refine argument %s. It must be instance of SchemaNodeIdentifier.", refineArgument); + + final Optional> optRefineTargetCtx = ChildSchemaNodeNamespace.findNode( + usesParentCtx, (SchemaNodeIdentifier) refineArgument); + InferenceException.throwIf(!optRefineTargetCtx.isPresent(), subStmtCtx.getStatementSourceReference(), + "Refine target node %s not found.", refineArgument); + + final StmtContext refineTargetNodeCtx = optRefineTargetCtx.get(); + if (StmtContextUtils.isUnknownStatement(refineTargetNodeCtx)) { + LOG.trace("Refine node '{}' in uses '{}' has target node unknown statement '{}'. " + + "Refine has been skipped. At line: {}", subStmtCtx.getStatementArgument(), + subStmtCtx.coerceParentContext().getStatementArgument(), + refineTargetNodeCtx.getStatementArgument(), subStmtCtx.getStatementSourceReference()); + subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx); + return; + } + + Verify.verify(refineTargetNodeCtx instanceof StatementContextBase); + addOrReplaceNodes(subStmtCtx, (StatementContextBase) refineTargetNodeCtx); + subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx); + } + + private static void addOrReplaceNodes(final Mutable subStmtCtx, + final StatementContextBase refineTargetNodeCtx) { + for (final Mutable refineSubstatementCtx : subStmtCtx.mutableDeclaredSubstatements()) { + if (isSupportedRefineSubstatement(refineSubstatementCtx)) { + addOrReplaceNode(refineSubstatementCtx, refineTargetNodeCtx); + } + } + } + + private static void addOrReplaceNode(final Mutable refineSubstatementCtx, + final StatementContextBase refineTargetNodeCtx) { + + final StatementDefinition refineSubstatementDef = refineSubstatementCtx.getPublicDefinition(); + + SourceException.throwIf(!isSupportedRefineTarget(refineSubstatementCtx, refineTargetNodeCtx), + refineSubstatementCtx.getStatementSourceReference(), + "Error in module '%s' in the refine of uses '%s': can not perform refine of '%s' for the target '%s'.", + refineSubstatementCtx.getRoot().getStatementArgument(), + refineSubstatementCtx.coerceParentContext().getStatementArgument(), + refineSubstatementCtx.getPublicDefinition(), refineTargetNodeCtx.getPublicDefinition()); + + if (isAllowedToAddByRefine(refineSubstatementDef)) { + refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx); + } else { + refineTargetNodeCtx.removeStatementFromEffectiveSubstatements(refineSubstatementDef); + refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx); + } + } + + private static boolean isAllowedToAddByRefine(final StatementDefinition publicDefinition) { + return YangStmtMapping.MUST.equals(publicDefinition); + } + + private static boolean isSupportedRefineSubstatement(final StmtContext refineSubstatementCtx) { + final Collection supportedRefineSubstatements = refineSubstatementCtx.getFromNamespace( + ValidationBundlesNamespace.class, ValidationBundleType.SUPPORTED_REFINE_SUBSTATEMENTS); + + return supportedRefineSubstatements == null || supportedRefineSubstatements.isEmpty() + || supportedRefineSubstatements.contains(refineSubstatementCtx.getPublicDefinition()) + || StmtContextUtils.isUnknownStatement(refineSubstatementCtx); + } + + private static boolean isSupportedRefineTarget(final StmtContext refineSubstatementCtx, + final StmtContext refineTargetNodeCtx) { + final Collection supportedRefineTargets = YangValidationBundles.SUPPORTED_REFINE_TARGETS.get( + refineSubstatementCtx.getPublicDefinition()); + + return supportedRefineTargets == null || supportedRefineTargets.isEmpty() + || supportedRefineTargets.contains(refineTargetNodeCtx.getPublicDefinition()); + } +} diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java index a12cd19660..1318af957b 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java @@ -10,11 +10,14 @@ package org.opendaylight.yangtools.yang.parser.spi.meta; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; +import java.util.Optional; 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.StatementDefinition; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; /** * Class providing necessary support for processing a YANG statement. This class is intended to be subclassed @@ -97,18 +100,31 @@ public abstract class AbstractStatementSupport @Override public boolean hasArgumentSpecificSupports() { - // Most of statement supports don't have any argument specific - // supports, so return 'false'. + // Most of statement supports don't have any argument specific supports, so return 'false'. return false; } @Override public StatementSupport getSupportSpecificForArgument(final String argument) { - // Most of statement supports don't have any argument specific - // supports, so return null. + // Most of statement supports don't have any argument specific supports, so return null. return null; } + @Override + public Optional> copyAsChildOf(final Mutable stmt, + final Mutable parent, final CopyType copyType, final QNameModule targetModule) { + // Most of statement supports will just want to copy the statement + // FIXME: YANGTOOLS-694: that is not strictly true. Subclasses of this should indicate if they are themselves + // copy-sensitive: + // 1) if they are not and cannot be targeted by inference, and all their current + // substatements are also non-sensitive, we want to return the same context. + // 2) if they are not and their current substatements are sensitive, we want to copy + // as a lazily-instantiated interceptor to let it deal with substatements when needed + // (YANGTOOLS-1067 prerequisite) + // 3) otherwise perform this eager copy + return Optional.of(parent.childCopyOf(stmt, copyType, targetModule)); + } + /** * Returns corresponding substatement validator of a statement support. * diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java index 56545ccacf..45ab5b20d6 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java @@ -9,6 +9,8 @@ package org.opendaylight.yangtools.yang.parser.spi.meta; import com.google.common.annotations.Beta; import com.google.common.collect.ForwardingObject; +import java.util.Optional; +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.StatementDefinition; @@ -85,4 +87,10 @@ public abstract class ForwardingStatementSupport getSupportSpecificForArgument(final String argument) { return delegate().getSupportSpecificForArgument(argument); } + + @Override + public Optional> copyAsChildOf(final Mutable stmt, + final Mutable parent, final CopyType type, final QNameModule targetModule) { + return delegate().copyAsChildOf(stmt, parent, type, targetModule); + } } diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java index f9463a0f2f..fb30a4a612 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java @@ -17,6 +17,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.ArgumentDefinition; 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.StmtContext.Mutable; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; /** @@ -32,7 +33,6 @@ import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; */ public interface StatementSupport, E extends EffectiveStatement> extends StatementDefinition, StatementFactory { - /** * Returns public statement definition, which will be present in built statements. * @@ -57,11 +57,8 @@ public interface StatementSupport, E extends E /** * Adapts the argument value to match a new module. * - * @param ctx - * Context, which may be used to access source-specific - * namespaces required for parsing. - * @param targetModule - * Target module, may not be null. + * @param ctx Context, which may be used to access source-specific namespaces required for parsing. + * @param targetModule Target module, may not be null. * @return Adapted argument value. The default implementation returns original value stored in context. */ default A adaptArgumentValue(final StmtContext ctx, final QNameModule targetModule) { @@ -74,8 +71,7 @@ public interface StatementSupport, E extends E * accessible via {@link StmtContext#getParentContext()}. One such use is populating the parent's namespaces to * allow it to locate this child statement. * - * @param stmt - * Context of added statement. No substatements are available. + * @param stmt Context of added statement. No substatements are available. */ void onStatementAdded(StmtContext.Mutable stmt); @@ -87,8 +83,7 @@ public interface StatementSupport, E extends E * Implementation may use method to perform actions on this event or register modification action using * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}. * - * @param stmt - * Context of added statement. + * @param stmt Context of added statement. */ void onPreLinkageDeclared(StmtContext.Mutable stmt); @@ -100,10 +95,8 @@ public interface StatementSupport, E extends E * Implementation may use method to perform actions on this event or register modification action using * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}. * - * @param stmt - * Context of added statement. - * @throws SourceException - * when an inconsistency is detected. + * @param stmt Context of added statement. + * @throws SourceException when an inconsistency is detected. */ void onLinkageDeclared(StmtContext.Mutable stmt); @@ -115,11 +108,8 @@ public interface StatementSupport, E extends E * Implementation may use method to perform actions on this event or register modification action using * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}. * - * @param stmt - * Context of added statement. Argument and statement parent is - * accessible. - * @throws SourceException - * when an inconsistency is detected. + * @param stmt Context of added statement. Argument and statement parent is accessible. + * @throws SourceException when an inconsistency is detected. */ void onStatementDefinitionDeclared(StmtContext.Mutable stmt); @@ -131,11 +121,8 @@ public interface StatementSupport, E extends E * Implementation may use method to perform actions on this event or register modification action using * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}. * - * @param stmt - * Context of added statement. Argument and statement parent is - * accessible. - * @throws SourceException - * when an inconsistency is detected. + * @param stmt Context of added statement. Argument and statement parent is accessible. + * @throws SourceException when an inconsistency is detected. */ void onFullDefinitionDeclared(StmtContext.Mutable stmt); @@ -148,17 +135,34 @@ public interface StatementSupport, E extends E * If this support has argument specific supports, the method returns support specific for given argument * (e.g. type statement support need to be specialized based on its argument), otherwise returns null. * - * @param argument - * argument of statement + * @param argument argument of statement * @return statement support specific for supplied argument or null */ @Nullable StatementSupport getSupportSpecificForArgument(String argument); + /** + * Create an optional copy of specified statement as a substatement of parent. + * + *

+ * Note that while it may be tempting to return the same context, this is not safe in general case. It is only safe + * if the entire subtree is unaffected by changes to parent/namespace/history. This includes the semantics of this + * statement (it cannot be a target of any inference effects) as well as any substatements -- an extension statement + * is allowed pretty much anywhere and if its semantics are context-dependent, a simple instance reuse will not + * work. + * + * @param stmt Context of statement to be copied statement. + * @param parent Parent statement context + * @param type Type of copy being performed + * @param targetModule Target module, if present + * @return Empty if the statement should be ignored, or present with an instance that should be copied into parent. + */ + @NonNull Optional> copyAsChildOf(Mutable stmt, Mutable parent, + CopyType type, @Nullable QNameModule targetModule); + /** * Given a raw string representation of an argument, try to use a shared representation. * - * @param rawArgument - * Argument string + * @param rawArgument Argument string * @return A potentially-shard instance */ default String internArgument(final String rawArgument) { @@ -168,10 +172,9 @@ public interface StatementSupport, E extends E /** * Returns unknown statement form of a regular YANG statement supplied as a parameter to the method. * - * @param yangStmtDef - * statement definition of a regular yang statement - * @return Optional of unknown statement form of a regular yang statement or - * Optional.empty() if it is not supported by this statement support + * @param yangStmtDef statement definition of a regular YANG statement + * @return Optional of unknown statement form of a regular YANG statement or empty() if it is not supported by this + * statement support */ default Optional> getUnknownStatementDefinitionOf(final StatementDefinition yangStmtDef) { return Optional.empty(); diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java index fac8a7daec..91eb89a005 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java @@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.parser.spi.meta; import static com.google.common.base.Verify.verifyNotNull; +import com.google.common.annotations.Beta; import com.google.common.base.VerifyException; import com.google.common.collect.Iterables; import com.google.common.collect.Streams; @@ -296,6 +297,10 @@ public interface StmtContext, E extends Effect return childCopyOf(stmt, type, null); } + @Beta + @NonNull Optional> copyAsChildOf(Mutable parent, CopyType type, + @Nullable QNameModule targetModule); + @Override default Collection> declaredSubstatements() { return mutableDeclaredSubstatements(); diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java index 7d4ffbfe0f..1a0f9462b9 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java @@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.spi.meta; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; +import com.google.common.annotations.Beta; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import java.util.Collection; @@ -645,4 +646,16 @@ public final class StmtContextUtils { } return Optional.ofNullable(revision); } + + /** + * Determine if a specific statetement context is a child of a statement context which produces a grouping. + * + * @param stmt Statement to examine + * @return True if parent context is that of a grouping. + */ + @Beta + public static boolean isChildOfGrouping(final StmtContext stmt) { + final StmtContext parent = stmt.getParentContext(); + return parent != null && parent.getPublicDefinition() == YangStmtMapping.GROUPING; + } } -- 2.36.6