From: Robert Varga Date: Wed, 2 Mar 2022 08:15:03 +0000 (+0100) Subject: Tolerate children not being present X-Git-Tag: v8.0.0~15 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=yangtools.git;a=commitdiff_plain;h=81f38342831f259f93e0d35f3f1ddc6f0e90b91f Tolerate children not being present Augment's children are subject to deviations at augment target, hence we need to check for their presence. Also add some sorely-missing documentation as to what this class actually does. JIRA: YANGTOOLS-1404 Change-Id: I98cce6b2a8bff74658a16553f93eb8049dd038b7 Signed-off-by: Robert Varga --- diff --git a/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java b/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java index 0813e676d7..5c4a8598a1 100644 --- a/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java +++ b/model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java @@ -32,9 +32,29 @@ import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement; import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression.QualifiedBound; /** - * Proxy for AugmentationSchema. Child node schemas are replaced with actual schemas from parent. + * Proxy for AugmentationSchema. Child node schemas are replaced with actual schemas from parent. This is needed to + * correctly interpret constructs like this: + *
+ *   
+ *     container foo;
+ *
+ *     augment /foo {
+ *       container bar;
+ *     }
+ *
+ *     augment /foo/bar {
+ *       container baz;
+ *     }
+ *   
+ * 
+ * The {@link AugmentationSchemaNode} returned for {@code augment /foo} contains bare {@code container bar}, e.g. it + * does not show {@code augment /foo/bar} as an available augmentation -- this is only visible in {@code foo}'s schema + * nodes. + * + *

+ * Note this class only handles {@link DataSchemaNode}s, not all {@code schema tree} statements, as it strictly should. */ -// FIXME: 7.0.0: re-evaluate the need for this class and potentially its effective statement replacement +// FIXME: YANGTOOLS-1403: this functionality should be integrated into EffectiveAugmentStatement/AugmentationSchemaNode public final class EffectiveAugmentationSchema implements AugmentationSchemaNode { private final AugmentationSchemaNode delegate; private final ImmutableSet realChildSchemas; @@ -42,7 +62,7 @@ public final class EffectiveAugmentationSchema implements AugmentationSchemaNode public EffectiveAugmentationSchema(final AugmentationSchemaNode augmentSchema, final Collection realChildSchemas) { - this.delegate = requireNonNull(augmentSchema); + delegate = requireNonNull(augmentSchema); this.realChildSchemas = ImmutableSet.copyOf(realChildSchemas); final Map m = new HashMap<>(realChildSchemas.size()); @@ -50,7 +70,7 @@ public final class EffectiveAugmentationSchema implements AugmentationSchemaNode m.put(realChildSchema.getQName(), realChildSchema); } - this.mappedChildSchemas = ImmutableMap.copyOf(m); + mappedChildSchemas = ImmutableMap.copyOf(m); } /** @@ -61,10 +81,16 @@ public final class EffectiveAugmentationSchema implements AugmentationSchemaNode * @return Adjusted Augmentation schema * @throws NullPointerException if any of the arguments is null */ + // FIXME: 8.0.0: integrate this method into the constructor public static AugmentationSchemaNode create(final AugmentationSchemaNode schema, final DataNodeContainer parent) { - Set children = new HashSet<>(); + final Set children = new HashSet<>(); for (DataSchemaNode augNode : schema.getChildNodes()) { - children.add(parent.getDataChildByName(augNode.getQName())); + // parent may have the corresponding child removed via 'deviate unsupported', i.e. the child is effectively + // not present at the target site + final DataSchemaNode child = parent.dataChildByName(augNode.getQName()); + if (child != null) { + children.add(child); + } } return new EffectiveAugmentationSchema(schema, children); } diff --git a/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1404Test.java b/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1404Test.java new file mode 100644 index 0000000000..63e597fd3e --- /dev/null +++ b/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1404Test.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 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.model.util; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import com.google.common.collect.Iterables; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class YT1404Test { + 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"); + + @Test + public void testDeviatedEffectiveAugmentationSchema() { + final var module = YangParserTestUtils.parseYangResourceDirectory("/yt1404").findModule("foo").orElseThrow(); + final var augment = Iterables.getOnlyElement(module.getAugmentations()); + assertEquals(2, augment.getChildNodes().size()); + assertThat(augment.dataChildByName(BAR), instanceOf(LeafSchemaNode.class)); + assertThat(augment.dataChildByName(BAZ), instanceOf(LeafSchemaNode.class)); + + final var foo = module.getDataChildByName(FOO); + assertThat(foo, instanceOf(ContainerSchemaNode.class)); + final var fooCont = (ContainerSchemaNode) foo; + assertEquals(1, fooCont.getChildNodes().size()); + final var fooBar = fooCont.dataChildByName(BAR); + assertThat(fooBar, instanceOf(LeafSchemaNode.class)); + + final var fooAugment = Iterables.getOnlyElement(fooCont.getAvailableAugmentations()); + assertSame(augment, fooAugment); + + final var effectiveAug = EffectiveAugmentationSchema.create(augment, fooCont); + assertEquals(1, effectiveAug.getChildNodes().size()); + assertSame(fooBar, effectiveAug.getDataChildByName(BAR)); + } +} diff --git a/model/yang-model-util/src/test/resources/yt1404/dev.yang b/model/yang-model-util/src/test/resources/yt1404/dev.yang new file mode 100644 index 0000000000..30f50a59f4 --- /dev/null +++ b/model/yang-model-util/src/test/resources/yt1404/dev.yang @@ -0,0 +1,13 @@ +module dev { + namespace dev; + prefix dev; + + import foo { + prefix foo; + } + + deviation /foo:foo/foo:baz { + deviate not-supported; + } +} + diff --git a/model/yang-model-util/src/test/resources/yt1404/foo.yang b/model/yang-model-util/src/test/resources/yt1404/foo.yang new file mode 100644 index 0000000000..93fdf34ca7 --- /dev/null +++ b/model/yang-model-util/src/test/resources/yt1404/foo.yang @@ -0,0 +1,16 @@ +module foo { + namespace foo; + prefix foo; + + container foo; + + augment /foo { + leaf bar { + type string; + } + leaf baz { + type string; + } + } +} +