X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-rfc7950%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Frfc7950%2Fstmt%2Faugment%2FAbstractAugmentStatementSupport.java;h=5c85334c3cdaf196a7fe16bf0e9df12f60de89f7;hb=6682a8e2a8c02ed7a66bddb8b7a86009ffbbb98d;hp=18093dc432d9bf111c5e698d4357683d3e638f03;hpb=509988128ed9d5fe314a14906114f53778200e47;p=yangtools.git diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/augment/AbstractAugmentStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/augment/AbstractAugmentStatementSupport.java index 18093dc432..5c85334c3c 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/augment/AbstractAugmentStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/augment/AbstractAugmentStatementSupport.java @@ -7,45 +7,55 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.augment; +import static com.google.common.base.Verify.verify; + import com.google.common.base.Verify; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.regex.Pattern; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.YangVersion; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +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; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement; import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionStatement; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement; -import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace; +import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.ArgumentUtils; -import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStatementSupport; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder; +import org.opendaylight.yangtools.yang.parser.spi.SchemaTreeNamespace; 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; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; 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.AugmentToChoiceNamespace; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; -import org.opendaylight.yangtools.yang.parser.spi.source.StmtOrderingNamespace; 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; -abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport> { +abstract class AbstractAugmentStatementSupport + extends BaseStatementSupport { private static final Logger LOG = LoggerFactory.getLogger(AbstractAugmentStatementSupport.class); private static final Pattern PATH_REL_PATTERN1 = Pattern.compile("\\.\\.?\\s*/(.+)"); private static final Pattern PATH_REL_PATTERN2 = Pattern.compile("//.*"); @@ -65,22 +75,11 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< } @Override - public final AugmentStatement createDeclared(final StmtContext ctx) { - return new AugmentStatementImpl(ctx); - } - - @Override - public final EffectiveStatement createEffective( - final StmtContext> ctx) { - return new AugmentEffectiveStatementImpl(ctx); - } - - @Override - public final void onFullDefinitionDeclared(final Mutable> augmentNode) { + public final void onFullDefinitionDeclared( + final Mutable augmentNode) { if (!augmentNode.isSupportedByFeatures()) { - return; + // We need this augment node to be present, but it should not escape to effective world + augmentNode.setIsSupportedToBuildEffective(false); } super.onFullDefinitionDeclared(augmentNode); @@ -89,18 +88,15 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< return; } - final ModelActionBuilder augmentAction = augmentNode.newInferenceAction( - ModelProcessingPhase.EFFECTIVE_MODEL); - final Prerequisite>> sourceCtxPrereq = - augmentAction.requiresCtx(augmentNode, ModelProcessingPhase.EFFECTIVE_MODEL); - final Prerequisite>> target = - augmentAction.mutatesEffectiveCtxPath(getSearchRoot(augmentNode), - ChildSchemaNodeNamespace.class, augmentNode.getStatementArgument().getPathFromRoot()); + final ModelActionBuilder augmentAction = augmentNode.newInferenceAction(ModelProcessingPhase.EFFECTIVE_MODEL); + augmentAction.requiresCtx(augmentNode, ModelProcessingPhase.EFFECTIVE_MODEL); + final Prerequisite>> target = augmentAction.mutatesEffectiveCtxPath( + getSearchRoot(augmentNode), SchemaTreeNamespace.class, + augmentNode.coerceStatementArgument().getNodeIdentifiers()); - augmentAction.apply(new ModelActionBuilder.InferenceAction() { + augmentAction.apply(new InferenceAction() { @Override - public void apply(final ModelActionBuilder.InferenceContext ctx) { + public void apply(final InferenceContext ctx) { final StatementContextBase augmentTargetCtx = (StatementContextBase) target.resolve(ctx); if (!isSupportedAugmentTarget(augmentTargetCtx) @@ -108,20 +104,19 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< augmentNode.setIsSupportedToBuildEffective(false); return; } - /** - * Marks case short hand in augment - */ - if (augmentTargetCtx.getPublicDefinition() == YangStmtMapping.CHOICE) { - augmentNode.addToNs(AugmentToChoiceNamespace.class, augmentNode, Boolean.TRUE); + + // We are targeting a context which is creating implicit nodes. In order to keep things consistent, + // we will need to circle back when creating effective statements. + if (augmentTargetCtx.hasImplicitParentSupport()) { + augmentNode.addToNs(AugmentImplicitHandlingNamespace.class, augmentNode, augmentTargetCtx); } + final StatementContextBase augmentSourceCtx = (StatementContextBase) augmentNode; // FIXME: this is a workaround for models which augment a node which is added via an extension // which we do not handle. This needs to be reworked in terms of unknown schema nodes. - final StatementContextBase augmentSourceCtx = (StatementContextBase) augmentNode; try { copyFromSourceToTarget(augmentSourceCtx, augmentTargetCtx); augmentTargetCtx.addEffectiveSubstatement(augmentSourceCtx); - updateAugmentOrder(augmentSourceCtx); } catch (final SourceException e) { LOG.warn("Failed to add augmentation {} defined at {}", augmentTargetCtx.getStatementSourceReference(), @@ -129,31 +124,19 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< } } - private void updateAugmentOrder(final StatementContextBase augmentSourceCtx) { - Integer currentOrder = augmentSourceCtx.getFromNamespace(StmtOrderingNamespace.class, - YangStmtMapping.AUGMENT); - if (currentOrder == null) { - currentOrder = 1; - } else { - currentOrder++; - } - - augmentSourceCtx.addToNs(StmtOrderingNamespace.class, YangStmtMapping.AUGMENT, currentOrder); - } - @Override - public void prerequisiteFailed(final Collection> failed) { + public void prerequisiteFailed(final Collection> failed) { /* * Do not fail, if it is an uses-augment to an unknown node. */ - if (YangStmtMapping.USES == augmentNode.getParentContext().getPublicDefinition()) { - final Optional> targetNode = ChildSchemaNodeNamespace.findNode( - getSearchRoot(augmentNode), augmentNode.getStatementArgument()); + if (YangStmtMapping.USES == augmentNode.coerceParentContext().getPublicDefinition()) { + final SchemaNodeIdentifier augmentArg = augmentNode.coerceStatementArgument(); + final Optional> targetNode = SchemaTreeNamespace.findNode( + getSearchRoot(augmentNode), augmentArg); if (targetNode.isPresent() && StmtContextUtils.isUnknownStatement(targetNode.get())) { augmentNode.setIsSupportedToBuildEffective(false); - LOG.warn( - "Uses-augment to unknown node {}. Augmentation has not been performed. At line: {}", - augmentNode.getStatementArgument(), augmentNode.getStatementSourceReference()); + LOG.warn("Uses-augment to unknown node {}. Augmentation has not been performed. At line: {}", + augmentArg, augmentNode.getStatementSourceReference()); return; } } @@ -164,9 +147,54 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< }); } + @Override + protected final AugmentStatement createDeclared(final StmtContext ctx, + final ImmutableList> substatements) { + return new RegularAugmentStatement(ctx.coerceRawStatementArgument(), ctx.coerceStatementArgument(), + substatements); + } + + @Override + protected final AugmentStatement createEmptyDeclared( + final StmtContext ctx) { + return new EmptyAugmentStatement(ctx.coerceRawStatementArgument(), ctx.coerceStatementArgument()); + } + + @Override + protected final List> statementsToBuild( + final StmtContext ctx, + final List> substatements) { + final StatementContextBase implicitDef = ctx.getFromNamespace(AugmentImplicitHandlingNamespace.class, + ctx); + return implicitDef == null ? substatements : Lists.transform(substatements, subCtx -> { + verify(subCtx instanceof StatementContextBase); + return implicitDef.wrapWithImplicit((StatementContextBase) subCtx); + }); + } + + @Override + protected final AugmentEffectiveStatement createEffective( + final StmtContext ctx, + final AugmentStatement declared, final ImmutableList> substatements) { + final int flags = new FlagsBuilder() + .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT)) + .toFlags(); + + return new AugmentEffectiveStatementImpl(declared, ctx.coerceStatementArgument(), flags, + StmtContextUtils.getRootModuleQName(ctx), substatements, ctx.getStatementSourceReference(), + (AugmentationSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null)); + } + + @Override + protected final AugmentEffectiveStatement createEmptyEffective( + final StmtContext ctx, + final AugmentStatement declared) { + return createEffective(ctx, declared, ImmutableList.of()); + } + private static StmtContext getSearchRoot(final StmtContext augmentContext) { - final StmtContext parent = augmentContext.getParentContext(); // Augment is in uses - we need to augment instantiated nodes in parent. + final StmtContext parent = augmentContext.coerceParentContext(); if (YangStmtMapping.USES == parent.getPublicDefinition()) { return parent.getParentContext(); } @@ -175,27 +203,26 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< static void copyFromSourceToTarget(final StatementContextBase sourceCtx, final StatementContextBase targetCtx) { - final CopyType typeOfCopy = UsesStatement.class.equals(sourceCtx.getParentContext().getPublicDefinition() - .getDeclaredRepresentationClass()) ? CopyType.ADDED_BY_USES_AUGMENTATION - : CopyType.ADDED_BY_AUGMENTATION; + final CopyType typeOfCopy = sourceCtx.coerceParentContext().producesDeclared(UsesStatement.class) + ? CopyType.ADDED_BY_USES_AUGMENTATION : CopyType.ADDED_BY_AUGMENTATION; /* * Since Yang 1.1, if an augmentation is made conditional with a * "when" statement, it is allowed to add mandatory nodes. */ final boolean skipCheckOfMandatoryNodes = YangVersion.VERSION_1_1.equals(sourceCtx.getRootVersion()) && isConditionalAugmentStmt(sourceCtx); + final boolean unsupported = !sourceCtx.isSupportedByFeatures(); final Collection> declared = sourceCtx.mutableDeclaredSubstatements(); final Collection> effective = sourceCtx.mutableEffectiveSubstatements(); final Collection> buffer = new ArrayList<>(declared.size() + effective.size()); for (final Mutable originalStmtCtx : declared) { - if (originalStmtCtx.isSupportedByFeatures()) { - copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer, skipCheckOfMandatoryNodes); - } + copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer, skipCheckOfMandatoryNodes, + unsupported || !originalStmtCtx.isSupportedByFeatures()); } for (final Mutable originalStmtCtx : effective) { - copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer, skipCheckOfMandatoryNodes); + copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer, skipCheckOfMandatoryNodes, unsupported); } targetCtx.addEffectiveSubstatements(buffer); @@ -212,18 +239,27 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< * statement, otherwise false */ private static boolean isConditionalAugmentStmt(final StmtContext ctx) { - return ctx.getPublicDefinition() == YangStmtMapping.AUGMENT - && StmtContextUtils.findFirstSubstatement(ctx, WhenStatement.class) != null; + return ctx.getPublicDefinition() == YangStmtMapping.AUGMENT && hasWhenSubstatement(ctx); + } + + private static boolean hasWhenSubstatement(final StmtContext ctx) { + return ctx.hasSubstatement(WhenEffectiveStatement.class); } private static void copyStatement(final Mutable original, final StatementContextBase target, final CopyType typeOfCopy, final Collection> buffer, - final boolean skipCheckOfMandatoryNodes) { + final boolean skipCheckOfMandatoryNodes, final boolean unsupported) { + // We always copy statements, but if either the source statement or the augmentation which causes it are not + // supported to build we also mark the target as such. if (needToCopyByAugment(original)) { validateNodeCanBeCopiedByAugment(original, target, typeOfCopy, skipCheckOfMandatoryNodes); - buffer.add(target.childCopyOf(original, typeOfCopy)); - } else if (isReusedByAugment(original)) { + final Mutable copy = target.childCopyOf(original, typeOfCopy); + if (unsupported) { + copy.setIsSupportedToBuildEffective(false); + } + buffer.add(copy); + } else if (isReusedByAugment(original) && !unsupported) { buffer.add(original); } } @@ -231,23 +267,15 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< private static void validateNodeCanBeCopiedByAugment(final StmtContext sourceCtx, final StatementContextBase targetCtx, final CopyType typeOfCopy, final boolean skipCheckOfMandatoryNodes) { - - if (WhenStatement.class.equals(sourceCtx.getPublicDefinition().getDeclaredRepresentationClass())) { - return; - } - if (!skipCheckOfMandatoryNodes && typeOfCopy == CopyType.ADDED_BY_AUGMENTATION - && reguiredCheckOfMandatoryNodes(sourceCtx, targetCtx)) { + && requireCheckOfMandatoryNodes(sourceCtx, targetCtx)) { checkForMandatoryNodes(sourceCtx); } // Data definition statements must not collide on their namespace - if (DataDefinitionStatement.class.isAssignableFrom( - sourceCtx.getPublicDefinition().getDeclaredRepresentationClass())) { + if (sourceCtx.producesDeclared(DataDefinitionStatement.class)) { for (final StmtContext subStatement : targetCtx.allSubstatements()) { - if (DataDefinitionStatement.class.isAssignableFrom( - subStatement.getPublicDefinition().getDeclaredRepresentationClass())) { - + if (subStatement.producesDeclared(DataDefinitionStatement.class)) { InferenceException.throwIf( Objects.equals(sourceCtx.getStatementArgument(), subStatement.getStatementArgument()), sourceCtx.getStatementSourceReference(), @@ -276,23 +304,25 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< sourceCtx.rawStatementArgument()); } - private static boolean reguiredCheckOfMandatoryNodes(final StmtContext sourceCtx, + private static boolean requireCheckOfMandatoryNodes(final StmtContext sourceCtx, Mutable targetCtx) { /* * If the statement argument is not QName, it cannot be mandatory * statement, therefore return false and skip mandatory nodes validation */ - if (!(sourceCtx.getStatementArgument() instanceof QName)) { + final Object arg = sourceCtx.getStatementArgument(); + if (!(arg instanceof QName)) { return false; } - final QName sourceStmtQName = (QName) sourceCtx.getStatementArgument(); + final QName sourceStmtQName = (QName) arg; // RootStatementContext, for example final Mutable root = targetCtx.getRoot(); do { - Verify.verify(targetCtx.getStatementArgument() instanceof QName, - "Argument of augment target statement must be QName."); - final QName targetStmtQName = (QName) targetCtx.getStatementArgument(); + final Object targetArg = targetCtx.getStatementArgument(); + Verify.verify(targetArg instanceof QName, "Argument of augment target statement must be QName, not %s", + targetArg); + final QName targetStmtQName = (QName) targetArg; /* * If target is from another module, return true and perform mandatory nodes validation */ @@ -313,6 +343,22 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< || StmtContextUtils.isNotMandatoryNodeOfType(targetCtx, YangStmtMapping.LIST)) { return false; } + + // This could be an augmentation stacked on top of a previous augmentation from the same module, which is + // conditional -- in which case we do not run further checks + if (targetCtx.getCopyHistory().getLastOperation() == CopyType.ADDED_BY_AUGMENTATION) { + final Optional> optPrevCopy = targetCtx.getPreviousCopyCtx(); + if (optPrevCopy.isPresent()) { + final StmtContext original = optPrevCopy.get(); + final Object origArg = original.coerceStatementArgument(); + Verify.verify(origArg instanceof QName, "Unexpected statement argument %s", origArg); + + if (sourceStmtQName.getModule().equals(((QName) origArg).getModule()) + && hasWhenSubstatement(getParentAugmentation(original))) { + return false; + } + } + } } while ((targetCtx = targetCtx.getParentContext()) != root); /* @@ -322,14 +368,22 @@ abstract class AbstractAugmentStatementSupport extends AbstractStatementSupport< return false; } - private static final Set NOCOPY_DEF_SET = ImmutableSet.of(YangStmtMapping.USES, + private static StmtContext getParentAugmentation(final StmtContext child) { + StmtContext parent = Verify.verifyNotNull(child.getParentContext(), "Child %s has not parent", child); + while (parent.getPublicDefinition() != YangStmtMapping.AUGMENT) { + parent = Verify.verifyNotNull(parent.getParentContext(), "Failed to find augmentation parent of %s", child); + } + return parent; + } + + private static final ImmutableSet NOCOPY_DEF_SET = ImmutableSet.of(YangStmtMapping.USES, YangStmtMapping.WHEN, YangStmtMapping.DESCRIPTION, YangStmtMapping.REFERENCE, YangStmtMapping.STATUS); private static boolean needToCopyByAugment(final StmtContext stmtContext) { return !NOCOPY_DEF_SET.contains(stmtContext.getPublicDefinition()); } - private static final Set REUSED_DEF_SET = ImmutableSet.of(YangStmtMapping.TYPEDEF); + private static final ImmutableSet REUSED_DEF_SET = ImmutableSet.of(YangStmtMapping.TYPEDEF); private static boolean isReusedByAugment(final StmtContext stmtContext) { return REUSED_DEF_SET.contains(stmtContext.getPublicDefinition());