BUG-2254 Make runtime rpcs in config subsystem/netconf handle context-instance attrib... 86/12286/3
authorMaros Marsalek <mmarsale@cisco.com>
Wed, 5 Nov 2014 13:29:55 +0000 (14:29 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Wed, 5 Nov 2014 13:29:55 +0000 (14:29 +0100)
Change-Id: I9ca4accdb10ba5a6b52ce9b8f7ad02a8cbe8743d
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java
opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java
opendaylight/netconf/config-netconf-connector/pom.xml
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolvedTest.java [new file with mode: 0644]

index 893a45aaa2df41eadc71a1a62215493fda3d4a04..2e5f8078a377e980d88e7c52e337f4fb265108e2 100644 (file)
@@ -43,6 +43,7 @@ import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -344,9 +345,14 @@ public class NetconfMessageTransformUtil {
         Preconditions.checkNotNull(rpcName);
         Preconditions.checkNotNull(schemaContext);
 
-        final NodeContainerProxy rpcBodyProxy = new NodeContainerProxy(rpcName, schemaContext.getChildNodes());
-        return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.<DataSchemaNode>newHashSet(rpcBodyProxy));
+        for (final RpcDefinition rpcDefinition : schemaContext.getOperations()) {
+            if(rpcDefinition.getQName().equals(rpcName)) {
+                final NodeContainerProxy rpcBodyProxy = new NodeContainerProxy(rpcName, rpcDefinition.getInput().getChildNodes());
+                return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.<DataSchemaNode>newHashSet(rpcBodyProxy));
+            }
+        }
 
+        throw new IllegalArgumentException("Rpc " + rpcName + " not found in schema context " + schemaContext + ". Unable to invoke Rpc");
     }
 
     public static CompositeNodeTOImpl wrap(final QName name, final Node<?> node) {
index e744e11bc9212fc58666654b454a804e1e7f06ce..4bf2e8463e616188125600bbaff2d4c0da8c6db7 100644 (file)
@@ -253,37 +253,4 @@ public class NetconfToRpcRequestTest {
         assertEquals(streamName.getLocalName(), "stream-name");
     }
 
-    @Test
-    public void testNoSchemaContextToRpcRequest() throws Exception {
-        final String exampleNamespace = "http://example.net/me/my-own/1.0";
-        final String exampleRevision = "2014-07-22";
-        final QName myOwnMethodRpcQName = QName.create(exampleNamespace, exampleRevision, "my-own-method");
-
-        final CompositeNodeBuilder<ImmutableCompositeNode> rootBuilder = ImmutableCompositeNode.builder();
-        rootBuilder.setQName(myOwnMethodRpcQName);
-
-        final CompositeNodeBuilder<ImmutableCompositeNode> inputBuilder = ImmutableCompositeNode.builder();
-        inputBuilder.setQName(QName.create(exampleNamespace, exampleRevision, "input"));
-        inputBuilder.addLeaf(QName.create(exampleNamespace, exampleRevision, "my-first-parameter"), "14");
-        inputBuilder.addLeaf(QName.create(exampleNamespace, exampleRevision, "another-parameter"), "fred");
-
-        rootBuilder.add(inputBuilder.toInstance());
-        final ImmutableCompositeNode root = rootBuilder.toInstance();
-
-        final NetconfMessage message = messageTransformer.toRpcRequest(myOwnMethodRpcQName, root);
-        assertNotNull(message);
-
-        final Document xmlDoc = message.getDocument();
-        final org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild();
-        assertEquals(rpcChild.getLocalName(), "rpc");
-
-        final org.w3c.dom.Node myOwnMethodNode = rpcChild.getFirstChild();
-        assertEquals(myOwnMethodNode.getLocalName(), "my-own-method");
-
-        final org.w3c.dom.Node firstParamNode = myOwnMethodNode.getFirstChild();
-        assertEquals(firstParamNode.getLocalName(), "my-first-parameter");
-
-        final org.w3c.dom.Node secParamNode = firstParamNode.getNextSibling();
-        assertEquals(secParamNode.getLocalName(), "another-parameter");
-    }
 }
index edba4e11da8661a69660b89051286b4faaa4854e..2b3015243fa175ebc48dc40a839af4b5bbf63fd6 100644 (file)
                             org.opendaylight.controller.netconf.confignetconfconnector.util,
                             org.opendaylight.controller.netconf.confignetconfconnector.osgi,
                             org.opendaylight.controller.netconf.confignetconfconnector.exception,</Private-Package>
