Promote MandatorLeafEnforcer 11/109411/3
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 23 Dec 2023 02:40:05 +0000 (03:40 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 23 Dec 2023 15:54:50 +0000 (16:54 +0100)
This is a very useful utility, promote it to data.spi.node, so it is
easily accessible.

JIRA: YANGTOOLS-980
Change-Id: I90c1320b5e3aa8fda19c50e3aeefde493da01341
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
data/yang-data-spi/src/main/java/org/opendaylight/yangtools/yang/data/spi/node/MandatoryLeafEnforcer.java [moved from data/yang-data-tree-ri/src/main/java/org/opendaylight/yangtools/yang/data/tree/impl/MandatoryLeafEnforcer.java with 85% similarity]
data/yang-data-tree-ri/src/main/java/module-info.java
data/yang-data-tree-ri/src/main/java/org/opendaylight/yangtools/yang/data/tree/impl/CaseEnforcer.java
data/yang-data-tree-ri/src/main/java/org/opendaylight/yangtools/yang/data/tree/impl/ContainerModificationStrategy.java
data/yang-data-tree-ri/src/main/java/org/opendaylight/yangtools/yang/data/tree/impl/MapEntryModificationStrategy.java
data/yang-data-tree-ri/src/main/java/org/opendaylight/yangtools/yang/data/tree/impl/SchemaAwareApplyOperation.java

similarity index 85%
rename from data/yang-data-tree-ri/src/main/java/org/opendaylight/yangtools/yang/data/tree/impl/MandatoryLeafEnforcer.java
rename to data/yang-data-spi/src/main/java/org/opendaylight/yangtools/yang/data/spi/node/MandatoryLeafEnforcer.java
index 421291f718e4108a9a831128ef6f0900dd5bbc5e..e102fc4f5f4ba63796843dea8c7f8b074850107f 100644 (file)
@@ -5,7 +5,7 @@
  * 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.tree.impl;
+package org.opendaylight.yangtools.yang.data.spi.node;
 
 import static java.util.Objects.requireNonNull;
 
@@ -18,9 +18,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
-import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
-import org.opendaylight.yangtools.yang.data.tree.api.TreeType;
-import org.opendaylight.yangtools.yang.data.tree.impl.node.TreeNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraintAware;
@@ -28,8 +25,7 @@ import org.opendaylight.yangtools.yang.model.api.MandatoryAware;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-// TODO: would making this Serializable be useful (for Functions and similar?)
-final class MandatoryLeafEnforcer implements Immutable {
+public final class MandatoryLeafEnforcer implements Immutable {
     private static final Logger LOG = LoggerFactory.getLogger(MandatoryLeafEnforcer.class);
 
     // FIXME: Well, there is still room to optimize footprint and performance. This list of lists can have overlaps,
@@ -71,19 +67,16 @@ final class MandatoryLeafEnforcer implements Immutable {
         this.mandatoryNodes = requireNonNull(mandatoryNodes);
     }
 
-    static @Nullable MandatoryLeafEnforcer forContainer(final DataNodeContainer schema,
-            final DataTreeConfiguration treeConfig) {
-        if (!treeConfig.isMandatoryNodesValidationEnabled()) {
-            return null;
-        }
+    public static @Nullable MandatoryLeafEnforcer forContainer(final DataNodeContainer schema,
+            final boolean includeConfigFalse) {
 
         final var builder = ImmutableList.<ImmutableList<PathArgument>>builder();
-        findMandatoryNodes(builder, YangInstanceIdentifier.of(), schema, treeConfig.getTreeType());
+        findMandatoryNodes(builder, YangInstanceIdentifier.of(), schema, includeConfigFalse);
         final var mandatoryNodes = builder.build();
         return mandatoryNodes.isEmpty() ? null : new MandatoryLeafEnforcer(mandatoryNodes);
     }
 
-    void enforceOnData(final NormalizedNode data) {
+    public void enforceOnData(final NormalizedNode data) {
         for (var path : mandatoryNodes) {
             if (NormalizedNodes.findNode(data, path).isEmpty()) {
                 throw new IllegalArgumentException("Node " + data.name() + " is missing mandatory descendant "
@@ -92,14 +85,10 @@ final class MandatoryLeafEnforcer implements Immutable {
         }
     }
 
-    void enforceOnTreeNode(final TreeNode tree) {
-        enforceOnData(tree.getData());
-    }
-
     private static void findMandatoryNodes(final Builder<ImmutableList<PathArgument>> builder,
-            final YangInstanceIdentifier id, final DataNodeContainer schema, final TreeType type) {
+            final YangInstanceIdentifier id, final DataNodeContainer schema, final boolean includeConfigFalse) {
         for (var child : schema.getChildNodes()) {
-            if (SchemaAwareApplyOperation.belongsToTree(type, child)) {
+            if (includeConfigFalse || child.effectiveConfig().orElse(Boolean.TRUE)) {
                 if (child instanceof ContainerSchemaNode container) {
                     if (!container.isPresenceContainer()) {
                         // the container is either:
@@ -107,7 +96,7 @@ final class MandatoryLeafEnforcer implements Immutable {
                         //    - in an augmented subtree
                         // in both cases just append the NodeID to the ongoing ID and continue the search.
                         findMandatoryNodes(builder, id.node(NodeIdentifier.create(container.getQName())), container,
-                            type);
+                            includeConfigFalse);
                     }
                 } else {
                     boolean needEnforce = child instanceof MandatoryAware aware && aware.isMandatory();
index 40be366ec6a176d2711ab28dac23f323dfaf125e..5b9d5f20cc090c249e97c3a205956d37410d67ef 100644 (file)
@@ -22,6 +22,7 @@ module org.opendaylight.yangtools.yang.data.tree {
     requires org.opendaylight.yangtools.yang.data.impl;
     requires org.opendaylight.yangtools.yang.data.spi;
     requires org.opendaylight.yangtools.yang.data.util;
+    requires org.opendaylight.yangtools.yang.model.api;
     requires org.slf4j;
 
     // Annotations
index eb5e22f65d707ab864d8c9f85573b49e2e80828d..d0cb67fd76bd532466c7acfe7437264b0e9b2bf5 100644 (file)
@@ -10,12 +10,12 @@ package org.opendaylight.yangtools.yang.data.tree.impl;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
 import java.util.Map.Entry;
 import java.util.Set;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.spi.node.MandatoryLeafEnforcer;
 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
 import org.opendaylight.yangtools.yang.data.tree.api.TreeType;
 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
@@ -44,22 +44,27 @@ class CaseEnforcer implements Immutable {
     }
 
     static CaseEnforcer forTree(final CaseSchemaNode schema, final DataTreeConfiguration treeConfig) {
-        final TreeType type = treeConfig.getTreeType();
-        final Builder<NodeIdentifier, DataSchemaNode> childrenBuilder = ImmutableMap.builder();
-        if (SchemaAwareApplyOperation.belongsToTree(type, schema)) {
-            for (final DataSchemaNode child : schema.getChildNodes()) {
-                if (SchemaAwareApplyOperation.belongsToTree(type, child)) {
+        final var treeType = treeConfig.getTreeType();
+        final var childrenBuilder = ImmutableMap.<NodeIdentifier, DataSchemaNode>builder();
+        if (SchemaAwareApplyOperation.belongsToTree(treeType, schema)) {
+            for (var child : schema.getChildNodes()) {
+                if (SchemaAwareApplyOperation.belongsToTree(treeType, child)) {
                     childrenBuilder.put(NodeIdentifier.create(child.getQName()), child);
                 }
             }
         }
 
-        final ImmutableMap<NodeIdentifier, DataSchemaNode> children = childrenBuilder.build();
+        final var children = childrenBuilder.build();
         if (children.isEmpty()) {
             return null;
         }
-        final var enforcer = MandatoryLeafEnforcer.forContainer(schema, treeConfig);
-        return enforcer != null ? new EnforcingMandatory(children, enforcer) : new CaseEnforcer(children);
+        if (treeConfig.isMandatoryNodesValidationEnabled()) {
+            final var enforcer = MandatoryLeafEnforcer.forContainer(schema, treeType == TreeType.OPERATIONAL);
+            if (enforcer != null) {
+                return new EnforcingMandatory(children, enforcer);
+            }
+        }
+        return new CaseEnforcer(children);
     }
 
     final Set<Entry<NodeIdentifier, DataSchemaNode>> getChildEntries() {
index f0955272bf746ee13bba96680a42f4394a377d91..8f19ede2d3e65224bc57f9a939f8fbfaaff88d5e 100644 (file)
@@ -9,12 +9,14 @@ package org.opendaylight.yangtools.yang.data.tree.impl;
 
 import static java.util.Objects.requireNonNull;
 
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DistinctNodeContainer;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.spi.node.MandatoryLeafEnforcer;
 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
 import org.opendaylight.yangtools.yang.data.tree.impl.node.TreeNode;
 import org.opendaylight.yangtools.yang.data.tree.impl.node.Version;
@@ -44,25 +46,24 @@ sealed class ContainerModificationStrategy extends DataNodeContainerModification
         @Override
         protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
                 final Version version) {
-            final var ret = super.applyMerge(modification, currentMeta, version);
-            enforcer.enforceOnTreeNode(ret);
-            return ret;
+            return enforce(super.applyMerge(modification, currentMeta, version));
         }
 
         @Override
         protected TreeNode applyWrite(final ModifiedNode modification, final NormalizedNode newValue,
                 final TreeNode currentMeta, final Version version) {
-            final var ret = super.applyWrite(modification, newValue, currentMeta, version);
-            enforcer.enforceOnTreeNode(ret);
-            return ret;
+            return enforce(super.applyWrite(modification, newValue, currentMeta, version));
         }
 
         @Override
         protected TreeNode applyTouch(final ModifiedNode modification, final TreeNode currentMeta,
                 final Version version) {
-            final var ret = super.applyTouch(modification, currentMeta, version);
-            enforcer.enforceOnTreeNode(ret);
-            return ret;
+            return enforce(super.applyTouch(modification, currentMeta, version));
+        }
+
+        private @NonNull TreeNode enforce(final TreeNode treeNode) {
+            enforcer.enforceOnData(treeNode.getData());
+            return treeNode;
         }
     }
 
@@ -104,7 +105,7 @@ sealed class ContainerModificationStrategy extends DataNodeContainerModification
 
     static ContainerModificationStrategy of(final ContainerSchemaNode schema, final DataTreeConfiguration treeConfig) {
         if (schema.isPresenceContainer()) {
-            final var enforcer = MandatoryLeafEnforcer.forContainer(schema, treeConfig);
+            final var enforcer = enforcerFor(schema, treeConfig);
             return enforcer != null ? new EnforcingMandatory(schema, treeConfig, enforcer)
                 : new ContainerModificationStrategy(schema, treeConfig);
         }
index a809b0da2c06332f480a206d00aa27577470cd6d..dbdabf4ca412dfd1350381a8019c2e98ac599071 100644 (file)
@@ -15,6 +15,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.DistinctNodeContainer;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.spi.node.MandatoryLeafEnforcer;
 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
 import org.opendaylight.yangtools.yang.data.tree.impl.node.TreeNode;
 import org.opendaylight.yangtools.yang.data.tree.impl.node.Version;
@@ -38,25 +39,24 @@ sealed class MapEntryModificationStrategy extends DataNodeContainerModificationS
         @Override
         protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
                 final Version version) {
-            final var ret = super.applyMerge(modification, currentMeta, version);
-            enforcer.enforceOnTreeNode(ret);
-            return ret;
+            return enforce(super.applyMerge(modification, currentMeta, version));
         }
 
         @Override
         protected TreeNode applyWrite(final ModifiedNode modification, final NormalizedNode newValue,
                 final TreeNode currentMeta, final Version version) {
-            final var ret = super.applyWrite(modification, newValue, currentMeta, version);
-            enforcer.enforceOnTreeNode(ret);
-            return ret;
+            return enforce(super.applyWrite(modification, newValue, currentMeta, version));
         }
 
         @Override
         protected TreeNode applyTouch(final ModifiedNode modification, final TreeNode currentMeta,
                 final Version version) {
-            final var ret = super.applyTouch(modification, currentMeta, version);
-            enforcer.enforceOnTreeNode(ret);
-            return ret;
+            return enforce(super.applyTouch(modification, currentMeta, version));
+        }
+
+        private @NonNull TreeNode enforce(final TreeNode treeNode) {
+            enforcer.enforceOnData(treeNode.getData());
+            return treeNode;
         }
     }
 
@@ -70,7 +70,7 @@ sealed class MapEntryModificationStrategy extends DataNodeContainerModificationS
 
     static @NonNull MapEntryModificationStrategy of(final ListSchemaNode schema,
             final DataTreeConfiguration treeConfig) {
-        final var enforcer = MandatoryLeafEnforcer.forContainer(schema, treeConfig);
+        final var enforcer = enforcerFor(schema, treeConfig);
         return enforcer != null ? new EnforcingMandatory(schema, treeConfig, enforcer)
             : new MapEntryModificationStrategy(schema, treeConfig);
     }
index 741d6fd3a61374203c31a602d6cd7ae3a557ef40..709569a3380493d6a01d9e508fed91d246a52480 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.AnydataNode;
 import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.spi.node.MandatoryLeafEnforcer;
 import org.opendaylight.yangtools.yang.data.tree.api.ConflictingModificationAppliedException;
 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
 import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
@@ -30,6 +31,7 @@ import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
@@ -293,4 +295,15 @@ abstract sealed class SchemaAwareApplyOperation<T extends DataSchemaNode> extend
     static final boolean belongsToTree(final TreeType treeType, final DataSchemaNode node) {
         return treeType == TreeType.OPERATIONAL || node.effectiveConfig().orElse(Boolean.TRUE);
     }
+
+    static final @Nullable MandatoryLeafEnforcer enforcerFor(final DataSchemaNode schema,
+            final DataTreeConfiguration treeConfig) {
+        if (treeConfig.isMandatoryNodesValidationEnabled() && schema instanceof DataNodeContainer container) {
+            final var includeConfigFalse = treeConfig.getTreeType() == TreeType.OPERATIONAL;
+            if (includeConfigFalse || schema.effectiveConfig().orElse(Boolean.TRUE)) {
+                return MandatoryLeafEnforcer.forContainer(container, includeConfigFalse);
+            }
+        }
+        return null;
+    }
 }