Implement edit-config operations for NormalizedNode yang-data-api 70/5670/19
authorMaros Marsalek <mmarsale@cisco.com>
Wed, 19 Mar 2014 08:54:15 +0000 (09:54 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Fri, 28 Mar 2014 08:18:55 +0000 (08:18 +0000)
Placed in a new module yang-data-operations

Supported operations: all defined in http://tools.ietf.org/html/rfc6241
Multiple positive and negative test cases added. Testing yang schema can be found under src/test/resources

Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Change-Id: I897c6479cf14e7073a6fb954565cfe2b376a6c40

88 files changed:
yang/pom.xml
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/AbstractImmutableDataContainerNodeBuilder.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/ImmutableContainerNodeBuilder.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/nodes/AbstractImmutableDataContainerNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/SchemaUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/DomUtils.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/dom/serializer/NormalizedNodeXmlTranslationTest.java
yang/yang-data-json/src/test/java/org/opendaylight/yangtools/yang/data/json/schema/cnsn/serializer/SerializeNormalizedStructToCnSnStructTest.java
yang/yang-data-operations/pom.xml [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/AbstractContainerNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/AugmentationNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ContainerNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataModificationException.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataOperations.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/LeafNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/LeafSetNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/MapEntryNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/MapNodeModification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/Modification.java [new file with mode: 0644]
yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/OperationStack.java [new file with mode: 0644]
yang/yang-data-operations/src/test/java/org/opendaylight/yangtools/yang/data/operations/YangDataOperationsNegativeTest.java [new file with mode: 0644]
yang/yang-data-operations/src/test/java/org/opendaylight/yangtools/yang/data/operations/YangDataOperationsTest.java [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/schemas/test.yang [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_choiceModificationMultipleCasesReferenced/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_choiceModificationMultipleCasesReferenced/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_createContainerActualPresent/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_createContainerActualPresent/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_deleteContainerActualMissing/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_noneContainerActualMissing/defaultOperation.txt [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_noneContainerActualMissing/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_createLeafActualPresent/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_createLeafActualPresent/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_deleteLeafActualMissing/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_deleteLeafActualMissing/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_createLeafActualPresent/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_createLeafActualPresent/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_deleteLeafActualMissing/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_deleteLeafActualMissing/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/listTest_createListActualPresent/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/listTest_createListActualPresent/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/listTest_deleteListActualMissing/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/listTest_deleteListActualMissing/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/defaultOperation.txt [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_createContainer/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_createContainer/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_deleteContainer/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_deleteContainer/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/defaultOperation.txt [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_removeContainer/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_removeContainer/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/leafListTest/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/leafListTest/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/leafListTest/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/listTest/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/listTest/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/listTest/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/defaultOperation.txt [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/result.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/none_NoChange/current.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/none_NoChange/defaultOperation.txt [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/none_NoChange/merge.xml [new file with mode: 0644]
yang/yang-data-operations/src/test/resources/xmls/none_NoChange/result.xml [new file with mode: 0644]

index 9bd59cdda81b57008f894ff25d74677478b70f14..2806937f7ebcaf8b9d68f2d2872b1ccce4a566a0 100644 (file)
@@ -25,6 +25,7 @@
         <module>yang-data-api</module>
         <module>yang-data-util</module>
         <module>yang-data-impl</module>
+        <module>yang-data-operations</module>
         <module>yang-model-api</module>
         <module>yang-maven-plugin</module>
         <module>yang-maven-plugin-it</module>
                 <artifactId>yang-data-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-data-impl</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-data-util</artifactId>
index af71a675c1c7e56674f2f1fad1e659ead8695a83..5647cb9aeb59691221e1481d1a0a2163c740467f 100644 (file)
@@ -25,7 +25,7 @@ abstract class AbstractImmutableDataContainerNodeBuilder<I extends InstanceIdent
     protected I nodeIdentifier;
 
     protected AbstractImmutableDataContainerNodeBuilder() {
-        this.value = Maps.newLinkedHashMap();
+        this.value = Maps.newHashMap();
     }
 
     @Override
index 54671ea6717aadb3693d81f823324ffea68d77b6..03e12adc88887b64c2481bb29161098834b4c43f 100644 (file)
@@ -39,6 +39,5 @@ public class ImmutableContainerNodeBuilder extends
                 final Map<QName, String> attributes) {
             super(ImmutableMap.copyOf(children), nodeIdentifier, attributes);
         }
-
     }
 }
index 2cac25dbb8412d9060da31d2f07b7e889e2a1e4c..020c364fe52967088c80eab05476dd7182b740f5 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.data.impl.schema.nodes;
 
 import java.util.Map;
 
+import com.google.common.collect.ImmutableSet;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
@@ -26,7 +27,7 @@ public abstract class AbstractImmutableDataContainerNode<K extends PathArgument>
 
     public AbstractImmutableDataContainerNode(
             final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> children, final K nodeIdentifier) {
-        super(nodeIdentifier, ImmutableList.copyOf(children.values()));
+        super(nodeIdentifier, ImmutableSet.copyOf(children.values()));
         this.children = children;
     }
 
index 9e08fc2f39f1b8bd079ba6847d7aceed35dce02f..b4df8fe2c694ce4437e8b86a0e87a5c68485da3d 100644 (file)
@@ -16,6 +16,8 @@ import com.google.common.collect.Collections2;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
 import org.opendaylight.yangtools.yang.model.api.*;
@@ -275,13 +277,31 @@ public final class SchemaUtils {
 
     public static Optional<ChoiceCaseNode> detectCase(ChoiceNode schema, DataContainerChild<?, ?> child) {
         for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
-            for (DataSchemaNode childFromCase : choiceCaseNode.getChildNodes()) {
-                if (childFromCase.getQName().equals(child.getNodeType())) {
-                    return Optional.of(choiceCaseNode);
-                }
+            if (child instanceof AugmentationNode
+                    && belongsToCaseAugment(choiceCaseNode,
+                            (InstanceIdentifier.AugmentationIdentifier) child.getIdentifier())) {
+                return Optional.of(choiceCaseNode);
+            } else if (choiceCaseNode.getDataChildByName(child.getNodeType()) != null) {
+                return Optional.of(choiceCaseNode);
             }
         }
 
         return Optional.absent();
     }
+
+    public static boolean belongsToCaseAugment(ChoiceCaseNode caseNode, InstanceIdentifier.AugmentationIdentifier childToProcess) {
+        for (AugmentationSchema augmentationSchema : caseNode.getAvailableAugmentations()) {
+
+            Set<QName> currentAugmentChildNodes = Sets.newHashSet();
+            for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) {
+                currentAugmentChildNodes.add(dataSchemaNode.getQName());
+            }
+
+            if(childToProcess.getPossibleChildNames().equals(currentAugmentChildNodes)){
+                return true;
+            }
+        }
+
+        return false;
+    }
 }
index 669630fa9ba2cfea81a739c17915ffba999462ee..afcbe358c48c9bf717623e95a759d38640759eb8 100644 (file)
@@ -98,7 +98,7 @@ public class DomUtils {
                 namespace = "";
             }
 
-            // SKip namespace definitions
+            // Skip namespace definitions
             if(namespace.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
                 continue;
             }
index 84ca9f540079f18f05f8e904fd81abe2aa882391..8bfa0ff286013b95c180c91ca8d2db9106ef2d60 100644 (file)
@@ -32,6 +32,7 @@ import javax.xml.transform.TransformerFactoryConfigurationError;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.custommonkey.xmlunit.Diff;
 import org.custommonkey.xmlunit.XMLAssert;
 import org.custommonkey.xmlunit.XMLUnit;
 import org.junit.Test;
@@ -251,8 +252,10 @@ public class NormalizedNodeXmlTranslationTest {
         XMLUnit.setIgnoreWhitespace(true);
         XMLUnit.setIgnoreComments(true);
 
-        XMLAssert.assertXMLEqual(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
-                XMLUnit.buildTestDocument(toString(el)));
+        System.err.println(toString(doc.getDocumentElement()));
+        System.err.println(toString(el));
+
+        boolean diff = new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), XMLUnit.buildTestDocument(toString(el))).similar();
     }
 
     private Document loadDocument(String xmlPath) throws Exception {
index 635c18b377772451d3ea3ce45add96f27582ecf1..5e1283fbafcefbd4bba77b4680a5b41e0dbba210 100644 (file)
@@ -13,6 +13,7 @@ import static org.junit.Assert.assertNotNull;
 import java.net.URISyntaxException;
 import java.util.Set;
 
+import com.google.common.collect.Sets;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -46,6 +47,10 @@ public class SerializeNormalizedStructToCnSnStructTest {
         assertNotNull(serialized.iterator().hasNext());
 
         CompositeNode compNode = TestUtils.prepareCompositeNodeStruct();
-        assertEquals(serialized.iterator().next(), compNode);
+
+        assertEquals(serialized.iterator().next().getNodeType(), compNode.getNodeType());
+
+        Set<Node<?>> value = Sets.newHashSet(((CompositeNode)serialized.iterator().next()).getValue());
+        assertEquals(value, Sets.newHashSet(compNode.getValue()));
     }
 }
diff --git a/yang/yang-data-operations/pom.xml b/yang/yang-data-operations/pom.xml
new file mode 100644 (file)
index 0000000..6e25ed8
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Cisco Systems, Inc. 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang</artifactId>
+        <version>0.6.2-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>yang-data-operations</artifactId>
+    <name>${project.artifactId}</name>
+    <description>${project.artifactId}</description>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.opendaylight.yangtools.yang.data.operations
+                        </Export-Package>
+                        <Import-Package>
+                            *
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-model-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-data-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+</project>
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/AbstractContainerNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/AbstractContainerNodeModification.java
new file mode 100644 (file)
index 0000000..1f3a7d3
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+abstract class AbstractContainerNodeModification<S, N extends DataContainerNode<?>> implements Modification<S, N> {
+
+    @Override
+    public final Optional<N> modify(S schema, Optional<N> actual, Optional<N> modification,
+            OperationStack operationStack) throws DataModificationException {
+
+        operationStack.enteringNode(modification);
+
+        Optional<N> result;
+        QName nodeQName = getQName(schema);
+
+        switch (operationStack.getCurrentOperation()) {
+        case DELETE: {
+            DataModificationException.DataMissingException.check(nodeQName, actual);
+        }
+        case REMOVE: {
+            result = Optional.absent();
+            break;
+        }
+        case CREATE: {
+            DataModificationException.DataExistsException.check(nodeQName, actual, null);
+        }
+        case REPLACE: {
+            result = modification;
+            break;
+        }
+        case NONE: {
+            DataModificationException.DataMissingException.check(nodeQName, actual);
+        }
+        case MERGE: {
+            // Recursively modify all child nodes
+            result = modifyContainer(schema, actual, modification, operationStack);
+            break;
+        }
+        default:
+            throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown",
+                    operationStack.getCurrentOperation(), schema));
+        }
+
+        operationStack.exitingNode(modification);
+        return result;
+    }
+
+    protected abstract QName getQName(S schema);
+
+    private Optional<N> modifyContainer(S schema, Optional<N> actual, Optional<N> modification,
+            OperationStack operationStack) throws DataModificationException {
+
+        if (actual.isPresent() == false) {
+            return modification;
+        }
+
+        if (modification.isPresent() == false) {
+            return actual;
+        }
+
+        Set<InstanceIdentifier.PathArgument> toProcess = getChildrenToProcess(schema, actual, modification);
+
+        List<? extends DataContainerChild<?, ?>> merged = modifyContainerChildNodes(schema, operationStack,
+                actual.get(), modification.get(), toProcess);
+        return build(schema, merged);
+    }
+
+    private List<? extends DataContainerChild<?, ?>> modifyContainerChildNodes(S schema, OperationStack operationStack,
+            N actual, N modification, Set<InstanceIdentifier.PathArgument> toProcess) throws DataModificationException {
+        List<DataContainerChild<?, ?>> result = Lists.newArrayList();
+
+        for (InstanceIdentifier.PathArgument childToProcessId : toProcess) {
+            Object schemaOfChildToProcess = findSchema(schema, childToProcessId);
+
+            Optional<? extends DataContainerChild<?, ?>> modifiedValues = modifyContainerNode(operationStack, actual,
+                    modification, childToProcessId, schemaOfChildToProcess);
+
+            if (modifiedValues.isPresent()) {
+                result.add(modifiedValues.get());
+            }
+        }
+
+        return result;
+    }
+
+    private Optional<? extends DataContainerChild<?, ?>> modifyContainerNode(OperationStack operationStack, N actual,
+            N modification, InstanceIdentifier.PathArgument childToProcess, Object schemaChild)
+            throws DataModificationException {
+
+        Optional<DataContainerChild<?, ?>> storedChildren = actual.getChild(childToProcess);
+        Optional<DataContainerChild<?, ?>> modifiedChildren = modification.getChild(childToProcess);
+
+        return NodeDispatcher.dispatchChildModification(schemaChild, storedChildren, modifiedChildren, operationStack);
+    }
+
+    private Object findSchema(S schema, InstanceIdentifier.PathArgument childToProcessId) {
+        if (childToProcessId instanceof InstanceIdentifier.AugmentationIdentifier) {
+            return findSchemaForAugment(schema, (InstanceIdentifier.AugmentationIdentifier) childToProcessId);
+        } else {
+            return findSchemaForChild(schema, childToProcessId.getNodeType());
+        }
+    }
+
+    protected abstract Object findSchemaForChild(S schema, QName nodeType);
+
+    protected abstract Object findSchemaForAugment(S schema, InstanceIdentifier.AugmentationIdentifier childToProcessId);
+
+    private Optional<N> build(S schema, List<? extends DataContainerChild<?, ?>> result) {
+        DataContainerNodeBuilder<?, N> b = getBuilder(schema);
+
+        // TODO skip empty container nodes ? e.g. if container looses all its child nodes
+//        if(result.isEmpty()) {
+//            return Optional.absent();
+//        }
+
+        for (DataContainerChild<?, ?> dataContainerChild : result) {
+            b.withChild(dataContainerChild);
+        }
+        return Optional.of(b.build());
+    }
+
+    protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
+
+    protected Set<InstanceIdentifier.PathArgument> getChildrenToProcess(S schema, Optional<N> actual,
+            Optional<N> modification) throws DataModificationException {
+        Set<InstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
+
+        qNames.addAll(getChildQNames(actual));
+        qNames.addAll(getChildQNames(modification));
+        return qNames;
+    }
+
+    private Set<? extends InstanceIdentifier.PathArgument> getChildQNames(Optional<N> actual) {
+        Set<InstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
+
+        for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> child : actual.get().getValue()) {
+            qNames.add(child.getIdentifier());
+        }
+
+        return qNames;
+    }
+
+    private static final class NodeDispatcher {
+
+        private static final LeafNodeModification LEAF_NODE_MODIFICATION = new LeafNodeModification();
+        private static final LeafSetNodeModification LEAF_SET_NODE_MODIFICATION = new LeafSetNodeModification();
+        private static final AugmentationNodeModification AUGMENTATION_NODE_MODIFICATION = new AugmentationNodeModification();
+        private static final MapNodeModification MAP_NODE_MODIFICATION = new MapNodeModification();
+        private static final ContainerNodeModification CONTAINER_NODE_MODIFICATION = new ContainerNodeModification();
+        private static final ChoiceNodeModification CHOICE_NODE_MODIFICATION = new ChoiceNodeModification();
+
+        static Optional<? extends DataContainerChild<?, ?>> dispatchChildModification(Object schemaChild,
+                Optional<DataContainerChild<?, ?>> actual, Optional<DataContainerChild<?, ?>> modification,
+                OperationStack operations) throws DataModificationException {
+
+            if (schemaChild instanceof LeafSchemaNode) {
+                return onLeafNode((LeafSchemaNode) schemaChild, actual, modification, operations);
+            } else if (schemaChild instanceof ContainerSchemaNode) {
+                return onContainerNode((ContainerSchemaNode) schemaChild, actual, modification, operations);
+            } else if (schemaChild instanceof LeafListSchemaNode) {
+                return onLeafSetNode((LeafListSchemaNode) schemaChild, actual, modification, operations);
+            } else if (schemaChild instanceof AugmentationSchema) {
+                return onAugmentationNode((AugmentationSchema) schemaChild, actual, modification, operations);
+            } else if (schemaChild instanceof ListSchemaNode) {
+                return onMapNode((ListSchemaNode) schemaChild, actual, modification, operations);
+            } else if (schemaChild instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
+                return onChoiceNode((org.opendaylight.yangtools.yang.model.api.ChoiceNode) schemaChild, actual,
+                        modification, operations);
+            }
+
+            throw new IllegalArgumentException("Unknown schema node type " + schemaChild);
+        }
+
+        private static Optional<? extends DataContainerChild<?, ?>> onChoiceNode(
+                org.opendaylight.yangtools.yang.model.api.ChoiceNode schemaChild,
+                Optional<? extends DataContainerChild<?, ?>> actual,
+                Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+                throws DataModificationException {
+            checkType(actual, ChoiceNode.class);
+            checkType(modification, ChoiceNode.class);
+            return CHOICE_NODE_MODIFICATION.modify(schemaChild, (Optional<ChoiceNode>) actual,
+                    (Optional<ChoiceNode>) modification, operations);
+        }
+
+        private static Optional<? extends DataContainerChild<?, ?>> onMapNode(ListSchemaNode schemaChild,
+                Optional<? extends DataContainerChild<?, ?>> actual,
+                Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+                throws DataModificationException {
+            checkType(actual, MapNode.class);
+            checkType(modification, MapNode.class);
+            return MAP_NODE_MODIFICATION.modify(schemaChild, (Optional<MapNode>) actual,
+                    (Optional<MapNode>) modification, operations);
+        }
+
+        private static Optional<? extends DataContainerChild<?, ?>> onAugmentationNode(AugmentationSchema schemaChild,
+                Optional<? extends DataContainerChild<?, ?>> actual,
+                Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+                throws DataModificationException {
+            checkType(actual, AugmentationNode.class);
+            checkType(modification, AugmentationNode.class);
+            return AUGMENTATION_NODE_MODIFICATION.modify(schemaChild, (Optional<AugmentationNode>) actual,
+                    (Optional<AugmentationNode>) modification, operations);
+        }
+
+        private static Optional<? extends DataContainerChild<?, ?>> onLeafSetNode(LeafListSchemaNode schemaChild,
+                Optional<? extends DataContainerChild<?, ?>> actual,
+                Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+                throws DataModificationException {
+            checkType(actual, LeafSetNode.class);
+            checkType(modification, LeafSetNode.class);
+            return LEAF_SET_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafSetNode<?>>) actual,
+                    (Optional<LeafSetNode<?>>) modification, operations);
+        }
+
+        private static Optional<? extends DataContainerChild<?, ?>> onContainerNode(ContainerSchemaNode schemaChild,
+                Optional<? extends DataContainerChild<?, ?>> actual,
+                Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+                throws DataModificationException {
+            checkType(actual, ContainerNode.class);
+            checkType(modification, ContainerNode.class);
+            return CONTAINER_NODE_MODIFICATION.modify(schemaChild, (Optional<ContainerNode>) actual,
+                    (Optional<ContainerNode>) modification, operations);
+        }
+
+        private static Optional<? extends DataContainerChild<?, ?>> onLeafNode(LeafSchemaNode schemaChild,
+                Optional<? extends DataContainerChild<?, ?>> actual,
+                Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
+                throws DataModificationException {
+            checkType(actual, LeafNode.class);
+            checkType(modification, LeafNode.class);
+            return LEAF_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafNode<?>>) actual,
+                    (Optional<LeafNode<?>>) modification, operations);
+        }
+
+        private static void checkType(Optional<? extends DataContainerChild<?, ?>> actual, Class<?> leafNodeClass) {
+            if (actual.isPresent()) {
+                Preconditions.checkArgument(leafNodeClass.isAssignableFrom(actual.get().getClass()),
+                        "Unexpected node type, should be: %s, but was: %s, for: %s", leafNodeClass, actual.getClass(),
+                        actual);
+            }
+        }
+    }
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/AugmentationNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/AugmentationNodeModification.java
new file mode 100644 (file)
index 0000000..2411d8f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+
+final class AugmentationNodeModification extends AbstractContainerNodeModification<AugmentationSchema, AugmentationNode> {
+
+    @Override
+    protected QName getQName(AugmentationSchema schema) {
+        // FIXME null qname for AUGMENT
+        return null;
+    }
+
+    @Override
+    protected Object findSchemaForChild(AugmentationSchema schema, QName nodeType) {
+        return SchemaUtils.findSchemaForChild(schema, nodeType);
+    }
+
+    @Override
+    protected Object findSchemaForAugment(AugmentationSchema schema, InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+        throw new UnsupportedOperationException("Augmentation cannot be augmented directly, " + schema);
+    }
+
+    @Override
+    protected DataContainerNodeBuilder<?, AugmentationNode> getBuilder(AugmentationSchema schema) {
+        return Builders.augmentationBuilder(schema);
+    }
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ChoiceNodeModification.java
new file mode 100644 (file)
index 0000000..534c6a6
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+
+final class ChoiceNodeModification extends
+        AbstractContainerNodeModification<ChoiceNode, org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> {
+
+    @Override
+    protected QName getQName(ChoiceNode schema) {
+        return schema.getQName();
+    }
+
+    @Override
+    protected Object findSchemaForChild(ChoiceNode schema, QName nodeType) {
+        return SchemaUtils.findSchemaForChild(schema, nodeType);
+    }
+
+    @Override
+    protected Set<InstanceIdentifier.PathArgument> getChildrenToProcess(ChoiceNode schema,
+            Optional<org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> actual,
+            Optional<org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> modification)
+            throws DataModificationException {
+        Set<InstanceIdentifier.PathArgument> childrenToProcess = super.getChildrenToProcess(schema, actual,
+                modification);
+
+        if (modification.isPresent() == false) {
+            return childrenToProcess;
+        }
+
+        // Detect case node from modification
+        ChoiceCaseNode detectedCase = null;
+        for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> child : modification.get().getValue()) {
+            Optional<ChoiceCaseNode> detectedCaseForChild = SchemaUtils.detectCase(schema, child);
+
+            if(detectedCaseForChild.isPresent() == false) {
+                DataModificationException.IllegalChoiceValuesException.throwUnknownChild(schema.getQName(),
+                        child.getNodeType());
+            }
+
+            if (detectedCase != null && detectedCase.equals(detectedCaseForChild.get()) == false) {
+                DataModificationException.IllegalChoiceValuesException.throwMultipleCasesReferenced(schema.getQName(),
+                        modification.get(), detectedCase.getQName(), detectedCaseForChild.get().getQName());
+            }
+            detectedCase = detectedCaseForChild.get();
+        }
+
+        if (detectedCase == null)
+            return childrenToProcess;
+
+        // Filter out child nodes that do not belong to detected case =
+        // Nodes from other cases present in actual
+        Set<InstanceIdentifier.PathArgument> childrenToProcessFiltered = Sets.newLinkedHashSet();
+        for (InstanceIdentifier.PathArgument childToProcess : childrenToProcess) {
+            // child from other cases, skip
+            if (childToProcess instanceof AugmentationNode
+                    && SchemaUtils.belongsToCaseAugment(detectedCase,
+                            (InstanceIdentifier.AugmentationIdentifier) childToProcess) == false) {
+                continue;
+            } else if (belongsToCase(detectedCase, childToProcess) == false) {
+                continue;
+            }
+
+            childrenToProcessFiltered.add(childToProcess);
+        }
+
+        return childrenToProcessFiltered;
+    }
+
+    private boolean belongsToCase(ChoiceCaseNode detectedCase, InstanceIdentifier.PathArgument childToProcess) {
+        return detectedCase.getDataChildByName(childToProcess.getNodeType()) != null;
+    }
+
+    @Override
+    protected Object findSchemaForAugment(ChoiceNode schema, InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+        return SchemaUtils.findSchemaForAugment(schema, childToProcessId.getPossibleChildNames());
+    }
+
+    @Override
+    protected DataContainerNodeBuilder<?, org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode> getBuilder(
+            ChoiceNode schema) {
+        return Builders.choiceBuilder(schema);
+    }
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ContainerNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/ContainerNodeModification.java
new file mode 100644 (file)
index 0000000..3fffa2f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+final class ContainerNodeModification extends AbstractContainerNodeModification<ContainerSchemaNode, ContainerNode> {
+
+    // FIXME normalized nodes as a result from merge contain attributes e.g. operation="merge" from modification
+
+    @Override
+    protected QName getQName(ContainerSchemaNode schema) {
+        return schema.getQName();
+    }
+
+    @Override
+    protected Object findSchemaForChild(ContainerSchemaNode schema, QName nodeType) {
+        return SchemaUtils.findSchemaForChild(schema, nodeType);
+    }
+
+    @Override
+    protected Object findSchemaForAugment(ContainerSchemaNode schema,
+            InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+        return SchemaUtils.findSchemaForAugment(schema, childToProcessId.getPossibleChildNames());
+    }
+
+    @Override
+    protected DataContainerNodeBuilder<?, ContainerNode> getBuilder(ContainerSchemaNode schema) {
+        return Builders.containerBuilder(schema);
+    }
+
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataModificationException.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataModificationException.java
new file mode 100644 (file)
index 0000000..cc66535
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+public class DataModificationException extends Exception {
+    // TODO replace QName as identifier for node with schema or NodeIdentifier,
+    // Augmentation does not have a QName
+
+    private static final long serialVersionUID = 1L;
+    private final QName node;
+
+    public DataModificationException(String message, QName node) {
+        super(message);
+        this.node = node;
+    }
+
+    public QName getNodeQName() {
+        return node;
+    }
+
+    public static final class DataMissingException extends DataModificationException {
+        private static final long serialVersionUID = 1L;
+
+        public DataMissingException(QName nodeType) {
+            super(String.format("Data missing for node: %s", nodeType), nodeType);
+        }
+
+        public DataMissingException(QName nodeType, Node<?> modificationNode) {
+            super(String.format("Data missing for node: %s, %s", nodeType, modificationNode), nodeType);
+        }
+
+        static void check(QName nodeQName, Optional<? extends NormalizedNode<?, ?>> actualNode) throws DataMissingException {
+            if (actualNode.isPresent() == false) {
+                throw new DataMissingException(nodeQName);
+            }
+        }
+
+        static void check(QName nodeQName, Optional<LeafSetNode<?>> actualNodes, LeafSetEntryNode<?> modificationNode)
+                throws DataMissingException {
+            if (actualNodes.isPresent()==false || actualNodes.get().getChild(modificationNode.getIdentifier()).isPresent() == false) {
+                throw new DataMissingException(nodeQName, modificationNode);
+            }
+        }
+
+        static void check(QName nodeQName, Optional<MapNode> actualNodes, MapEntryNode modificationNode)
+                throws DataModificationException {
+            if (actualNodes.isPresent()==false || actualNodes.get().getChild(modificationNode.getIdentifier()).isPresent() == false) {
+                throw new DataMissingException(nodeQName, modificationNode);
+            }
+        }
+    }
+
+    public static final class DataExistsException extends DataModificationException {
+        private static final long serialVersionUID = 1L;
+
+        public DataExistsException(QName nodeType, NormalizedNode<?, ?> actualNode, NormalizedNode<?, ?> modificationNode) {
+            super(String
+                    .format("Data already exists for node: %s, current value: %s. modification value: %s", nodeType, actualNode, modificationNode),
+                    nodeType);
+        }
+
+        static void check(QName nodeQName, Optional<? extends NormalizedNode<?, ?>> actualNode, NormalizedNode<?, ?> modificationNode) throws DataExistsException {
+            if (actualNode.isPresent()) {
+                throw new DataExistsException(nodeQName, actualNode.get(), modificationNode);
+            }
+        }
+
+        static void check(QName nodeQName, Optional<LeafSetNode<?>> actualNodes, LeafSetEntryNode<?> modificationNode)
+                throws DataExistsException {
+            if (actualNodes.isPresent() && actualNodes.get().getChild(modificationNode.getIdentifier()).isPresent()) {
+                throw new DataExistsException(nodeQName, actualNodes.get(), modificationNode);
+            }
+        }
+
+        public static void check(QName qName, Optional<MapNode> actualNodes, MapEntryNode listModification)
+                throws DataModificationException {
+            if (actualNodes.isPresent() && actualNodes.get().getChild(listModification.getIdentifier()).isPresent()) {
+                throw new DataExistsException(qName, actualNodes.get(), listModification);
+            }
+        }
+    }
+
+    public static final class IllegalChoiceValuesException extends DataModificationException {
+        private static final long serialVersionUID = 1L;
+
+        public IllegalChoiceValuesException(String message, QName node) {
+            super(message, node);
+        }
+
+        public static void throwMultipleCasesReferenced(QName choiceQName, ChoiceNode modification,
+                QName case1QName, QName case2QName) throws IllegalChoiceValuesException {
+            throw new IllegalChoiceValuesException(String.format(
+                    "Child nodes from multiple cases present in modification: %s, choice: %s, case1: %s, case2: %s",
+                    modification, choiceQName, case1QName, case2QName), choiceQName);
+        }
+
+        public static void throwUnknownChild(QName choiceQName, QName nodeQName) throws IllegalChoiceValuesException {
+            throw new IllegalChoiceValuesException(String.format(
+                    "Unknown child node detected, choice: %s, child node: %s",
+                    choiceQName, nodeQName), choiceQName);
+        }
+    }
+
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataOperations.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/DataOperations.java
new file mode 100644 (file)
index 0000000..401b387
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Optional;
+
+/**
+ * Edit config operations utilities.
+ */
+public final class DataOperations {
+
+    private DataOperations() {}
+
+    public static Optional<ContainerNode> modify(ContainerSchemaNode schema, ContainerNode stored,
+            ContainerNode modified) throws DataModificationException {
+        return modify(schema, stored, modified, ModifyAction.MERGE);
+    }
+
+    public static Optional<MapNode> modify(ListSchemaNode schema, MapNode stored, MapNode modified)
+            throws DataModificationException {
+        return modify(schema, stored, modified, ModifyAction.MERGE);
+    }
+
+    public static Optional<ContainerNode> modify(ContainerSchemaNode schema, ContainerNode stored,
+            ContainerNode modified, ModifyAction defaultOperation) throws DataModificationException {
+
+        OperationStack operations = new OperationStack(defaultOperation);
+
+        return new ContainerNodeModification().modify(schema, Optional.fromNullable(stored),
+                Optional.fromNullable(modified), operations);
+    }
+
+    public static Optional<MapNode> modify(ListSchemaNode schema, MapNode stored, MapNode modified,
+            ModifyAction defaultOperation) throws DataModificationException {
+
+        OperationStack operations = new OperationStack(defaultOperation);
+
+        return new MapNodeModification().modify(schema, Optional.fromNullable(stored), Optional.fromNullable(modified),
+                operations);
+    }
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/LeafNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/LeafNodeModification.java
new file mode 100644 (file)
index 0000000..39990a5
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+import com.google.common.base.Optional;
+
+final class LeafNodeModification implements Modification<LeafSchemaNode, LeafNode<?>> {
+
+    @Override
+    public Optional<LeafNode<?>> modify(LeafSchemaNode schema, Optional<LeafNode<?>> actualNode,
+                                    Optional<LeafNode<?>> modificationNode, OperationStack operationStack) throws DataModificationException {
+
+        operationStack.enteringNode(modificationNode);
+
+        Optional<LeafNode<?>> result;
+
+        // Returns either actual node, modification node or empty in case of removal
+        switch (operationStack.getCurrentOperation()) {
+            case MERGE: {
+                result = modificationNode.isPresent() ? modificationNode : actualNode;
+                break;
+            }
+            case CREATE: {
+                DataModificationException.DataExistsException.check(schema.getQName(), actualNode, null);
+            }
+            case REPLACE: {
+                result = modificationNode;
+                break;
+            }
+            case DELETE: {
+                DataModificationException.DataMissingException.check(schema.getQName(), actualNode);
+            }
+            case REMOVE: {
+                result = Optional.absent();
+                break;
+            }
+            case NONE: {
+                result = actualNode;
+                break;
+            }
+            default:
+                throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown", operationStack.getCurrentOperation(), schema));
+
+        }
+
+        operationStack.exitingNode(modificationNode);
+
+        return result;
+    }
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/LeafSetNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/LeafSetNodeModification.java
new file mode 100644 (file)
index 0000000..de5a5b0
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+final class LeafSetNodeModification implements Modification<LeafListSchemaNode, LeafSetNode<?>> {
+
+    @Override
+    public Optional<LeafSetNode<?>> modify(LeafListSchemaNode schema, Optional<LeafSetNode<?>> actual,
+            Optional<LeafSetNode<?>> modification, OperationStack operationStack) throws DataModificationException {
+
+        List<LeafSetEntryNode<?>> resultNodes = Lists.newArrayList();
+        if(actual.isPresent()) {
+            Iterables.addAll(resultNodes, actual.get().getValue());
+        }
+
+        // TODO implement ordering for modification nodes
+
+        for (LeafSetEntryNode<?> leafListModification : modification.get().getValue()) {
+            operationStack.enteringNode(leafListModification);
+
+            switch (operationStack.getCurrentOperation()) {
+                case MERGE:
+                case CREATE: {
+                    DataModificationException.DataExistsException.check(schema.getQName(), actual, leafListModification);
+                }
+                case REPLACE: {
+                    if (contains(actual, leafListModification) == false) {
+                        resultNodes.add(leafListModification);
+                    }
+                    break;
+                }
+                case DELETE: {
+                    DataModificationException.DataMissingException.check(schema.getQName(), actual, leafListModification);
+                }
+                case REMOVE: {
+                    if (resultNodes.contains(leafListModification)) {
+                        resultNodes.remove(leafListModification);
+                    }
+                    break;
+                }
+                case NONE: {
+                    break;
+                }
+                default:
+                    throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown", operationStack.getCurrentOperation(), schema));
+            }
+
+            operationStack.exitingNode(leafListModification);
+        }
+        return build(schema, resultNodes);
+    }
+
+    private Optional<LeafSetNode<?>> build(LeafListSchemaNode schemaNode, List<LeafSetEntryNode<?>> resultNodes) {
+        if(resultNodes.isEmpty())
+            return Optional.absent();
+
+        ListNodeBuilder<Object, LeafSetEntryNode<Object>> b = Builders.leafSetBuilder(schemaNode);
+        for (LeafSetEntryNode<?> resultNode : resultNodes) {
+            // FIXME: can we do something about this SuppressWarnings?
+            @SuppressWarnings("unchecked")
+            final LeafSetEntryNode<Object> child = (LeafSetEntryNode<Object>) resultNode;
+            b.withChild(child);
+        }
+
+        return Optional.<LeafSetNode<?>>of(b.build());
+    }
+
+    private static boolean contains(Optional<LeafSetNode<?>> actual, LeafSetEntryNode<?> leafListModification) {
+        boolean contains = actual.isPresent();
+        contains &= actual.get().getChild(leafListModification.getIdentifier()).isPresent();
+
+        return contains;
+    }
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/MapEntryNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/MapEntryNodeModification.java
new file mode 100644 (file)
index 0000000..64b5399
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+final class MapEntryNodeModification extends AbstractContainerNodeModification<ListSchemaNode, MapEntryNode> {
+
+    @Override
+    protected QName getQName(ListSchemaNode schema) {
+        return schema.getQName();
+    }
+
+    @Override
+    protected Object findSchemaForChild(ListSchemaNode schema, QName nodeType) {
+        return SchemaUtils.findSchemaForChild(schema, nodeType);
+    }
+
+    @Override
+    protected Object findSchemaForAugment(ListSchemaNode schema, InstanceIdentifier.AugmentationIdentifier childToProcessId) {
+        return SchemaUtils.findSchemaForAugment(schema, childToProcessId.getPossibleChildNames());
+    }
+
+    @Override
+    protected DataContainerNodeBuilder<?, MapEntryNode> getBuilder(ListSchemaNode schema) {
+        return Builders.mapEntryBuilder(schema);
+    }
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/MapNodeModification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/MapNodeModification.java
new file mode 100644 (file)
index 0000000..9bb5e88
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+* Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+
+public class MapNodeModification implements Modification<ListSchemaNode, MapNode> {
+
+    public static final MapEntryNodeModification MAP_ENTRY_NODE_MODIFICATION = new MapEntryNodeModification();
+
+    @Override
+    public Optional<MapNode> modify(ListSchemaNode schema, Optional<MapNode> actual,
+                                    Optional<MapNode> modification, OperationStack operationStack) throws DataModificationException {
+
+        // Merge or None operation on parent, leaving actual if modification not present
+        if (modification.isPresent() == false)
+            return actual;
+
+        Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> resultNodes = Maps.newLinkedHashMap();
+        if(actual.isPresent())
+            resultNodes.putAll(mapEntries(actual.get()));
+
+        // TODO implement ordering for modification nodes
+
+        for (MapEntryNode mapEntryModification : modification.get().getValue()) {
+
+            operationStack.enteringNode(mapEntryModification);
+
+            InstanceIdentifier.NodeIdentifierWithPredicates entryKey = mapEntryModification.getIdentifier();
+
+            switch (operationStack.getCurrentOperation()) {
+            case NONE:
+                DataModificationException.DataMissingException.check(schema.getQName(), actual, mapEntryModification);
+            case MERGE: {
+                MapEntryNode mergedListNode;
+                if (resultNodes.containsKey(entryKey)) {
+                    MapEntryNode actualEntry = resultNodes.get(entryKey);
+                    mergedListNode = MAP_ENTRY_NODE_MODIFICATION.modify(schema, Optional.of(actualEntry), Optional.of(mapEntryModification), operationStack).get();
+                } else {
+                    mergedListNode = mapEntryModification;
+                }
+
+                resultNodes.put(mergedListNode.getIdentifier(), mergedListNode);
+                break;
+            }
+            case CREATE: {
+                DataModificationException.DataExistsException.check(schema.getQName(), actual, mapEntryModification);
+            }
+            case REPLACE: {
+                resultNodes.put(entryKey, mapEntryModification);
+                break;
+            }
+            case DELETE: {
+                DataModificationException.DataMissingException.check(schema.getQName(), actual, mapEntryModification);
+            }
+            case REMOVE: {
+                if (resultNodes.containsKey(entryKey)) {
+                    resultNodes.remove(entryKey);
+                }
+                break;
+            }
+            default:
+                throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown", operationStack.getCurrentOperation(), schema));
+            }
+
+            operationStack.exitingNode(mapEntryModification);
+        }
+        return build(schema, resultNodes);
+    }
+
+    private Optional<MapNode> build(ListSchemaNode schema, Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> resultNodes) {
+        if(resultNodes.isEmpty())
+            return Optional.absent();
+
+        CollectionNodeBuilder<MapEntryNode, MapNode> b = Builders.mapBuilder(schema);
+
+        for (MapEntryNode child : resultNodes.values()) {
+            b.withChild(child);
+        }
+
+        return Optional.of(b.build());
+    }
+
+    private Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntries(MapNode mapNode) {
+        Map<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapped = Maps.newLinkedHashMap();
+
+        for (MapEntryNode mapEntryNode : mapNode.getValue()) {
+            mapped.put(mapEntryNode.getIdentifier(), mapEntryNode);
+        }
+
+        return mapped;
+    }
+
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/Modification.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/Modification.java
new file mode 100644 (file)
index 0000000..67ce361
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+/**
+ * Strategy interface for data modification.
+ *
+ * @param <S> SchemaNode type
+ * @param <N> LeafNode type
+ *
+ */
+interface Modification<S, N extends NormalizedNode<?, ?>> {
+
+    Optional<N> modify(S schemaNode, Optional<N> actual, Optional<N> modification, OperationStack operations) throws DataModificationException;
+}
diff --git a/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/OperationStack.java b/yang/yang-data-operations/src/main/java/org/opendaylight/yangtools/yang/data/operations/OperationStack.java
new file mode 100644 (file)
index 0000000..c4f890d
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. 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.operations;
+
+import java.net.URI;
+import java.util.Deque;
+import java.util.LinkedList;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Tracks netconf operations on nested nodes.
+ */
+final class OperationStack {
+
+    private static final Logger logger = LoggerFactory.getLogger(OperationStack.class);
+    private static final QName OPERATION_NAME = new QName(URI.create("urn:ietf:params:xml:ns:netconf:base:1.0"), "operation");
+
+    private final Deque<ModifyAction> operations = new LinkedList<>();
+
+    public OperationStack(ModifyAction operation) {
+        operations.add(operation);
+    }
+
+    public void enteringNode(Optional<? extends NormalizedNode<?, ?>> modificationNode) {
+        if (modificationNode.isPresent() == false) {
+            return;
+        }
+
+        NormalizedNode<?, ?> modification = modificationNode.get();
+
+        enteringNode(modification);
+    }
+
+    public void enteringNode(NormalizedNode<?, ?> modificationNode) {
+        ModifyAction operation = getOperation(modificationNode);
+        if (operation == null) {
+            return;
+        }
+
+        addOperation(operation);
+    }
+
+    private ModifyAction getOperation(NormalizedNode<?, ?> modificationNode) {
+        if (modificationNode instanceof AttributesContainer == false)
+            return null;
+
+        String operationString = ((AttributesContainer) modificationNode).getAttributes().get(OPERATION_NAME);
+
+        return operationString == null ? null : ModifyAction.fromXmlValue(operationString);
+    }
+
+    private void addOperation(ModifyAction operation) {
+        // Add check for permitted operation
+        operations.add(operation);
+        logger.trace("Operation added {}, {}", operation, this);
+    }
+
+    public ModifyAction getCurrentOperation() {
+        return operations.getLast();
+    }
+
+    public void exitingNode(Optional<? extends NormalizedNode<?, ?>> modificationNode) {
+        if (modificationNode.isPresent() == false) {
+            return;
+        }
+
+        NormalizedNode<?, ?> modification = modificationNode.get();
+
+        exitingNode(modification);
+    }
+
+    public void exitingNode(NormalizedNode<?, ?> modification) {
+        ModifyAction operation = getOperation(modification);
+        if (operation == null) {
+            return;
+        }
+
+        Preconditions.checkState(operations.size() > 1);
+        Preconditions.checkState(operations.peekLast().equals(operation), "Operations mismatch %s, %s",
+                operations.peekLast(), operation);
+
+        ModifyAction removed = operations.removeLast();
+        logger.trace("Operation removed {}, {}", removed, this);
+    }
+
+    @Override
+       public String toString() {
+        return operations.toString();
+    }
+
+}
diff --git a/yang/yang-data-operations/src/test/java/org/opendaylight/yangtools/yang/data/operations/YangDataOperationsNegativeTest.java b/yang/yang-data-operations/src/test/java/org/opendaylight/yangtools/yang/data/operations/YangDataOperationsNegativeTest.java
new file mode 100644 (file)
index 0000000..7cfdce8
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. 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.operations;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class YangDataOperationsNegativeTest extends YangDataOperationsTest{
+
+    private static final String XML_NEG_FOLDER_NAME = "/xmls-negative";
+    private final Class<? extends DataModificationException> expected;
+
+    @Parameterized.Parameters()
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+
+                // Container
+                { "/containerTest_noneContainerActualMissing", DataModificationException.DataMissingException.class },
+                { "/containerTest_createContainerActualPresent", DataModificationException.DataExistsException.class },
+                { "/containerTest_deleteContainerActualMissing", DataModificationException.DataMissingException.class },
+                // List
+                { "/listTest_createListActualPresent", DataModificationException.DataExistsException.class },
+                { "/listTest_deleteListActualMissing", DataModificationException.DataMissingException.class },
+                { "/listTest_noneListActualMissing", DataModificationException.DataMissingException.class },
+                // Leaf
+                { "/leafTest_createLeafActualPresent", DataModificationException.DataExistsException.class },
+                { "/leafTest_deleteLeafActualMissing", DataModificationException.DataMissingException.class },
+                // Leaf list
+                { "/leafListTest_createLeafActualPresent", DataModificationException.DataExistsException.class },
+                { "/leafListTest_deleteLeafActualMissing", DataModificationException.DataMissingException.class },
+        });
+    }
+
+    public YangDataOperationsNegativeTest(String testDir, Class<? extends DataModificationException> e) throws Exception {
+        super(testDir);
+        this.expected = e;
+    }
+
+    @Override
+    protected String getXmlFolderName() {
+        return XML_NEG_FOLDER_NAME;
+    }
+
+    @Test
+    public void testModification() throws Exception {
+        try {
+            DataOperations.modify(containerNode,
+                    currentConfig.orNull(), modification.orNull(), modifyAction);
+            fail("Negative test for " + testDirName + " should have failed");
+        } catch (Exception e) {
+            assertEquals(e.getClass(), expected);
+        }
+    }
+}
diff --git a/yang/yang-data-operations/src/test/java/org/opendaylight/yangtools/yang/data/operations/YangDataOperationsTest.java b/yang/yang-data-operations/src/test/java/org/opendaylight/yangtools/yang/data/operations/YangDataOperationsTest.java
new file mode 100644 (file)
index 0000000..4097d4a
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. 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.operations;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+@RunWith(Parameterized.class)
+public class YangDataOperationsTest {
+
+    public static final String CURRENT_XML_NAME = "/current.xml";
+    public static final String MODIFICATION_XML_NAME = "/merge.xml";
+    private static final String XML_FOLDER_NAME = "/xmls";
+    public static final String RESULT_XML_NAME = "/result.xml";
+    private static final Object OPERATION_XML_NAME = "/defaultOperation.txt";
+
+    protected final ContainerSchemaNode containerNode;
+    protected final String testDirName;
+    protected final Optional<ContainerNode> currentConfig;
+    protected final Optional<ContainerNode> modification;
+    protected final ModifyAction modifyAction;
+
+    @Parameterized.Parameters()
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+            // Container
+            { "/containerTest_createContainer" },
+            { "/containerTest_deleteContainer" },
+            { "/containerTest_innerContainerContainer" },
+            { "/containerTest_innerLeavesBaseOperationsContainer" },
+            { "/containerTest_noneContainer" },
+            { "/containerTest_removeContainer"},
+            { "/containerTest_replaceContainer"},
+            { "/containerTest_choiceActualModificationSameCase"},
+            { "/containerTest_choiceActualModificationDifferentCases"},
+            { "/containerTest_choiceActualOneCaseModificationOtherCase"},
+//            LeafList
+            { "/leafListTest" },
+            // List
+            { "/listTest" },
+            // Additional
+            {"/none_NoChange"},
+            {"/listTest_alterInnerValue"}
+        });
+    }
+
+    public YangDataOperationsTest(String testDir) throws Exception {
+        SchemaContext schema = parseTestSchema();
+        containerNode = (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
+        this.testDirName = testDir;
+
+        currentConfig = loadXmlToCompositeNode(getXmlFolderName() + testDirName + CURRENT_XML_NAME);
+        modification = loadXmlToCompositeNode(getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
+        Preconditions.checkState(modification.isPresent(), "Modification xml has to be present under "
+                + getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
+
+        modifyAction = loadModifyAction(getXmlFolderName() + testDirName + OPERATION_XML_NAME);
+    }
+
+    protected String getXmlFolderName() {
+        return XML_FOLDER_NAME;
+    }
+
+    // TODO unite testing resources e.g. schemas with yang-data-impl
+    // TODO create extract common testing infrastructure from this and yang-data-impl e.g. xml dom handling
+
+    @Test
+    public void testModification() throws Exception {
+
+        Optional<ContainerNode> result = DataOperations.modify(containerNode,
+                currentConfig.orNull(), modification.orNull(), modifyAction);
+
+        String expectedResultXmlPath = getXmlFolderName() + testDirName + RESULT_XML_NAME;
+        Optional<ContainerNode> expectedResult = loadXmlToCompositeNode(expectedResultXmlPath);
+
+        if (result.isPresent()) {
+            verifyModificationResult(result, expectedResult);
+        } else {
+            junit.framework.Assert.assertNull("Result of modification is empty node, result xml should not be present "
+                    + expectedResultXmlPath, getClass().getResourceAsStream(expectedResultXmlPath));
+        }
+
+    }
+
+    private ModifyAction loadModifyAction(String path) throws Exception {
+        URL resource = getClass().getResource(path);
+        if (resource == null) {
+            return ModifyAction.MERGE;
+        }
+
+        return ModifyAction.fromXmlValue(Files.toString(new File(resource.getFile()), Charsets.UTF_8).trim());
+    }
+
+    private void verifyModificationResult(Optional<ContainerNode> result, Optional<ContainerNode> expectedResult)
+            throws UnsupportedDataTypeException {
+        Assert.assertEquals(
+                String.format(
+                        "Test result %n %s %n Expected %n %s %n",
+                        toString(toDom(result.get())),
+                        toString(toDom(expectedResult.get()))), expectedResult.get(), result.get());
+    }
+
+    private Element toDom(ContainerNode container) {
+        Iterable<Element> a =
+                DomFromNormalizedNodeSerializerFactory.getInstance(newDocument(), DomUtils.defaultValueCodecProvider())
+                .getContainerNodeSerializer().serialize(containerNode, container);
+        return a.iterator().next();
+    }
+
+    private Document newDocument() {
+        try {
+            return BUILDERFACTORY.newDocumentBuilder().newDocument();
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException("Failed to parse XML document", e);
+        }
+    }
+
+    private Optional<ContainerNode> loadXmlToCompositeNode(String xmlPath) throws IOException, SAXException {
+        InputStream resourceAsStream = getClass().getResourceAsStream(xmlPath);
+        if (resourceAsStream == null) {
+            return Optional.absent();
+        }
+
+        Document currentConfigElement = readXmlToDocument(resourceAsStream);
+        Preconditions.checkNotNull(currentConfigElement);
+
+        return Optional.of(DomToNormalizedNodeParserFactory.getInstance(DomUtils.defaultValueCodecProvider()).getContainerNodeParser().parse(
+                Collections.singletonList(currentConfigElement.getDocumentElement()), containerNode));
+    }
+
+    SchemaContext parseTestSchema() {
+        YangParserImpl yangParserImpl = new YangParserImpl();
+        Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(getTestYangs());
+        return yangParserImpl.resolveSchemaContext(modules);
+    }
+
+    List<InputStream> getTestYangs() {
+
+        return Lists.newArrayList(Collections2.transform(Lists.newArrayList("/schemas/test.yang"),
+                new Function<String, InputStream>() {
+                    @Override
+                    public InputStream apply(String input) {
+                        InputStream resourceAsStream = getClass().getResourceAsStream(input);
+                        Preconditions.checkNotNull(resourceAsStream, "File %s was null", resourceAsStream);
+                        return resourceAsStream;
+                    }
+                }));
+    }
+
+    DataSchemaNode getSchemaNode(SchemaContext context, String moduleName, String childNodeName) {
+        for (Module module : context.getModules()) {
+            if (module.getName().equals(moduleName)) {
+                for (DataSchemaNode dataSchemaNode : module.getChildNodes()) {
+                    if (dataSchemaNode.getQName().getLocalName().equals(childNodeName))
+                        return dataSchemaNode;
+                }
+            }
+        }
+
+        throw new IllegalStateException("Unable to find child node " + childNodeName);
+    }
+
+    private static final DocumentBuilderFactory BUILDERFACTORY;
+
+    static {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        factory.setCoalescing(true);
+        factory.setIgnoringElementContentWhitespace(true);
+        factory.setIgnoringComments(true);
+        BUILDERFACTORY = factory;
+    }
+
+    private Document readXmlToDocument(InputStream xmlContent) throws IOException, SAXException {
+        DocumentBuilder dBuilder;
+        try {
+            dBuilder = BUILDERFACTORY.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException("Failed to parse XML document", e);
+        }
+        Document doc = dBuilder.parse(xmlContent);
+
+        doc.getDocumentElement().normalize();
+        return doc;
+    }
+
+    public static String toString(Element xml) {
+        try {
+            Transformer transformer = TransformerFactory.newInstance().newTransformer();
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+            StreamResult result = new StreamResult(new StringWriter());
+            DOMSource source = new DOMSource(xml);
+            transformer.transform(source, result);
+
+            return result.getWriter().toString();
+        } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
+            throw new RuntimeException("Unable to serialize xml element " + xml, e);
+        }
+    }
+
+}
diff --git a/yang/yang-data-operations/src/test/resources/schemas/test.yang b/yang/yang-data-operations/src/test/resources/schemas/test.yang
new file mode 100644 (file)
index 0000000..96d2ef6
--- /dev/null
@@ -0,0 +1,152 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module test {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:test";
+    prefix "test";
+
+    organization "Cisco Systems, Inc.";
+
+    revision "2013-2-21" {
+        description
+            "Initial revision";
+    }
+
+    grouping listGroup {
+        list list {
+            key "uint32";
+
+            leaf uint32 {
+                type uint32;
+            }
+
+               container containerInList{
+                   leaf uint32 {
+                    type uint32;
+                }
+                leaf uint16 {
+                    type uint16;
+                }
+            }
+        }
+     }
+
+     grouping innerContainerGrouping {
+        container innerContainer {
+            leaf uint16 {
+                type uint16;
+            }
+
+            container innerInnerContainer {
+
+                leaf uint16 {
+                    type uint16;
+                }
+
+                leaf uint32 {
+                    type uint32;
+                }
+            }
+        }
+     }
+
+    container container {
+        leaf uint32 {
+            type uint32;
+        }
+
+        leaf decimal64 {
+            type decimal64 {
+                fraction-digits 2;
+            }
+        }
+
+        leaf boolean {
+            type boolean;
+        }
+
+        leaf binary {
+            type binary;
+        }
+
+        leaf string {
+            type string;
+        }
+
+        uses listGroup;
+        uses innerContainerGrouping;
+
+        choice choice{}
+        choice choice2{}
+
+        leaf-list leafList {
+            type string;
+        }
+
+        leaf identityRef {
+            type identityref {
+                base test-identity;
+            }
+        }
+
+        /* TODO test modification with empty type
+        leaf empty {
+             type empty;
+         }
+         */
+    }
+
+    augment "/container/" {
+        leaf augumentUint32 {
+            type uint32;
+        }
+    }
+
+    augment "/container/choice/" {
+        case test-identity-augument {
+            when "/container/identityRef = 'test-identity'";
+            leaf augumentString1 {
+                type string;
+            }
+
+            leaf augumentInt1 {
+                type uint32;
+            }
+        }
+        case test-identity-augument2 {
+            when "/container/identityRef = 'test-identity2'";
+            leaf augumentString2 {
+                type string;
+            }
+
+            leaf augumentInt2 {
+                type uint32;
+            }
+        }
+    }
+
+    augment "/container/choice2/" {
+        case test-identity-augument {
+            when "/container/identityRef = 'test-identity'";
+            container augumentContainer {
+                leaf augumentStringInAugumentContainer {
+                    type string;
+                }
+            }
+        }
+        case test-identity-augument2 {
+            when "/container/identityRef = 'test-identity2'";
+            list augumentedList {
+                leaf augumentStringInAugumentList {
+                    type string;
+                }
+            }
+        }
+    }
+
+
+    identity test-identity {}
+    identity test-identity2 {
+        base test-identity;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_choiceModificationMultipleCasesReferenced/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_choiceModificationMultipleCasesReferenced/current.xml
new file mode 100644 (file)
index 0000000..83bf5ac
--- /dev/null
@@ -0,0 +1,2 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_choiceModificationMultipleCasesReferenced/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_choiceModificationMultipleCasesReferenced/merge.xml
new file mode 100644 (file)
index 0000000..10580b2
--- /dev/null
@@ -0,0 +1,11 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <identityRef>test-identity2</identityRef>
+
+    <augumentedList>
+        <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+    </augumentedList>
+
+    <augumentContainer>
+    </augumentContainer>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_createContainerActualPresent/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_createContainerActualPresent/current.xml
new file mode 100644 (file)
index 0000000..d55c195
--- /dev/null
@@ -0,0 +1,3 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_createContainerActualPresent/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_createContainerActualPresent/merge.xml
new file mode 100644 (file)
index 0000000..79e1306
--- /dev/null
@@ -0,0 +1,4 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="create">
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_deleteContainerActualMissing/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_deleteContainerActualMissing/merge.xml
new file mode 100644 (file)
index 0000000..41c6caa
--- /dev/null
@@ -0,0 +1,4 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="delete">
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_noneContainerActualMissing/defaultOperation.txt b/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_noneContainerActualMissing/defaultOperation.txt
new file mode 100644 (file)
index 0000000..c86c3f3
--- /dev/null
@@ -0,0 +1 @@
+none
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_noneContainerActualMissing/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/containerTest_noneContainerActualMissing/merge.xml
new file mode 100644 (file)
index 0000000..2915070
--- /dev/null
@@ -0,0 +1,7 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <!--container is not present and default value is NONE-->
+    <uint32 nc:operation="replace">88</uint32>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_createLeafActualPresent/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_createLeafActualPresent/current.xml
new file mode 100644 (file)
index 0000000..860fdb4
--- /dev/null
@@ -0,0 +1,3 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <leafList>currentLeafList1</leafList>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_createLeafActualPresent/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_createLeafActualPresent/merge.xml
new file mode 100644 (file)
index 0000000..c5440f0
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="merge">
+    <leafList nc:operation="create">currentLeafList1</leafList>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_deleteLeafActualMissing/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_deleteLeafActualMissing/current.xml
new file mode 100644 (file)
index 0000000..83bf5ac
--- /dev/null
@@ -0,0 +1,2 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_deleteLeafActualMissing/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafListTest_deleteLeafActualMissing/merge.xml
new file mode 100644 (file)
index 0000000..ae24aca
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="merge">
+    <leafList nc:operation="delete">currentLeafList1</leafList>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_createLeafActualPresent/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_createLeafActualPresent/current.xml
new file mode 100644 (file)
index 0000000..f78d3ff
--- /dev/null
@@ -0,0 +1,3 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>44</uint32>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_createLeafActualPresent/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_createLeafActualPresent/merge.xml
new file mode 100644 (file)
index 0000000..1f0dacf
--- /dev/null
@@ -0,0 +1,7 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="merge">
+
+    <uint32 nc:operation="create">88</uint32>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_deleteLeafActualMissing/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_deleteLeafActualMissing/current.xml
new file mode 100644 (file)
index 0000000..83bf5ac
--- /dev/null
@@ -0,0 +1,2 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_deleteLeafActualMissing/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/leafTest_deleteLeafActualMissing/merge.xml
new file mode 100644 (file)
index 0000000..f78f610
--- /dev/null
@@ -0,0 +1,7 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="merge">
+
+    <uint32 nc:operation="delete">88</uint32>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_createListActualPresent/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_createListActualPresent/current.xml
new file mode 100644 (file)
index 0000000..012271a
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <list>
+        <uint32>1</uint32>
+    </list>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_createListActualPresent/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_createListActualPresent/merge.xml
new file mode 100644 (file)
index 0000000..99f9d2e
--- /dev/null
@@ -0,0 +1,8 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <list nc:operation="create">
+        <uint32>1</uint32>
+    </list>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_deleteListActualMissing/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_deleteListActualMissing/current.xml
new file mode 100644 (file)
index 0000000..012271a
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <list>
+        <uint32>1</uint32>
+    </list>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_deleteListActualMissing/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_deleteListActualMissing/merge.xml
new file mode 100644 (file)
index 0000000..8b72242
--- /dev/null
@@ -0,0 +1,8 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <list nc:operation="delete">
+        <uint32>2</uint32>
+    </list>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/current.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/current.xml
new file mode 100644 (file)
index 0000000..012271a
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <list>
+        <uint32>1</uint32>
+    </list>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/defaultOperation.txt b/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/defaultOperation.txt
new file mode 100644 (file)
index 0000000..c86c3f3
--- /dev/null
@@ -0,0 +1 @@
+none
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/merge.xml b/yang/yang-data-operations/src/test/resources/xmls-negative/listTest_noneListActualMissing/merge.xml
new file mode 100644 (file)
index 0000000..dc90cc2
--- /dev/null
@@ -0,0 +1,11 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <list>
+        <uint32>2</uint32>
+        <containerInList nc:operation="create">
+            <uint32>88</uint32>
+        </containerInList>
+    </list>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/current.xml
new file mode 100644 (file)
index 0000000..c5c0159
--- /dev/null
@@ -0,0 +1,4 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <identityRef>test-identity2</identityRef>
+    <augumentString2>augumentString2</augumentString2>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/merge.xml
new file mode 100644 (file)
index 0000000..6b3a009
--- /dev/null
@@ -0,0 +1,10 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <augumentedList nc:operation="create">
+        <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+    </augumentedList>
+
+    <augumentedList nc:operation="replace">
+        <augumentStringInAugumentList>str2</augumentStringInAugumentList>
+    </augumentedList>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationDifferentCases/result.xml
new file mode 100644 (file)
index 0000000..fcacf89
--- /dev/null
@@ -0,0 +1,14 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <identityRef>test-identity2</identityRef>
+
+    <augumentedList>
+        <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+    </augumentedList>
+
+    <augumentedList>
+        <augumentStringInAugumentList>str2</augumentStringInAugumentList>
+    </augumentedList>
+
+    <augumentString2>augumentString2</augumentString2>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/current.xml
new file mode 100644 (file)
index 0000000..b9d3c36
--- /dev/null
@@ -0,0 +1,9 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <identityRef>test-identity</identityRef>
+    <augumentString1>augumentString1</augumentString1>
+    <augumentContainer>
+        <augumentStringInAugumentContainer>
+            case1
+        </augumentStringInAugumentContainer>
+    </augumentContainer>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/merge.xml
new file mode 100644 (file)
index 0000000..afc17f8
--- /dev/null
@@ -0,0 +1,9 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <augumentString1>augumentString1</augumentString1>
+
+    <augumentContainer>
+        <augumentStringInAugumentContainer nc:operation="delete">
+        </augumentStringInAugumentContainer>
+    </augumentContainer>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualModificationSameCase/result.xml
new file mode 100644 (file)
index 0000000..3019b6e
--- /dev/null
@@ -0,0 +1,9 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <identityRef>test-identity</identityRef>
+
+    <augumentString1>augumentString1</augumentString1>
+
+    <augumentContainer>
+    </augumentContainer>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/current.xml
new file mode 100644 (file)
index 0000000..fd57674
--- /dev/null
@@ -0,0 +1,8 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <identityRef>test-identity</identityRef>
+    <augumentContainer>
+        <augumentStringInAugumentContainer>
+            case1
+        </augumentStringInAugumentContainer>
+    </augumentContainer>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/merge.xml
new file mode 100644 (file)
index 0000000..0e68281
--- /dev/null
@@ -0,0 +1,7 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <identityRef>test-identity2</identityRef>
+    <augumentedList nc:operation="create">
+        <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+    </augumentedList>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_choiceActualOneCaseModificationOtherCase/result.xml
new file mode 100644 (file)
index 0000000..47eae32
--- /dev/null
@@ -0,0 +1,6 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <identityRef>test-identity2</identityRef>
+    <augumentedList>
+        <augumentStringInAugumentList>str1</augumentStringInAugumentList>
+    </augumentedList>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_createContainer/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_createContainer/merge.xml
new file mode 100644 (file)
index 0000000..79aad42
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="create">
+
+    <!--Inner operations under create are ignored-->
+    <uint32 nc:operation="replace">88</uint32>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_createContainer/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_createContainer/result.xml
new file mode 100644 (file)
index 0000000..7e29bf0
--- /dev/null
@@ -0,0 +1,3 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>88</uint32>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_deleteContainer/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_deleteContainer/current.xml
new file mode 100644 (file)
index 0000000..36530ed
--- /dev/null
@@ -0,0 +1,3 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>1</uint32>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_deleteContainer/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_deleteContainer/merge.xml
new file mode 100644 (file)
index 0000000..9c38da8
--- /dev/null
@@ -0,0 +1,3 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/current.xml
new file mode 100644 (file)
index 0000000..b0959d1
--- /dev/null
@@ -0,0 +1,9 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <innerContainer>
+           <uint16>11</uint16>
+        <innerInnerContainer>
+               <uint32>11</uint32>
+               <uint16>11</uint16>
+        </innerInnerContainer>
+    </innerContainer>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/merge.xml
new file mode 100644 (file)
index 0000000..0a29154
--- /dev/null
@@ -0,0 +1,12 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <innerContainer nc:operation="merge">
+         <!--TODO integer element has to contain value in order to be parsed even if its being removed-->
+        <uint16 nc:operation="remove">-1</uint16>
+        <innerInnerContainer nc:operation="replace">
+            <uint16>22</uint16>
+        </innerInnerContainer>
+    </innerContainer>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerContainerContainer/result.xml
new file mode 100644 (file)
index 0000000..247caf7
--- /dev/null
@@ -0,0 +1,7 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <innerContainer>
+        <innerInnerContainer>
+            <uint16>22</uint16>
+        </innerInnerContainer>
+    </innerContainer>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/current.xml
new file mode 100644 (file)
index 0000000..97cd725
--- /dev/null
@@ -0,0 +1,10 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>1</uint32>
+    <augumentUint32>1</augumentUint32>
+    <string>currentString</string>
+    <decimal64>45.1</decimal64>
+    <binary>abcd</binary>
+
+    <identityRef>test-identity</identityRef>
+    <augumentString1>augumentString1</augumentString1>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/merge.xml
new file mode 100644 (file)
index 0000000..943836a
--- /dev/null
@@ -0,0 +1,13 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <uint32 nc:operation="replace">88</uint32>
+    <augumentUint32>88</augumentUint32>
+    <decimal64 nc:operation="merge">88.1</decimal64>
+    <string nc:operation="delete"></string>
+    <binary nc:operation="remove"></binary>
+    <boolean nc:operation="create">false</boolean>
+
+    <identityRef>test-identity2</identityRef>
+    <augumentString2 nc:operation="create">augumentString2</augumentString2>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_innerLeavesBaseOperationsContainer/result.xml
new file mode 100644 (file)
index 0000000..618d721
--- /dev/null
@@ -0,0 +1,8 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>88</uint32>
+    <augumentUint32>88</augumentUint32>
+    <decimal64>88.1</decimal64>
+    <identityRef>test-identity2</identityRef>
+    <boolean>false</boolean>
+    <augumentString2>augumentString2</augumentString2>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/current.xml
new file mode 100644 (file)
index 0000000..1044367
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+       <uint32>1</uint32>
+       <string>currentString</string>
+    <decimal64>45.1</decimal64>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/defaultOperation.txt b/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/defaultOperation.txt
new file mode 100644 (file)
index 0000000..c86c3f3
--- /dev/null
@@ -0,0 +1 @@
+none
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/merge.xml
new file mode 100644 (file)
index 0000000..7f047ee
--- /dev/null
@@ -0,0 +1,9 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <uint32 nc:operation="replace">88</uint32>
+    <decimal64 nc:operation="merge">88.1</decimal64>
+    <string>newString</string>
+    <binary >aaa</binary>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_noneContainer/result.xml
new file mode 100644 (file)
index 0000000..e5b4866
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>88</uint32>
+    <string>currentString</string>
+    <decimal64>88.1</decimal64>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_removeContainer/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_removeContainer/current.xml
new file mode 100644 (file)
index 0000000..36530ed
--- /dev/null
@@ -0,0 +1,3 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>1</uint32>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_removeContainer/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_removeContainer/merge.xml
new file mode 100644 (file)
index 0000000..8a03228
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="remove"
+           >
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/current.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/current.xml
new file mode 100644 (file)
index 0000000..510f5ee
--- /dev/null
@@ -0,0 +1,4 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+       <uint32>1</uint32>
+       <string>currentString</string>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/merge.xml
new file mode 100644 (file)
index 0000000..33421a6
--- /dev/null
@@ -0,0 +1,7 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+           nc:operation="replace">
+    <!--Inner strategies under replace are ignored-->
+    <uint32 nc:operation="remove">88</uint32>
+    <string nc:operation="delete">string</string>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/result.xml b/yang/yang-data-operations/src/test/resources/xmls/containerTest_replaceContainer/result.xml
new file mode 100644 (file)
index 0000000..1cea85f
--- /dev/null
@@ -0,0 +1,4 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>88</uint32>
+    <string>string</string>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/leafListTest/current.xml b/yang/yang-data-operations/src/test/resources/xmls/leafListTest/current.xml
new file mode 100644 (file)
index 0000000..581faf9
--- /dev/null
@@ -0,0 +1,6 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+       <leafList>currentLeafList1</leafList>
+       <leafList>currentLeafList2</leafList>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/leafListTest/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/leafListTest/merge.xml
new file mode 100644 (file)
index 0000000..39a9d22
--- /dev/null
@@ -0,0 +1,10 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <leafList nc:operation="delete">currentLeafList1</leafList>
+    <leafList nc:operation="remove">random</leafList>
+    <leafList nc:operation="create">currentLeafList3</leafList>
+    <leafList nc:operation="replace">currentLeafList4</leafList>
+    <leafList nc:operation="merge">currentLeafList5</leafList>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/leafListTest/result.xml b/yang/yang-data-operations/src/test/resources/xmls/leafListTest/result.xml
new file mode 100644 (file)
index 0000000..5a7e98c
--- /dev/null
@@ -0,0 +1,8 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+    <leafList>currentLeafList2</leafList>
+    <leafList>currentLeafList3</leafList>
+    <leafList>currentLeafList4</leafList>
+    <leafList>currentLeafList5</leafList>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/listTest/current.xml b/yang/yang-data-operations/src/test/resources/xmls/listTest/current.xml
new file mode 100644 (file)
index 0000000..15334b8
--- /dev/null
@@ -0,0 +1,31 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+
+       <list>
+        <uint32>1</uint32>
+        <containerInList>
+            <uint32>32</uint32>
+        </containerInList>
+       </list>
+       <list>
+        <uint32>2</uint32>
+        <containerInList>
+            <uint32>32</uint32>
+        </containerInList>
+       </list>
+       <list>
+        <uint32>6</uint32>
+        <containerInList>
+            <uint32>32</uint32>
+        </containerInList>
+       </list>
+       <list>
+        <uint32>3</uint32>
+       </list>
+       <list>
+        <uint32>4</uint32>
+       </list>
+       <list>
+        <uint32>5</uint32>
+       </list>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/listTest/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/listTest/merge.xml
new file mode 100644 (file)
index 0000000..c4dc7ee
--- /dev/null
@@ -0,0 +1,34 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <list nc:operation="merge">
+        <uint32>1</uint32>
+        <containerInList>
+            <uint32>88</uint32>
+        </containerInList>
+    </list>
+    <list nc:operation="merge">
+        <uint32>2</uint32>
+        <containerInList nc:operation="replace">
+        </containerInList>
+    </list>
+    <list nc:operation="delete">
+        <uint32>3</uint32>
+    </list>
+    <list nc:operation="remove">
+        <uint32>4</uint32>
+    </list>
+    <list>
+        <uint32>5</uint32>
+        <containerInList nc:operation="create">
+            <uint32>88</uint32>
+        </containerInList>
+    </list>
+    <list>
+        <uint32>6</uint32>
+        <containerInList>
+            <uint32 nc:operation="delete">-1</uint32>
+        </containerInList>
+    </list>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/listTest/result.xml b/yang/yang-data-operations/src/test/resources/xmls/listTest/result.xml
new file mode 100644 (file)
index 0000000..f2e39f3
--- /dev/null
@@ -0,0 +1,25 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <list>
+        <uint32>1</uint32>
+        <containerInList>
+            <uint32>88</uint32>
+        </containerInList>
+    </list>
+    <list>
+        <uint32>2</uint32>
+        <containerInList>
+        </containerInList>
+    </list>
+    <list>
+        <uint32>6</uint32>
+        <containerInList>
+        </containerInList>
+    </list>
+    <list>
+        <uint32>5</uint32>
+        <containerInList>
+            <uint32>88</uint32>
+        </containerInList>
+    </list>
+
+</container>
diff --git a/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/current.xml b/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/current.xml
new file mode 100644 (file)
index 0000000..c2aac04
--- /dev/null
@@ -0,0 +1,9 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+       <list>
+        <uint32>1</uint32>
+        <containerInList>
+            <uint32>32</uint32>
+            <uint16>32</uint16>
+        </containerInList>
+       </list>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/defaultOperation.txt b/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/defaultOperation.txt
new file mode 100644 (file)
index 0000000..c86c3f3
--- /dev/null
@@ -0,0 +1 @@
+none
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/merge.xml
new file mode 100644 (file)
index 0000000..8bf933d
--- /dev/null
@@ -0,0 +1,11 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <list>
+        <uint32>1</uint32>
+        <containerInList>
+            <uint16 nc:operation="delete">88</uint16>
+        </containerInList>
+    </list>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/result.xml b/yang/yang-data-operations/src/test/resources/xmls/listTest_alterInnerValue/result.xml
new file mode 100644 (file)
index 0000000..31bd961
--- /dev/null
@@ -0,0 +1,8 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <list>
+        <uint32>1</uint32>
+        <containerInList>
+            <uint32>32</uint32>
+        </containerInList>
+    </list>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/current.xml b/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/current.xml
new file mode 100644 (file)
index 0000000..1044367
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+       <uint32>1</uint32>
+       <string>currentString</string>
+    <decimal64>45.1</decimal64>
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/defaultOperation.txt b/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/defaultOperation.txt
new file mode 100644 (file)
index 0000000..c86c3f3
--- /dev/null
@@ -0,0 +1 @@
+none
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/merge.xml b/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/merge.xml
new file mode 100644 (file)
index 0000000..9836290
--- /dev/null
@@ -0,0 +1,9 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test"
+           xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+
+    <uint32>88</uint32>
+    <decimal64>88.1</decimal64>
+    <string>newString</string>
+    <binary >aaa</binary>
+
+</container>
\ No newline at end of file
diff --git a/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/result.xml b/yang/yang-data-operations/src/test/resources/xmls/none_NoChange/result.xml
new file mode 100644 (file)
index 0000000..fb0e5f7
--- /dev/null
@@ -0,0 +1,5 @@
+<container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test">
+    <uint32>1</uint32>
+    <string>currentString</string>
+    <decimal64>45.1</decimal64>
+</container>
\ No newline at end of file