-            <Import-Package>com.google.common.base,
-                            com.google.common.collect,
-                            javax.annotation,
-                            javax.management,
-                            javax.management.openmbean,
-                            org.opendaylight.controller.config.api,
-                            org.opendaylight.controller.config.api.jmx,
-                            org.opendaylight.controller.config.yangjmxgenerator,
-                            org.opendaylight.controller.config.yangjmxgenerator.attribute,
-                            org.opendaylight.controller.netconf.api,
-                            org.opendaylight.controller.netconf.mapping.api,
-                            org.opendaylight.controller.netconf.util.mapping,
-                            org.opendaylight.controller.netconf.util.xml,
-                            org.opendaylight.controller.netconf.util.exception,
-                            org.opendaylight.yangtools.yang.common,
-                            org.opendaylight.yangtools.yang.model.api,
-                            org.osgi.framework,
-                            org.osgi.util.tracker,
-                            org.slf4j,
-                            org.w3c.dom,
-                            com.google.common.io,
-                            org.opendaylight.yangtools.yang.model.api.type,
-                            org.opendaylight.yangtools.sal.binding.generator.spi,
-                            org.opendaylight.yangtools.sal.binding.yang.types,
-                            org.opendaylight.controller.config.util
-              </Import-Package>
+            <Import-Package>*</Import-Package>
             <Export-Package></Export-Package>
           </instructions>
         </configuration>
index 7fd8928928feb8814b0eb003c61e2c51152beef5..551da722c06732b60219d80044b3d6ca5319f3fa 100644 (file)
@@ -8,20 +8,23 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Maps;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.management.ObjectName;
 
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.Modules;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module;
 
-import javax.management.ObjectName;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
 
 /**
  * Represents parsed xpath to runtime bean instance
@@ -46,6 +49,11 @@ public final class RuntimeRpcElementResolved {
         return moduleName;
     }
 
+    @VisibleForTesting
+    Map<String, String> getAdditionalAttributes() {
+        return additionalAttributes;
+    }
+
     public String getInstanceName() {
         return instanceName;
     }
@@ -70,22 +78,45 @@ public final class RuntimeRpcElementResolved {
         return ObjectNameUtil.createRuntimeBeanName(moduleName, instanceName, additionalAttributesJavaNames);
     }
 
+    /**
+     * Pattern for an absolute instance identifier xpath pointing to a runtime bean instance e.g:
+     * <pre>
+     * /modules/module[name=instanceName][type=moduleType]
+     * </pre>
+     * or
+     * <pre>
+     * /a:modules/a:module[a:name=instanceName][a:type=moduleType]
+     * </pre>
+     */
     private static final String xpathPatternBlueprint =
-            "/" + XmlNetconfConstants.MODULES_KEY
-            + "/" + XmlNetconfConstants.MODULE_KEY
-            + "\\["
-
-            + "(?<key1>type|name)"
-            + "='(?<value1>[^']+)'"
-            + "( and |\\]\\[)"
-            + "(?<key2>type|name)"
-            + "='(?<value2>[^']+)'"
-
-            + "\\]"
-            + "(?<additional>.*)";
+            "/" + getRegExForPrefixedName(Modules.QNAME.getLocalName())+ "/" + getRegExForPrefixedName(Module.QNAME.getLocalName())
+
+                    + "\\["
+                    + "(?<key1>" + getRegExForPrefixedName(XmlNetconfConstants.TYPE_KEY) + "|" + getRegExForPrefixedName(XmlNetconfConstants.NAME_KEY) + ")"
+                    + "=('|\")?(?<value1>[^'\"\\]]+)('|\")?"
+                    + "( and |\\]\\[)"
+                    + "(?<key2>" + getRegExForPrefixedName(XmlNetconfConstants.TYPE_KEY) + "|" + getRegExForPrefixedName(XmlNetconfConstants.NAME_KEY) + ")"
+                    + "=('|\")?(?<value2>[^'\"\\]]+)('|\")?"
+                    + "\\]"
+
+                    + "(?<additional>.*)";
+
+    /**
+     * Return reg ex that matches either the name with or without a prefix
+     */
+    private static String getRegExForPrefixedName(final String name) {
+        return "([^:]+:)?" + name;
+    }
 
     private static final Pattern xpathPattern = Pattern.compile(xpathPatternBlueprint);
