+++ /dev/null
-/*
- * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.impl.schema.tree;
-
-import static com.google.common.base.Verify.verify;
-import static java.util.Objects.requireNonNull;
-
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.concepts.Immutable;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
-import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A path to a descendant which must exist. This really should be equivalent to YangInstanceIdentifier, but for now we
- * need to deal with up to two possible paths -- one with AugmentationIdentifiers and one without.
- */
-// FIXME: 8.0.0: remove this structure and just keep the 'path' YangInstanceIdentifier
-final class MandatoryDescendant implements Immutable {
- private static final Logger LOG = LoggerFactory.getLogger(MandatoryDescendant.class);
-
- // Correctly-nested path, mirroring Augmentation and choice/case structure
- private final @NonNull YangInstanceIdentifier path;
- // Legacy trivial path,
- private final @Nullable YangInstanceIdentifier legacyPath;
-
- private MandatoryDescendant(final YangInstanceIdentifier path, final YangInstanceIdentifier legacyPath) {
- this.path = requireNonNull(path);
- this.legacyPath = legacyPath;
- }
-
- static @NonNull MandatoryDescendant create(final YangInstanceIdentifier parentId,
- final DataNodeContainer parentSchema, final DataSchemaNode childSchema) {
- final NodeIdentifier childId = NodeIdentifier.create(childSchema.getQName());
-
- if (childSchema.isAugmenting()) {
- verify(parentSchema instanceof AugmentationTarget, "Unexpected augmenting child %s in non-target %s at %s",
- childSchema, parentSchema, parentId);
-
- final AugmentationSchemaNode aug = ((AugmentationTarget) parentSchema).getAvailableAugmentations().stream()
- .filter(augment -> augment.findDataChildByName(childSchema.getQName()).isPresent())
- .findFirst()
- .orElseThrow(() -> new IllegalArgumentException(String.format(
- "Node %s is marked as augmenting but is not present in the schema of %s", childSchema.getQName(),
- parentSchema)));
-
- return new MandatoryDescendant(
- parentId.node(DataSchemaContextNode.augmentationIdentifierFrom(aug)).node(childId).toOptimized(),
- parentId.node(childId).toOptimized());
- }
-
- return new MandatoryDescendant(parentId.node(childId).toOptimized(), null);
- }
-
- void enforceOnData(final NormalizedNode<?, ?> data) {
- // Find try primary path first ...
- if (NormalizedNodes.findNode(data, path).isPresent()) {
- return;
- }
- // ... if we have a legacy path, try that as well ...
- if (legacyPath != null) {
- if (NormalizedNodes.findNode(data, legacyPath).isPresent()) {
- // .. this should not really be happening ...
- LOG.debug("Found {} at alternate path {}", path, legacyPath);
- return;
- }
- }
-
- // ... not found, report the error
- throw new IllegalArgumentException(String.format("Node %s is missing mandatory descendant %s",
- data.getIdentifier(), path));
- }
-
- @Override
- public String toString() {
- return legacyPath == null ? path.toString() : "(" + path + " || " + legacyPath + ")";
- }
-}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.tree;
+import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import com.google.common.collect.ImmutableList;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
final class MandatoryLeafEnforcer implements Immutable {
private static final Logger LOG = LoggerFactory.getLogger(MandatoryLeafEnforcer.class);
- private final ImmutableList<MandatoryDescendant> mandatoryNodes;
+ private final ImmutableList<YangInstanceIdentifier> mandatoryNodes;
- private MandatoryLeafEnforcer(final ImmutableList<MandatoryDescendant> mandatoryNodes) {
+ private MandatoryLeafEnforcer(final ImmutableList<YangInstanceIdentifier> mandatoryNodes) {
this.mandatoryNodes = requireNonNull(mandatoryNodes);
}
+
static Optional<MandatoryLeafEnforcer> forContainer(final DataNodeContainer schema,
final DataTreeConfiguration treeConfig) {
if (!treeConfig.isMandatoryNodesValidationEnabled()) {
return Optional.empty();
}
- final Builder<MandatoryDescendant> builder = ImmutableList.builder();
+ final Builder<YangInstanceIdentifier> builder = ImmutableList.builder();
findMandatoryNodes(builder, YangInstanceIdentifier.empty(), schema, treeConfig.getTreeType());
- final ImmutableList<MandatoryDescendant> mandatoryNodes = builder.build();
+ final ImmutableList<YangInstanceIdentifier> mandatoryNodes = builder.build();
return mandatoryNodes.isEmpty() ? Optional.empty() : Optional.of(new MandatoryLeafEnforcer(mandatoryNodes));
}
void enforceOnData(final NormalizedNode<?, ?> data) {
- mandatoryNodes.forEach(node -> node.enforceOnData(data));
+ for (final YangInstanceIdentifier id : mandatoryNodes) {
+ checkArgument(NormalizedNodes.findNode(data, id).isPresent(),
+ "Node %s is missing mandatory descendant %s", data.getIdentifier(), id);
+ }
}
void enforceOnTreeNode(final TreeNode tree) {
enforceOnData(tree.getData());
}
- private static void findMandatoryNodes(final Builder<MandatoryDescendant> builder,
- final YangInstanceIdentifier id, final DataNodeContainer schema, final TreeType type) {
+ private static void findMandatoryNodes(final Builder<YangInstanceIdentifier> builder,
+ final YangInstanceIdentifier id, final DataNodeContainer schema, final TreeType type) {
for (final DataSchemaNode child : schema.getChildNodes()) {
if (SchemaAwareApplyOperation.belongsToTree(type, child)) {
if (child instanceof ContainerSchemaNode) {
final ContainerSchemaNode container = (ContainerSchemaNode) child;
if (!container.isPresenceContainer()) {
- findMandatoryNodes(builder,
- id.node(NodeIdentifier.create(container.getQName())), container, type);
+ findMandatoryNodes(builder, id.node(NodeIdentifier.create(child.getQName())), container, type);
}
} else {
boolean needEnforce = child instanceof MandatoryAware && ((MandatoryAware) child).isMandatory();
if (!needEnforce && child instanceof ElementCountConstraintAware) {
- needEnforce = ((ElementCountConstraintAware) child).getElementCountConstraint()
- .map(constraint -> {
- final Integer min = constraint.getMinElements();
- return min != null && min > 0;
- })
- .orElse(Boolean.FALSE);
+ needEnforce = ((ElementCountConstraintAware) child)
+ .getElementCountConstraint().map(constraint -> {
+ final Integer min = constraint.getMinElements();
+ return min != null && min > 0;
+ }).orElse(Boolean.FALSE).booleanValue();
}
if (needEnforce) {
- final MandatoryDescendant desc = MandatoryDescendant.create(id, schema, child);
- LOG.debug("Adding mandatory child {}", desc);
- builder.add(desc);
+ final YangInstanceIdentifier childId = id.node(NodeIdentifier.create(child.getQName()));
+ LOG.debug("Adding mandatory child {}", childId);
+ builder.add(childId.toOptimized());
}
}
}
+++ /dev/null
-/*
- * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.impl.schema.tree;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
-
-import java.util.Set;
-import java.util.function.Consumer;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
-
-public class YT1276Test {
- private static final QName FOO = QName.create("foo", "foo");
- private static final QName BAR = QName.create(FOO, "bar");
- private static final QName BAZ = QName.create(FOO, "baz");
- private static final QName XYZZY_LEAF = QName.create(FOO, "xyzzy-leaf");
- private static final QName XYZZY_AUGMENT = QName.create(FOO, "xyzzy-augment");
-
- private static EffectiveModelContext MODEL;
-
- private final DataTree tree = new InMemoryDataTreeFactory()
- .create(DataTreeConfiguration.DEFAULT_CONFIGURATION, MODEL);
-
- @BeforeClass
- public static void beforeClass() {
- MODEL = YangParserTestUtils.parseYangResource("/yt1276.yang");
- }
-
- @Test
- public void testFooWithBar() throws DataValidationFailedException {
- applyOperation(mod -> {
- mod.write(YangInstanceIdentifier.of(FOO), Builders.containerBuilder()
- .withNodeIdentifier(new NodeIdentifier(FOO))
- .withChild(Builders.augmentationBuilder()
- .withNodeIdentifier(new AugmentationIdentifier(Set.of(BAR)))
- .withChild(ImmutableNodes.leafNode(BAR, "xyzzy"))
- .build())
- .build());
- });
- }
-
- @Test
- @Deprecated
- public void testFooWithBarLegacy() throws DataValidationFailedException {
- applyOperation(mod -> {
- mod.write(YangInstanceIdentifier.of(FOO), Builders.containerBuilder()
- .withNodeIdentifier(new NodeIdentifier(FOO))
- .withChild(ImmutableNodes.leafNode(BAR, "xyzzy"))
- .build());
- });
- }
-
- @Test
- public void testFooWithoutBar() {
- final IllegalArgumentException ex = assertFailsReady(mod -> {
- mod.write(YangInstanceIdentifier.of(FOO), Builders.containerBuilder()
- .withNodeIdentifier(new NodeIdentifier(FOO))
- .build());
- });
- assertEquals(
- "Node (foo)foo is missing mandatory descendant /AugmentationIdentifier{childNames=[(foo)bar]}/(foo)bar",
- ex.getMessage());
- }
-
- @Test
- public void testBarWithXyzzy() throws DataValidationFailedException {
- applyOperation(mod -> {
- mod.write(YangInstanceIdentifier.of(BAR), Builders.containerBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAR))
- .withChild(Builders.choiceBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAZ))
- .withChild(ImmutableNodes.leafNode(XYZZY_LEAF, "xyzzy"))
- .withChild(Builders.augmentationBuilder()
- .withNodeIdentifier(new AugmentationIdentifier(Set.of(XYZZY_AUGMENT)))
- .withChild(ImmutableNodes.leafNode(XYZZY_AUGMENT, "xyzzy"))
- .build())
- .build())
- .build());
- });
- }
-
- @Test
- @Deprecated
- public void testBarWithXyzzyLegacy() throws DataValidationFailedException {
- applyOperation(mod -> {
- mod.write(YangInstanceIdentifier.of(BAR), Builders.containerBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAR))
- .withChild(Builders.choiceBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAZ))
- .withChild(ImmutableNodes.leafNode(XYZZY_LEAF, "xyzzy"))
- .withChild(ImmutableNodes.leafNode(XYZZY_AUGMENT, "xyzzy"))
- .build())
- .build());
- });
- }
-
- @Test
- public void testBarWithoutXyzzyLeaf() {
- final IllegalArgumentException ex = assertFailsReady(mod -> {
- mod.write(YangInstanceIdentifier.of(BAR), Builders.containerBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAR))
- .withChild(Builders.choiceBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAZ))
- .withChild(Builders.augmentationBuilder()
- .withNodeIdentifier(new AugmentationIdentifier(Set.of(XYZZY_AUGMENT)))
- .withChild(ImmutableNodes.leafNode(XYZZY_AUGMENT, "xyzzy"))
- .build())
- .build())
- .build());
- });
- assertEquals(
- "Node (foo)baz is missing mandatory descendant /(foo)xyzzy-leaf",
- ex.getMessage());
- }
-
- @Test
- public void testBarWithoutXyzzyAugment() {
- final IllegalArgumentException ex = assertFailsReady(mod -> {
- mod.write(YangInstanceIdentifier.of(BAR), Builders.containerBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAR))
- .withChild(Builders.choiceBuilder()
- .withNodeIdentifier(new NodeIdentifier(BAZ))
- .withChild(ImmutableNodes.leafNode(XYZZY_LEAF, "xyzzy"))
- .build())
- .build());
- });
- assertEquals("Node (foo)baz is missing mandatory descendant "
- + "/AugmentationIdentifier{childNames=[(foo)xyzzy-augment]}/(foo)xyzzy-augment",
- ex.getMessage());
-
- }
-
- private IllegalArgumentException assertFailsReady(final Consumer<DataTreeModification> operation) {
- return assertThrows(IllegalArgumentException.class, () -> applyOperation(operation));
- }
-
- private void applyOperation(final Consumer<DataTreeModification> operation)
- throws DataValidationFailedException {
- final DataTreeModification mod = tree.takeSnapshot().newModification();
- operation.accept(mod);
- mod.ready();
- tree.commit(tree.prepare(mod));
- }
-}
+++ /dev/null
-module foo {
- namespace foo;
- prefix foo;
-
- container foo {
- presence blah;
- }
-
- augment /foo {
- leaf bar {
- type string;
- mandatory true;
- }
- }
-
- container bar {
- presence blah;
-
- choice baz {
- case xyzzy-case {
- leaf xyzzy-leaf {
- type string;
- mandatory true;
- }
- }
- }
- }
-
- augment /bar/baz/xyzzy-case {
- leaf xyzzy-augment {
- type string;
- mandatory true;
- }
- }
-}
-