From e55154f0d2e8208ce1356ddbad281df343f3a508 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Tue, 19 Jan 2016 21:50:35 +0100 Subject: [PATCH] BUG-4684: validate changes against effective state In order to deal with merges, we would have to concoct a very fragile machinery, which would perform the equivalent of apply(), except it would not produce merged data. Instead of that let us pass down version, which is all we need to run the apply operation. Once applied, we will have a preliminary result of apply, which we can reuse under some circumstances -- which is if the observed current metadata node does not change and if the SchemaContext (and hence the associated SchemaAwareApplyOperation object) does not change. If either does, we re-calculate the result -- but that may not be accurate at this point. Change-Id: I145969e47136b324c07868bd00ded0764ef634f4 Signed-off-by: Robert Varga Signed-off-by: Filip.Gregor --- .../impl/schema/tree/AbstractDataTreeTip.java | 2 +- ...ractNodeContainerModificationStrategy.java | 14 +- ...AbstractValueNodeModificationStrategy.java | 3 +- .../impl/schema/tree/AlwaysFailOperation.java | 4 +- .../schema/tree/MinMaxElementsValidation.java | 126 ++++++++---------- .../tree/ModificationApplyOperation.java | 21 +-- .../data/impl/schema/tree/ModifiedNode.java | 15 +++ .../tree/RootModificationApplyOperation.java | 6 +- .../tree/SchemaAwareApplyOperation.java | 17 +-- ...ructuralContainerModificationStrategy.java | 7 +- .../tree/UnkeyedListModificationStrategy.java | 2 +- 11 files changed, 106 insertions(+), 111 deletions(-) diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractDataTreeTip.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractDataTreeTip.java index 677135ef78..76e41886eb 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractDataTreeTip.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractDataTreeTip.java @@ -35,7 +35,7 @@ abstract class AbstractDataTreeTip implements DataTreeTip { final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification; Preconditions.checkArgument(m.isSealed(), "Attempted to verify unsealed modification %s", m); - m.getStrategy().checkApplicable(PUBLIC_ROOT_PATH, m.getRootModification(), Optional.of(getTipRoot())); + m.getStrategy().checkApplicable(PUBLIC_ROOT_PATH, m.getRootModification(), Optional.of(getTipRoot()), m.getVersion()); } @Override diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java index 59ed52d04a..831c818647 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java @@ -8,7 +8,6 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import static com.google.common.base.Preconditions.checkArgument; - import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Verify; @@ -282,7 +281,7 @@ abstract class AbstractNodeContainerModificationStrategy extends SchemaAwareAppl @Override protected void checkTouchApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException { + final Optional current, final Version version) throws DataValidationFailedException { if (!modification.getOriginal().isPresent() && !current.isPresent()) { throw new ModifiedNodeDoesNotExistException(path, String.format("Node %s does not exist. Cannot apply modification to its children.", path)); } @@ -291,7 +290,7 @@ abstract class AbstractNodeContainerModificationStrategy extends SchemaAwareAppl throw new ConflictingModificationAppliedException(path, "Node was deleted by other transaction."); } - checkChildPreconditions(path, modification, current.get()); + checkChildPreconditions(path, modification, current.get(), version); } /** @@ -301,21 +300,22 @@ abstract class AbstractNodeContainerModificationStrategy extends SchemaAwareAppl * @param modification current modification * @param current Current data tree node. */ - private void checkChildPreconditions(final YangInstanceIdentifier path, final NodeModification modification, final TreeNode current) throws DataValidationFailedException { + private void checkChildPreconditions(final YangInstanceIdentifier path, final NodeModification modification, + final TreeNode current, final Version version) throws DataValidationFailedException { for (final NodeModification childMod : modification.getChildren()) { final YangInstanceIdentifier.PathArgument childId = childMod.getIdentifier(); final Optional childMeta = current.getChild(childId); final YangInstanceIdentifier childPath = path.node(childId); - resolveChildOperation(childId).checkApplicable(childPath, childMod, childMeta); + resolveChildOperation(childId).checkApplicable(childPath, childMod, childMeta, version); } } @Override protected void checkMergeApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException { + final Optional current, final Version version) throws DataValidationFailedException { if (current.isPresent()) { - checkChildPreconditions(path, modification, current.get()); + checkChildPreconditions(path, modification, current.get(), version); } } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractValueNodeModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractValueNodeModificationStrategy.java index e4b80b2fb5..ae7edda82b 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractValueNodeModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractValueNodeModificationStrategy.java @@ -8,7 +8,6 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import static com.google.common.base.Preconditions.checkArgument; - import com.google.common.base.Optional; import com.google.common.base.Preconditions; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -69,7 +68,7 @@ abstract class AbstractValueNodeModificationStrategy e @Override protected final void checkTouchApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws IncorrectDataStructureException { + final Optional current, final Version version) throws IncorrectDataStructureException { throw new IncorrectDataStructureException(path, "Subtree modification is not allowed."); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AlwaysFailOperation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AlwaysFailOperation.java index cd2455695a..42bef4314a 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AlwaysFailOperation.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AlwaysFailOperation.java @@ -34,8 +34,8 @@ final class AlwaysFailOperation extends ModificationApplyOperation { } @Override - void checkApplicable(final YangInstanceIdentifier path,final NodeModification modification, - final Optional storeMetadata) { + void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, + final Optional storeMetadata, final Version version) { throw new IllegalStateException("Schema Context is not available."); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/MinMaxElementsValidation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/MinMaxElementsValidation.java index ede5bcc067..032e1d8f45 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/MinMaxElementsValidation.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/MinMaxElementsValidation.java @@ -8,7 +8,6 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; - import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Verify; @@ -48,53 +47,45 @@ final class MinMaxElementsValidation extends SchemaAwareApplyOperation { } - private static int findChildrenBefore(final Optional current) { - if (current.isPresent()) { - return numOfChildrenFromValue(current.get().getData()); - } else { - return 0; + private void validateMinMaxElements(final YangInstanceIdentifier path, final PathArgument id, + final NormalizedNode data) throws DataValidationFailedException { + final int children = numOfChildrenFromValue(data); + if (minElements != null && minElements > children) { + throw new DataValidationFailedException(path, String.format( + "%s does not have enough elements (%s), needs at least %s", id, + children, minElements)); } - } - - private static int findChildrenAfter(final ModifiedNode modification) { - if (modification.getWrittenValue() != null) { - return numOfChildrenFromValue(modification.getWrittenValue()); - } else { - return 0; + if (maxElements != null && maxElements < children) { + throw new DataValidationFailedException(path, String.format( + "%s has too many elements (%s), can have at most %s", id, children, + maxElements)); } } private void checkMinMaxElements(final YangInstanceIdentifier path, final NodeModification nodeMod, - final Optional current) throws DataValidationFailedException { + final Optional current, final Version version) throws DataValidationFailedException { if (!(nodeMod instanceof ModifiedNode)) { LOG.debug("Could not validate {}, does not implement expected class {}", nodeMod, ModifiedNode.class); return; } final ModifiedNode modification = (ModifiedNode) nodeMod; - final int childrenBefore = (modification.getOperation() == LogicalOperation.WRITE) ? 0 : findChildrenBefore - (current); - Verify.verify(childrenBefore >= 0, "Child count before is %s (from %s)", childrenBefore, current); - final int childrenAfter = findChildrenAfter(modification); - Verify.verify(childrenAfter >= 0, "Child count after is %s (from %s)", childrenAfter, modification); + // We need to actually perform the operation to get deal with merge in a sane manner. We know the modification + // is immutable, so the result of validation will probably not change. + final Optional maybeApplied = delegate.apply(modification, current, version); + Verify.verify(maybeApplied.isPresent()); - final int childrenModified = numOfChildrenFromChildMods(modification, current); - LOG.debug("Modified child count is %s (from %s and %s)", childrenModified, modification, current); + final TreeNode applied = maybeApplied.get(); + validateMinMaxElements(path, modification.getIdentifier(), applied.getData()); - final int childrenTotal = childrenBefore + childrenAfter + childrenModified; - Verify.verify(childrenTotal >= 0, "Total child count is %s (from %s and %s)", childrenTotal, modification, current); - - if (minElements != null && minElements > childrenTotal) { - throw new DataValidationFailedException(path, String.format( - "%s does not have enough elements (%s), needs at least %s", modification.getIdentifier(), - childrenTotal, minElements)); - } - if (maxElements != null && maxElements < childrenTotal) { - throw new DataValidationFailedException(path, String.format( - "%s has too many elements (%s), can have at most %s", modification.getIdentifier(), childrenTotal, - maxElements)); - } + // Everything passed. We now have a snapshot of the result node, it would be too bad if we just threw it out. + // We know what the result of an apply operation is going to be *if* the following are kept unchanged: + // - the 'current' node + // - the schemacontext (therefore, the fact this object is associated with the modification) + // + // So let's stash the result. We will pick it up during apply operation. + modification.setValidatedNode(this, current, applied); } private static int numOfChildrenFromValue(final NormalizedNode value) { @@ -109,62 +100,31 @@ final class MinMaxElementsValidation extends SchemaAwareApplyOperation { value.getClass())); } - private static int numOfChildrenFromChildMods(final ModifiedNode modification, final Optional current) { - int result = 0; - for (final ModifiedNode modChild : modification.getChildren()) { - switch (modChild.getOperation()) { - case WRITE: - if (!checkOriginalPresent(modChild)) { - result++; - } - break; - case MERGE: - if (!checkOriginalPresent(modChild)) { - result++; - } - break; - case DELETE: - if (checkOriginalPresent(modChild)) { - result--; - } - break; - case NONE: - case TOUCH: - // NOOP - break; - default: - throw new IllegalArgumentException("Unsupported operation type: " + modChild.getOperation()); - } - } - return result; - } - private static boolean checkOriginalPresent(ModifiedNode child) { return child.getOriginal().isPresent(); } @Override protected void checkTouchApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException { - delegate.checkTouchApplicable(path, modification, current); - checkMinMaxElements(path, modification, current); + final Optional current, final Version version) throws DataValidationFailedException { + delegate.checkTouchApplicable(path, modification, current, version); + checkMinMaxElements(path, modification, current, version); } @Override protected void checkMergeApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException { - delegate.checkMergeApplicable(path, modification, current); - checkMinMaxElements(path, modification, current); + final Optional current, final Version version) throws DataValidationFailedException { + delegate.checkMergeApplicable(path, modification, current, version); + checkMinMaxElements(path, modification, current, version); } @Override protected void checkWriteApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException { - delegate.checkWriteApplicable(path, modification, current); - checkMinMaxElements(path, modification, current); + final Optional current, final Version version) throws DataValidationFailedException { + delegate.checkWriteApplicable(path, modification, current, version); + checkMinMaxElements(path, modification, current, version); } - @Override public Optional getChild(final PathArgument child) { return delegate.getChild(child); @@ -177,17 +137,35 @@ final class MinMaxElementsValidation extends SchemaAwareApplyOperation { @Override protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { + final TreeNode validated = modification.getValidatedNode(this, Optional.of(currentMeta)); + if (validated != null) { + return validated; + } + + // FIXME: the result moved, make sure we enforce again return delegate.applyMerge(modification, currentMeta, version); } @Override protected TreeNode applyTouch(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { + final TreeNode validated = modification.getValidatedNode(this, Optional.of(currentMeta)); + if (validated != null) { + return validated; + } + + // FIXME: the result moved, make sure we enforce again return delegate.applyTouch(modification, currentMeta, version); } @Override protected TreeNode applyWrite(final ModifiedNode modification, final Optional currentMeta, final Version version) { + final TreeNode validated = modification.getValidatedNode(this, currentMeta); + if (validated != null) { + return validated; + } + + // FIXME: the result moved, make sure we enforce again return delegate.applyWrite(modification, currentMeta, version); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationApplyOperation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationApplyOperation.java index 933bf9c570..83c9b6d041 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationApplyOperation.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationApplyOperation.java @@ -57,16 +57,17 @@ abstract class ModificationApplyOperation implements StoreTreeNode apply(ModifiedNode modification, Optional storeMeta, Version version); /** - * - * Checks if provided node modification could be applied to current metadata node. - * - * @param modification Modification - * @param current Metadata Node to which modification should be applied - * @return true if modification is applicable - * false if modification is no applicable - * @throws DataValidationFailedException - */ - abstract void checkApplicable(YangInstanceIdentifier path, NodeModification modification, Optional current) throws DataValidationFailedException; + * + * Checks if provided node modification could be applied to current metadata node. + * + * @param modification Modification + * @param current Metadata Node to which modification should be applied + * @param version + * @return true if modification is applicable + * false if modification is no applicable + * @throws DataValidationFailedException + */ + abstract void checkApplicable(YangInstanceIdentifier path, NodeModification modification, Optional current, Version version) throws DataValidationFailedException; /** * diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java index be0ed682ad..299a52b577 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java @@ -66,6 +66,11 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode validatedCurrent; + private TreeNode validatedNode; + private ModifiedNode(final PathArgument identifier, final Optional original, final ChildTrackingPolicy childPolicy) { this.identifier = identifier; this.original = original; @@ -346,4 +351,14 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode current, final TreeNode node) { + this.validatedOp = Preconditions.checkNotNull(op); + this.validatedCurrent = Preconditions.checkNotNull(current); + this.validatedNode = Preconditions.checkNotNull(node); + } + + TreeNode getValidatedNode(final SchemaAwareApplyOperation op, final Optional current) { + return op.equals(validatedOp) && current.equals(validatedCurrent) ? validatedNode : null; + } } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java index 6fc704c053..ead1ebff6d 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java @@ -67,9 +67,9 @@ abstract class RootModificationApplyOperation extends ModificationApplyOperation } @Override - final void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional current) - throws DataValidationFailedException { - getDelegate().checkApplicable(path, modification, current); + final void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, + final Optional current, final Version version) throws DataValidationFailedException { + getDelegate().checkApplicable(path, modification, current, version); } @Override diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java index a511ddf064..22a056fca3 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java @@ -115,19 +115,19 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation { } @Override - final void checkApplicable(final YangInstanceIdentifier path,final NodeModification modification, final Optional current) throws DataValidationFailedException { + final void checkApplicable(final YangInstanceIdentifier path,final NodeModification modification, final Optional current, final Version version) throws DataValidationFailedException { switch (modification.getOperation()) { case DELETE: checkDeleteApplicable(modification, current); break; case TOUCH: - checkTouchApplicable(path, modification, current); + checkTouchApplicable(path, modification, current, version); break; case WRITE: - checkWriteApplicable(path, modification, current); + checkWriteApplicable(path, modification, current, version); break; case MERGE: - checkMergeApplicable(path, modification, current); + checkMergeApplicable(path, modification, current, version); break; case NONE: break; @@ -136,7 +136,8 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation { } } - protected void checkMergeApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional current) throws DataValidationFailedException { + protected void checkMergeApplicable(final YangInstanceIdentifier path, final NodeModification modification, + final Optional current, final Version version) throws DataValidationFailedException { final Optional original = modification.getOriginal(); if (original.isPresent() && current.isPresent()) { /* @@ -162,7 +163,7 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation { * @throws DataValidationFailedException */ protected void checkWriteApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException { + final Optional current, final Version version) throws DataValidationFailedException { final Optional original = modification.getOriginal(); if (original.isPresent() && current.isPresent()) { checkNotConflicting(path, original.get(), current.get()); @@ -256,8 +257,8 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation { * @throws ConflictingModificationAppliedException If subtree was changed in conflicting way * @throws IncorrectDataStructureException If subtree modification is not applicable (e.g. leaf node). */ - protected abstract void checkTouchApplicable(YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException; + protected abstract void checkTouchApplicable(YangInstanceIdentifier path, NodeModification modification, + Optional current, Version version) throws DataValidationFailedException; /** * Checks if supplied schema node belong to specified Data Tree type. All nodes belong to the operational tree, diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/StructuralContainerModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/StructuralContainerModificationStrategy.java index be35b5aa67..55784e06b4 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/StructuralContainerModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/StructuralContainerModificationStrategy.java @@ -89,12 +89,13 @@ final class StructuralContainerModificationStrategy extends ModificationApplyOpe } @Override - void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional current) throws DataValidationFailedException { + void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, + final Optional current, final Version version) throws DataValidationFailedException { if (modification.getOperation() == LogicalOperation.TOUCH && !current.isPresent()) { // Structural containers are created as needed, so we pretend this container is here - delegate.checkApplicable(path, modification, fakeMeta(FAKE_VERSION)); + delegate.checkApplicable(path, modification, fakeMeta(FAKE_VERSION), version); } else { - delegate.checkApplicable(path, modification, current); + delegate.checkApplicable(path, modification, current, version); } } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnkeyedListModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnkeyedListModificationStrategy.java index d93d4971d1..4b569cef0e 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnkeyedListModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnkeyedListModificationStrategy.java @@ -132,7 +132,7 @@ final class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation { @Override protected void checkTouchApplicable(final YangInstanceIdentifier path, final NodeModification modification, - final Optional current) throws IncorrectDataStructureException { + final Optional current, final Version version) throws IncorrectDataStructureException { throw new IncorrectDataStructureException(path, "Subtree modification is not allowed."); } -- 2.36.6