-    private static final String additionalPatternBlueprint = "(?<additionalKey>.+)\\[(.+)='(?<additionalValue>.+)'\\]";
+
+    /**
+     * Pattern for additional path elements inside xpath for instance identifier pointing to an inner runtime bean e.g:
+     * <pre>
+     * /modules/module[name=instanceName and type=moduleType]/inner[key=b]
+     * </pre>
+     */
+    private static final String additionalPatternBlueprint = getRegExForPrefixedName("(?<additionalKey>.+)") + "\\[(?<prefixedKey>" + getRegExForPrefixedName("(.+)") + ")=('|\")?(?<additionalValue>[^'\"\\]]+)('|\")?\\]";
     private static final Pattern additionalPattern = Pattern.compile(additionalPatternBlueprint);
 
     public static RuntimeRpcElementResolved fromXpath(String xpath, String elementName, String namespace) {
@@ -115,20 +146,19 @@ public final class RuntimeRpcElementResolved {
         PatternGroupResolver(String key1, String value1,  String value2, String additional) {
             this.key1 = Preconditions.checkNotNull(key1);
             this.value1 = Preconditions.checkNotNull(value1);
-
             this.value2 = Preconditions.checkNotNull(value2);
-
             this.additional = Preconditions.checkNotNull(additional);
         }
 
         String getModuleName() {
-            return key1.equals(XmlNetconfConstants.TYPE_KEY) ? value1 : value2;
+            return key1.contains(XmlNetconfConstants.TYPE_KEY) ? value1 : value2;
         }
 
         String getInstanceName() {
-            return key1.equals(XmlNetconfConstants.NAME_KEY) ? value1 : value2;
+            return key1.contains(XmlNetconfConstants.NAME_KEY) ? value1 : value2;
         }
 
+
         Map<String, String> getAdditionalKeys(String elementName, String moduleName) {
             HashMap<String, String> additionalAttributes = Maps.newHashMap();
 
@@ -141,7 +171,7 @@ public final class RuntimeRpcElementResolved {
                 Preconditions
                         .checkState(
                                 matcher.matches(),
-                                "Attribute %s not in required form on rpc element %s, required format for additional attributes is  %s",
+                                "Attribute %s not in required form on rpc element %s, required format for additional attributes is: %s",
                                 additionalKeyValue, elementName, additionalPatternBlueprint);
                 String name = matcher.group("additionalKey");
                 runtimeBeanYangName = name;
diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolvedTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolvedTest.java
new file mode 100644 (file)
index 0000000..816e118
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.controller.netconf.confignetconfconnector.operations.runtimerpc;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RuntimeRpcElementResolvedTest {
+
+    private static final String MODULE_TYPE = "moduleType";
+    private static final String INSTANCE_NAME = "instanceName";
+    @Parameterized.Parameter(0)
+    public String xpath;
+    @Parameterized.Parameter(1)
+    public Map<String, String> additional;
+
+    @Parameterized.Parameters(name = "{index}: parsed({0}) contains moduleName:{1} and instanceName:{2}")
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+                // With namespaces
+                { "/a:modules/a:module[a:name='instanceName'][a:type='moduleType']/b:listener-state[b:peer-id='127.0.0.1']",
+                        new HashMap<String, String>() {{
+                            put("listener-state", "127.0.0.1");
+                        }}},
+                { "/a:modules/a:module[a:name='instanceName'][a:type='moduleType']",
+                        null},
+
+                // Without namespaces
+                { "/modules/module[name=instanceName][type=moduleType]", null},
+                { "/modules/module[type=moduleType][name='instanceName']", null},
+                { "/modules/module[name=\'instanceName\'][type=\"moduleType\"]", null},
+                { "/modules/module[type=moduleType and name=instanceName]", null},
+                { "/modules/module[name=\"instanceName\" and type=moduleType]", null},
+                { "/modules/module[type=\"moduleType\" and name=instanceName]", null},
+                { "/modules/module[name=\'instanceName\' and type=\"moduleType\"]", null},
+
+                // With inner beans
+                { "/modules/module[name=instanceName and type=\"moduleType\"]/inner[key=b]", Collections.singletonMap("inner", "b")},
+                { "/modules/module[name=instanceName and type=moduleType]/inner[key=b]", Collections.singletonMap("inner", "b")},
+                { "/modules/module[name=instanceName and type=moduleType]/inner[key=\'b\']", Collections.singletonMap("inner", "b")},
+                { "/modules/module[name=instanceName and type=moduleType]/inner[key=\"b\"]", Collections.singletonMap("inner", "b")},
+
+                { "/modules/module[name=instanceName and type=\"moduleType\"]/inner[key2=a]/inner2[key=b]",
+                        new HashMap<String, String>() {{
+                            put("inner", "a");
+                            put("inner2", "b");
+                        }}
+                },
+        });
+    }
+
+    @Test
+    public void testFromXpath() throws Exception {
+        final RuntimeRpcElementResolved resolved = RuntimeRpcElementResolved.fromXpath(xpath, "element", "namespace");
+        assertEquals(MODULE_TYPE, resolved.getModuleName());
+        assertEquals(INSTANCE_NAME, resolved.getInstanceName());
+        if (additional != null) {
+            assertEquals(additional, resolved.getAdditionalAttributes());
+        }
+    }
+}