From: Maros Marsalek Date: Wed, 5 Nov 2014 13:29:55 +0000 (+0100) Subject: BUG-2254 Make runtime rpcs in config subsystem/netconf handle context-instance attrib... X-Git-Tag: release/lithium~876^2~16^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=e359ec4465f75136a41de20c6c3f5628a2c37211;hp=--cc BUG-2254 Make runtime rpcs in config subsystem/netconf handle context-instance attribute with namespaces Change-Id: I9ca4accdb10ba5a6b52ce9b8f7ad02a8cbe8743d Signed-off-by: Maros Marsalek --- e359ec4465f75136a41de20c6c3f5628a2c37211 diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java index 893a45aaa2..2e5f8078a3 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java @@ -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.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.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) { diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java index e744e11bc9..4bf2e8463e 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java @@ -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 rootBuilder = ImmutableCompositeNode.builder(); - rootBuilder.setQName(myOwnMethodRpcQName); - - final CompositeNodeBuilder 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"); - } } diff --git a/opendaylight/netconf/config-netconf-connector/pom.xml b/opendaylight/netconf/config-netconf-connector/pom.xml index edba4e11da..2b3015243f 100644 --- a/opendaylight/netconf/config-netconf-connector/pom.xml +++ b/opendaylight/netconf/config-netconf-connector/pom.xml @@ -106,32 +106,7 @@ org.opendaylight.controller.netconf.confignetconfconnector.util, org.opendaylight.controller.netconf.confignetconfconnector.osgi, org.opendaylight.controller.netconf.confignetconfconnector.exception, - 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 - + * diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java index 7fd8928928..551da722c0 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java @@ -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 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: + *
+     * /modules/module[name=instanceName][type=moduleType]
+     * 
+ * or + *
+     * /a:modules/a:module[a:name=instanceName][a:type=moduleType]
+     * 
+ */ private static final String xpathPatternBlueprint = - "/" + XmlNetconfConstants.MODULES_KEY - + "/" + XmlNetconfConstants.MODULE_KEY - + "\\[" - - + "(?type|name)" - + "='(?[^']+)'" - + "( and |\\]\\[)" - + "(?type|name)" - + "='(?[^']+)'" - - + "\\]" - + "(?.*)"; + "/" + getRegExForPrefixedName(Modules.QNAME.getLocalName())+ "/" + getRegExForPrefixedName(Module.QNAME.getLocalName()) + + + "\\[" + + "(?" + getRegExForPrefixedName(XmlNetconfConstants.TYPE_KEY) + "|" + getRegExForPrefixedName(XmlNetconfConstants.NAME_KEY) + ")" + + "=('|\")?(?[^'\"\\]]+)('|\")?" + + "( and |\\]\\[)" + + "(?" + getRegExForPrefixedName(XmlNetconfConstants.TYPE_KEY) + "|" + getRegExForPrefixedName(XmlNetconfConstants.NAME_KEY) + ")" + + "=('|\")?(?[^'\"\\]]+)('|\")?" + + "\\]" + + + "(?.*)"; + + /** + * 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 = "(?.+)\\[(.+)='(?.+)'\\]"; + + /** + * Pattern for additional path elements inside xpath for instance identifier pointing to an inner runtime bean e.g: + *
+     * /modules/module[name=instanceName and type=moduleType]/inner[key=b]
+     * 
+ */ + private static final String additionalPatternBlueprint = getRegExForPrefixedName("(?.+)") + "\\[(?" + getRegExForPrefixedName("(.+)") + ")=('|\")?(?[^'\"\\]]+)('|\")?\\]"; 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 getAdditionalKeys(String elementName, String moduleName) { HashMap 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 index 0000000000..816e118f39 --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolvedTest.java @@ -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 additional; + + @Parameterized.Parameters(name = "{index}: parsed({0}) contains moduleName:{1} and instanceName:{2}") + public static Collection 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() {{ + 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() {{ + 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()); + } + } +}