Fix preparing of action request 72/79472/7
authorAnna Bencurova <Anna.Bencurova@pantheon.tech>
Thu, 10 Jan 2019 14:58:04 +0000 (15:58 +0100)
committerJakub Morvay <jakub.morvay@gmail.com>
Mon, 14 Jan 2019 13:30:39 +0000 (13:30 +0000)
When the YangInstanceIdentifier used for creation of action request
contained mixin path argument (e.g. list as whole), the list ID was in
request twice. Once for list as whole and once for the list entry.

Change-Id: Ic6507c0137abedb6c87718c4a536c983033488f6
JIRA: NETCONF-566
Signed-off-by: Anna Bencurova <Anna.Bencurova@pantheon.tech>
Signed-off-by: Jakub Morvay <jmorvay@frinx.io>
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfMessageTransformUtil.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java
netconf/sal-netconf-connector/src/test/resources/schemas/example-server-farm.yang

index 1c390fb903145a3d4c4202a7ba74ec6c96977ca8..82f54b952dc784621c1f55dce21cbfcf9bf94f0b 100644 (file)
@@ -53,6 +53,7 @@ import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
@@ -225,7 +226,8 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
 
         if (actionDefinition.getInput().getChildNodes().isEmpty()) {
             return new NetconfMessage(NetconfMessageTransformUtil.prepareDomResultForActionRequest(
-                    domDataTreeIdentifier, action, counter, actionDefinition.getQName().getLocalName())
+                    DataSchemaContextTree.from(schemaContext), domDataTreeIdentifier, action, counter,
+                    actionDefinition.getQName().getLocalName())
                     .getNode().getOwnerDocument());
         }
 
