*/
package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
-import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangVersion;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ActionStatement;
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.NotificationStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement;
@Override
public SchemaNodeIdentifier parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
- Preconditions.checkArgument(!PATH_REL_PATTERN1.matcher(value).matches()
- && !PATH_REL_PATTERN2.matcher(value).matches(),
- "An argument for augment can be only absolute path; or descendant if used in uses");
+ SourceException.throwIf(PATH_REL_PATTERN1.matcher(value).matches()
+ || PATH_REL_PATTERN2.matcher(value).matches(), ctx.getStatementSourceReference(),
+ "Augment argument \'%s\' is not valid, it can be only absolute path; or descendant if used in uses",
+ value);
return Utils.nodeIdentifierFromPath(ctx, value);
}
return;
}
- SUBSTATEMENT_VALIDATOR.validate(augmentNode);
+ super.onFullDefinitionDeclared(augmentNode);
if (StmtContextUtils.isInExtensionBody(augmentNode)) {
return;
augmentTargetCtx.addEffectiveSubstatement(augmentSourceCtx);
updateAugmentOrder(augmentSourceCtx);
} catch (final SourceException e) {
- LOG.debug("Failed to add augmentation {} defined at {}",
+ LOG.warn("Failed to add augmentation {} defined at {}",
augmentTargetCtx.getStatementSourceReference(),
augmentSourceCtx.getStatementSourceReference(), e);
}
final CopyType typeOfCopy = UsesStatement.class.equals(sourceCtx.getParentContext().getPublicDefinition()
.getDeclaredRepresentationClass()) ? 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 Collection<StatementContextBase<?, ?, ?>> declared = sourceCtx.declaredSubstatements();
final Collection<StatementContextBase<?, ?, ?>> effective = sourceCtx.effectiveSubstatements();
for (final StatementContextBase<?, ?, ?> originalStmtCtx : declared) {
if (StmtContextUtils.areFeaturesSupported(originalStmtCtx)) {
- copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer);
+ copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer, skipCheckOfMandatoryNodes);
}
}
for (final StatementContextBase<?, ?, ?> originalStmtCtx : effective) {
- copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer);
+ copyStatement(originalStmtCtx, targetCtx, typeOfCopy, buffer, skipCheckOfMandatoryNodes);
}
targetCtx.addEffectiveSubstatements(buffer);
}
+ /**
+ * Checks whether supplied statement context is conditional augment
+ * statement.
+ *
+ * @param ctx
+ * statement context to be checked
+ *
+ * @return true if supplied statement context is conditional augment
+ * statement, otherwise false
+ */
+ private static boolean isConditionalAugmentStmt(final StatementContextBase<?, ?, ?> ctx) {
+ return ctx.getPublicDefinition() == YangStmtMapping.AUGMENT
+ && StmtContextUtils.findFirstSubstatement(ctx, WhenStatement.class) != null;
+ }
+
private static void copyStatement(final StatementContextBase<?, ?, ?> original,
final StatementContextBase<?, ?, ?> target, final CopyType typeOfCopy,
- final Collection<StatementContextBase<?, ?, ?>> buffer) {
+ final Collection<StatementContextBase<?, ?, ?>> buffer, final boolean skipCheckOfMandatoryNodes) {
if (needToCopyByAugment(original)) {
- validateNodeCanBeCopiedByAugment(original, target, typeOfCopy);
+ validateNodeCanBeCopiedByAugment(original, target, typeOfCopy, skipCheckOfMandatoryNodes);
final StatementContextBase<?, ?, ?> copy = original.createCopy(target, typeOfCopy);
buffer.add(copy);
}
private static void validateNodeCanBeCopiedByAugment(final StatementContextBase<?, ?, ?> sourceCtx,
- final StatementContextBase<?, ?, ?> targetCtx, final CopyType typeOfCopy) {
+ final StatementContextBase<?, ?, ?> targetCtx, final CopyType typeOfCopy, final boolean skipCheckOfMandatoryNodes) {
if (WhenStatement.class.equals(sourceCtx.getPublicDefinition().getDeclaredRepresentationClass())) {
return;
}
- if (typeOfCopy == CopyType.ADDED_BY_AUGMENTATION && reguiredCheckOfMandatoryNodes(sourceCtx, targetCtx)) {
+ if (!skipCheckOfMandatoryNodes && typeOfCopy == CopyType.ADDED_BY_AUGMENTATION
+ && reguiredCheckOfMandatoryNodes(sourceCtx, targetCtx)) {
checkForMandatoryNodes(sourceCtx);
}
* b) added to augment body also via uses of a grouping and
* such sub-statements are stored in effective sub-statements collection.
*/
- for (final StatementContextBase<?, ?, ?> sourceSubStatement : Iterables.concat(
- sourceCtx.declaredSubstatements(), sourceCtx.declaredSubstatements())) {
- checkForMandatoryNodes(sourceSubStatement);
- }
+ sourceCtx.declaredSubstatements().forEach(Definition::checkForMandatoryNodes);
+ sourceCtx.effectiveSubstatements().forEach(Definition::checkForMandatoryNodes);
}
InferenceException.throwIf(StmtContextUtils.isMandatoryNode(sourceCtx),
}
/*
- * If target or one of its parent is a presence container from
- * the same module, return false and skip mandatory nodes
- * validation
+ * If target or one of the target's ancestors from the same namespace
+ * is a presence container
+ * or is non-mandatory choice
+ * or is non-mandatory list
+ * return false and skip mandatory nodes validation, because these nodes
+ * are not mandatory node containers according to RFC 6020 section 3.1.
*/
- if (StmtContextUtils.isPresenceContainer(targetCtx)) {
+ if (StmtContextUtils.isPresenceContainer(targetCtx)
+ || StmtContextUtils.isNotMandatoryNodeOfType(targetCtx, YangStmtMapping.CHOICE)
+ || StmtContextUtils.isNotMandatoryNodeOfType(targetCtx, YangStmtMapping.LIST)) {
return false;
}
} while ((targetCtx = targetCtx.getParentContext()) != root);
|| allowedAugmentTargets.contains(substatementCtx.getPublicDefinition());
}
+ @Override
+ protected SubstatementValidator getSubstatementValidator() {
+ return SUBSTATEMENT_VALIDATOR;
+ }
+
}
@Nonnull
public Collection<? extends DataDefinitionStatement> getDataDefinitions() {
return allDeclared(DataDefinitionStatement.class);
}
+
+ @Nonnull
+ @Override
+ public Collection<? extends ActionStatement> getActions() {
+ return allDeclared(ActionStatement.class);
+ }
+
+ @Override
+ public final Collection<? extends NotificationStatement> getNotifications() {
+ return allDeclared(NotificationStatement.class);
+ }
}