From 4892ae40dc6ff83d122601941599369241955e76 Mon Sep 17 00:00:00 2001 From: Anna Bencurova Date: Thu, 10 Jan 2019 15:58:04 +0100 Subject: [PATCH] Fix preparing of action request 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 Signed-off-by: Jakub Morvay --- .../mapping/NetconfMessageTransformer.java | 7 ++- .../util/NetconfMessageTransformUtil.java | 26 ++++++--- .../NetconfMessageTransformerTest.java | 57 ++++++++++++++++--- .../schemas/example-server-farm.yang | 9 +++ 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java index 1c390fb903..82f54b952d 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java @@ -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 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 iterator, - final Document document) { + private static Element prepareActionData(final DataSchemaContextNode currentParentSchemaNode, + final Element actionNS, final Iterator 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; } diff --git a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java index a91458077f..02d8ddc3b4 100644 --- a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java +++ b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java @@ -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 qnames = new HashSet<>(Arrays.asList(reset, start, open)); + QName enable = QName.create(open, "enable"); + Set qnames = new HashSet<>(Arrays.asList(reset, start, open, enable)); Set 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 nodeIdentifiers = - Collections.singleton(new NodeIdentifierWithPredicates(qname, nameQname, "test")); + List 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 nodeIdentifiers = Collections.singleton(NodeIdentifier.create(qname)); + List 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 nodeIdentifiers = new HashSet<>(); + List 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 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 nodeIdentifiers) { + private static DOMDataTreeIdentifier prepareDataTreeId(final List 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); diff --git a/netconf/sal-netconf-connector/src/test/resources/schemas/example-server-farm.yang b/netconf/sal-netconf-connector/src/test/resources/schemas/example-server-farm.yang index 0cc0fef7be..dd3218c43f 100644 --- a/netconf/sal-netconf-connector/src/test/resources/schemas/example-server-farm.yang +++ b/netconf/sal-netconf-connector/src/test/resources/schemas/example-server-farm.yang @@ -40,6 +40,15 @@ module example-server-farm { } } } + + list interface { + key name; + leaf name { + type string; + } + action enable { + } + } } container box-out { -- 2.36.6