@@ -237,7 +239,8 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
         // Set the path to the input of rpc for the node stream writer
         action = action.createChild(QName.create(action.getLastComponent(), "input").intern());
         final DOMResult result = NetconfMessageTransformUtil.prepareDomResultForActionRequest(
-                domDataTreeIdentifier, action, counter, actionDefinition.getQName().getLocalName());
+                DataSchemaContextTree.from(schemaContext), domDataTreeIdentifier, action, counter,
+                actionDefinition.getQName().getLocalName());
 
         try {
             NetconfMessageTransformUtil.writeNormalizedRpc((ContainerNode) payload, result,
index 2454b5eedc8931eeaf8060e096ec981cbb5b4909..bec32307d02254028b58c4203e48445c531a3bf8 100644 (file)
@@ -62,6 +62,8 @@ import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.SchemaOrderedNormalizedNodeWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -425,8 +427,9 @@ public final class NetconfMessageTransformUtil {
         return new DOMResult(elementNS);
     }
 
-    public static DOMResult prepareDomResultForActionRequest(final DOMDataTreeIdentifier domDataTreeIdentifier,
-            final SchemaPath actionSchemaPath, final MessageCounter counter, final String action) {
+    public static DOMResult prepareDomResultForActionRequest(final DataSchemaContextTree dataSchemaContextTree,
+            final DOMDataTreeIdentifier domDataTreeIdentifier, final SchemaPath actionSchemaPath,
+            final MessageCounter counter, final String action) {
         final Document document = XmlUtil.newDocument();
         final Element rpcNS =
                 document.createElementNS(NETCONF_RPC_QNAME.getNamespace().toString(), NETCONF_RPC_QNAME.getLocalName());
@@ -434,8 +437,8 @@ public final class NetconfMessageTransformUtil {
         rpcNS.setAttribute(MESSAGE_ID_ATTR, counter.getNewMessageId(MESSAGE_ID_PREFIX));
 
         final Element actionNS = document.createElementNS(NETCONF_ACTION_NAMESPACE.toString(), NETCONF_ACTION);
-
-        final Element actionData = prepareActionData(actionNS,
+        final DataSchemaContextNode<?> rootSchemaContextNode = dataSchemaContextTree.getRoot();
+        final Element actionData = prepareActionData(rootSchemaContextNode, actionNS,
                 domDataTreeIdentifier.getRootIdentifier().getPathArguments().iterator(), document);
 
         Element specificActionElement = document.createElement(action);
@@ -445,12 +448,19 @@ public final class NetconfMessageTransformUtil {
         return new DOMResult(specificActionElement);
     }
 
-    private static Element prepareActionData(final Element actionNS, final Iterator<PathArgument> iterator,
-            final Document document) {
+    private static Element prepareActionData(final DataSchemaContextNode<?> currentParentSchemaNode,
+            final Element actionNS, final Iterator<PathArgument> iterator, final Document document) {
         if (iterator.hasNext()) {
-            PathArgument next = iterator.next();
+            final PathArgument next = iterator.next();
             final QName actualNS = next.getNodeType();
 
+            DataSchemaContextNode<?> current = currentParentSchemaNode.getChild(next);
+            Preconditions.checkArgument(current != null, "Invalid input: schema for argument %s not found", next);
+
+            if (current.isMixin()) {
+                return prepareActionData(current, actionNS, iterator, document);
+            }
+
             final Element actualElement = document.createElementNS(actualNS.getNamespace().toString(),
                     actualNS.getLocalName());
             if (next instanceof NodeWithValue) {
@@ -465,7 +475,7 @@ public final class NetconfMessageTransformUtil {
                 }
             }
             actionNS.appendChild(actualElement);
-            return prepareActionData(actualElement, iterator, document);
+            return prepareActionData(current, actualElement, iterator, document);
         } else {
             return actionNS;
         }
index a91458077f24a0321b4742a8668039db7acca65f..02d8ddc3b40b0ba0dbfcbd2d4ba8b7325751da77 100644 (file)
@@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -399,7 +400,8 @@ public class NetconfMessageTransformerTest {
         QName reset = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "reset");
         QName start = QName.create(reset, "start");
         QName open = QName.create(start, "open");
-        Set<QName> qnames = new HashSet<>(Arrays.asList(reset, start, open));
+        QName enable = QName.create(open, "enable");
+        Set<QName> qnames = new HashSet<>(Arrays.asList(reset, start, open, enable));
         Set<ActionDefinition> actions = actionNetconfMessageTransformer.getActions();
         assertTrue(!actions.isEmpty());
         for (ActionDefinition actionDefinition : actions) {
@@ -414,9 +416,9 @@ public class NetconfMessageTransformerTest {
         QName qname = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "server");
         QName nameQname = QName.create(qname, "name");
         QName actionResetQName = QName.create(qname, "reset");
-
-        Set<PathArgument> nodeIdentifiers =
-                Collections.singleton(new NodeIdentifierWithPredicates(qname, nameQname, "test"));
+        List<PathArgument> nodeIdentifiers = new ArrayList<>();
+        nodeIdentifiers.add(new NodeIdentifier(qname));
+        nodeIdentifiers.add(new NodeIdentifierWithPredicates(qname, nameQname, "test"));
         DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
 
         ContainerNode data = initInputAction(QName.create(qname, "reset-at"), "now");
@@ -443,7 +445,7 @@ public class NetconfMessageTransformerTest {
         QName qname = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "device");
         QName actionStartQName = QName.create(qname, "start");
 
-        Set<PathArgument> nodeIdentifiers = Collections.singleton(NodeIdentifier.create(qname));
+        List<PathArgument> nodeIdentifiers = Collections.singletonList(NodeIdentifier.create(qname));
         DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
 
         NormalizedNode<?, ?> payload = initInputAction(QName.create(qname, "start-at"), "now");
@@ -464,7 +466,7 @@ public class NetconfMessageTransformerTest {
         QName boxInQName = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "box-in");
         QName actionOpenQName = QName.create(boxOutQName, "open");
 
-        Set<PathArgument> nodeIdentifiers = new HashSet<>();
+        List<PathArgument> nodeIdentifiers = new ArrayList<>();
         nodeIdentifiers.add(NodeIdentifier.create(boxOutQName));
         nodeIdentifiers.add(NodeIdentifier.create(boxInQName));
 
@@ -486,6 +488,42 @@ public class NetconfMessageTransformerTest {
         checkNode(action, null, actionOpenQName.getLocalName(), null);
     }
 
+    @Test
+    public void toActionRequestListInContainerTest() {
+        QName qnameDevice = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "device");
+        QName qnameInterface = QName.create(URN_EXAMPLE_SERVER_FARM, REVISION_EXAMPLE_SERVER_FARM, "interface");
+        QName nameQname = QName.create(qnameInterface, "name");
+        QName actionEnableQName = QName.create(qnameInterface, "enable");
+
+        List<PathArgument> nodeIdentifiers = new ArrayList<>();
+        nodeIdentifiers.add(NodeIdentifier.create(qnameDevice));
+        nodeIdentifiers.add(NodeIdentifier.create(qnameInterface));
+        nodeIdentifiers.add(new NodeIdentifierWithPredicates(qnameInterface, nameQname, "test"));
+
+        DOMDataTreeIdentifier domDataTreeIdentifier = prepareDataTreeId(nodeIdentifiers);
+
+        NormalizedNode<?, ?> payload = initEmptyInputAction(qnameInterface);
+        NetconfMessage actionRequest = actionNetconfMessageTransformer.toActionRequest(
+                SchemaPath.create(true, actionEnableQName), domDataTreeIdentifier, payload);
+
+        Node childAction = checkBasePartOfActionRequest(actionRequest);
+
+        Node childDevice = childAction.getFirstChild();
+        checkNode(childDevice, "device", "device", qnameDevice.getNamespace().toString());
+
+        Node childInterface = childDevice.getFirstChild();
+        checkNode(childInterface, "interface", "interface", qnameInterface.getNamespace().toString());
+
+        Node childName = childInterface.getFirstChild();
+        checkNode(childName, "name", "name", nameQname.getNamespace().toString());
+
+        Node childTest = childName.getFirstChild();
+        assertEquals(childTest.getNodeValue(), "test");
+
+        Node action = childInterface.getLastChild();
+        checkNode(action, null, actionEnableQName.getLocalName(), null);
+    }
+
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @Test
     public void toActionResultTest() throws Exception {
@@ -532,7 +570,7 @@ public class NetconfMessageTransformerTest {
         return childAction;
     }
 
-    private static DOMDataTreeIdentifier prepareDataTreeId(final Set<PathArgument> nodeIdentifiers) {
+    private static DOMDataTreeIdentifier prepareDataTreeId(final List<PathArgument> nodeIdentifiers) {
         YangInstanceIdentifier yangInstanceIdentifier =
                 YangInstanceIdentifier.builder().append(nodeIdentifiers).build();
         DOMDataTreeIdentifier domDataTreeIdentifier =
@@ -550,6 +588,11 @@ public class NetconfMessageTransformerTest {
         return data;
     }
 
+    private static ContainerNode initEmptyInputAction(final QName qname) {
+        return ImmutableContainerNodeBuilder.create().withNodeIdentifier(NodeIdentifier.create(
+                QName.create(qname, "input"))).build();
+    }
+
     private static void checkNode(final Node childServer, final String expectedLocalName, final String expectedNodeName,
             final String expectedNamespace) {
         assertNotNull(childServer);
index 0cc0fef7be26300bfc101e811e8e0029ba5d33d1..dd3218c43f43fb3d7ae09ce16b8f234aba89a9c6 100644 (file)
@@ -40,6 +40,15 @@ module example-server-farm {
         }
       }
     }
+
+    list interface {
+      key name;
+      leaf name {
+        type string;
+      }
+      action enable {
+      }
+    }
   }
 
   container box-out {