From: Tony Tkacik Date: Tue, 5 Aug 2014 15:18:02 +0000 (+0000) Subject: Merge "Fix failing IT tests" X-Git-Tag: release/helium~345 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=1bf9f8c060f6adf32f527f6efe82f78f774ffd8d;hp=5712c1aa7f7c9d3ade45fe91acb9bc96d5681c8e Merge "Fix failing IT tests" --- diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index a7bbbe772d..ff8735a518 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -332,6 +332,11 @@ akka-testkit_${scala.version} ${akka.version} + + com.typesafe.akka + akka-osgi_${scala.version} + ${akka.version} + commons-codec commons-codec @@ -1284,6 +1289,13 @@ ${mdsal.version} + + org.opendaylight.controller + sal-remoterpc-connector + ${mdsal.version} + + + org.opendaylight.controller diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index e4468b6f27..f8796e0ae4 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -1062,6 +1062,11 @@ org.opendaylight.controller sal-restconf-broker + + org.opendaylight.controller + sal-remoterpc-connector + + org.opendaylight.controller diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java index 80d0f67ac4..47ef9039d1 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java @@ -70,10 +70,15 @@ public class NetconfMessageTransformer implements MessageTransformer toRpcResult(final NetconfMessage message, final QName rpc, final SchemaContext context) { final CompositeNode compositeNode; - if (NetconfMessageTransformUtil.isDataRetrievalOperation(rpc)) { - final Element xmlData = NetconfMessageTransformUtil.getDataSubtree(message.getDocument()); - final List> dataNodes = XmlDocumentUtils.toDomNodes(xmlData, Optional.of(context.getDataDefinitions()), context); final CompositeNodeBuilder it = ImmutableCompositeNode.builder(); it.setQName(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME); it.add(ImmutableCompositeNode.create(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataNodes)); - compositeNode = it.toInstance(); } else { - // TODO map rpc with schema - compositeNode = (CompositeNode) XmlDocumentUtils.toDomNode(message.getDocument()); + final CompositeNode rpcReply = XmlDocumentUtils.rpcReplyToDomNodes(message.getDocument(), rpc, context); + if (rpcReply != null) { + compositeNode = rpcReply; + } else { + compositeNode = (CompositeNode) XmlDocumentUtils.toDomNode(message.getDocument()); + } } - return RpcResultBuilder.success( compositeNode ).build(); } 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 d3faddd471..4f792a0a71 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 @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.sal.connect.netconf.util; +import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; @@ -226,6 +227,14 @@ public class NetconfMessageTransformUtil { NETCONF_GET_QNAME.getLocalName())); } + public static boolean isGetOperation(final QName rpc) { + return NETCONF_URI.equals(rpc.getNamespace()) && rpc.getLocalName().equals(NETCONF_GET_QNAME.getLocalName()); + } + + public static boolean isGetConfigOperation(final QName rpc) { + return NETCONF_URI.equals(rpc.getNamespace()) && rpc.getLocalName().equals(NETCONF_GET_CONFIG_QNAME.getLocalName()); + } + public static boolean isDataEditOperation(final QName rpc) { return NETCONF_URI.equals(rpc.getNamespace()) && rpc.getLocalName().equals(NETCONF_EDIT_CONFIG_QNAME.getLocalName()); @@ -256,6 +265,80 @@ public class NetconfMessageTransformUtil { return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); } + /** + * Creates artificial schema node for edit-config rpc. This artificial schema looks like: + *
+     * {@code
+     * rpc
+     *   get
+     *     filter
+     *         // All schema nodes from remote schema
+     *     filter
+     *   get
+     * rpc
+     * }
+     * 
+ * + * This makes the translation of rpc get request(especially the config node) + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForGet(final SchemaContext schemaContext) { + final QName filter = QName.create(NETCONF_GET_QNAME, "filter"); + final QName get = QName.create(NETCONF_GET_QNAME, "get"); + final NodeContainerProxy configProxy = new NodeContainerProxy(filter, schemaContext.getChildNodes()); + final NodeContainerProxy editConfigProxy = new NodeContainerProxy(get, Sets.newHashSet(configProxy)); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); + } + + /** + * Creates artificial schema node for get rpc. This artificial schema looks like: + *
+     * {@code
+     * rpc
+     *   get-config
+     *     filter
+     *         // All schema nodes from remote schema
+     *     filter
+     *   get-config
+     * rpc
+     * }
+     * 
+ * + * This makes the translation of rpc get-config request(especially the config node) + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForGetConfig(final SchemaContext schemaContext) { + final QName filter = QName.create(NETCONF_GET_CONFIG_QNAME, "filter"); + final QName getConfig = QName.create(NETCONF_GET_CONFIG_QNAME, "get-config"); + final NodeContainerProxy configProxy = new NodeContainerProxy(filter, schemaContext.getChildNodes()); + final NodeContainerProxy editConfigProxy = new NodeContainerProxy(getConfig, Sets.newHashSet(configProxy)); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); + } + + /** + * Creates artificial schema node for schema defined rpc. This artificial schema looks like: + *
+     * {@code
+     * rpc
+     *   rpc-name
+     *      // All schema nodes from remote schema
+     *   rpc-name
+     * rpc
+     * }
+     * 
+ * + * This makes the translation of schema defined rpc request + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForRpc(final QName rpcName, final SchemaContext schemaContext) { + Preconditions.checkNotNull(rpcName); + Preconditions.checkNotNull(schemaContext); + + final NodeContainerProxy rpcBodyProxy = new NodeContainerProxy(rpcName, schemaContext.getChildNodes()); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(rpcBodyProxy)); + + } + public static CompositeNodeTOImpl wrap(final QName name, final Node node) { if (node != null) { return new CompositeNodeTOImpl(name, null, Collections.> singletonList(node)); diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java index 521a55df68..127b0cbfcd 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java @@ -31,6 +31,7 @@ public class NetconfToNotificationTest { NetconfMessage userNotification; + @SuppressWarnings("deprecation") @Before public void setup() throws Exception { final List modelsToParse = Collections.singletonList(getClass().getResourceAsStream("/schemas/user-notification.yang")); 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 18a3b9f0ff..e744e11bc9 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 @@ -9,7 +9,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.sal.connect.netconf.schema.mapping.NetconfMessageTransformer; @@ -22,6 +22,8 @@ import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.w3c.dom.Document; + /** * Test case for reported bug 1355 @@ -32,33 +34,195 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; */ public class NetconfToRpcRequestTest { - private String TEST_MODEL_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:rpc-test"; - private String REVISION = "2014-07-14"; - private QName INPUT_QNAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "input"); - private QName STREAM_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "stream-name"); - private QName RPC_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "subscribe"); + private final static String TEST_MODEL_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:rpc-test"; + private final static String REVISION = "2014-07-14"; + private final static QName INPUT_QNAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "input"); + private final static QName STREAM_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "stream-name"); + private final static QName SUBSCRIBE_RPC_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "subscribe"); + + private final static String CONFIG_TEST_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:rpc:config:defs"; + private final static String CONFIG_TEST_REVISION = "2014-07-21"; + private final static QName EDIT_CONFIG_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "edit-config"); + private final static QName GET_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "get"); + private final static QName GET_CONFIG_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "get-config"); - NetconfMessageTransformer messageTransformer; + static SchemaContext notifCtx; + static SchemaContext cfgCtx; + static NetconfMessageTransformer messageTransformer; @SuppressWarnings("deprecation") - @Before - public void setup() throws Exception { - final List modelsToParse = Collections - .singletonList(getClass().getResourceAsStream("/schemas/rpc-notification-subscription.yang")); - final YangContextParser parser = new YangParserImpl(); - final Set modules = parser.parseYangModelsFromStreams(modelsToParse); - assertTrue(!modules.isEmpty()); - final SchemaContext schemaContext = parser.resolveSchemaContext(modules); - assertNotNull(schemaContext); + @BeforeClass + public static void setup() throws Exception { + List modelsToParse = Collections + .singletonList(NetconfToRpcRequestTest.class.getResourceAsStream("/schemas/rpc-notification-subscription.yang")); + YangContextParser parser = new YangParserImpl(); + final Set notifModules = parser.parseYangModelsFromStreams(modelsToParse); + assertTrue(!notifModules.isEmpty()); + + notifCtx = parser.resolveSchemaContext(notifModules); + assertNotNull(notifCtx); + + modelsToParse = Collections + .singletonList(NetconfToRpcRequestTest.class.getResourceAsStream("/schemas/config-test-rpc.yang")); + parser = new YangParserImpl(); + final Set configModules = parser.parseYangModelsFromStreams(modelsToParse); + cfgCtx = parser.resolveSchemaContext(configModules); + assertNotNull(cfgCtx); messageTransformer = new NetconfMessageTransformer(); - messageTransformer.onGlobalContextUpdated(schemaContext); } @Test - public void test() throws Exception { + public void testIsDataEditOperation() throws Exception { + messageTransformer.onGlobalContextUpdated(cfgCtx); + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); - rootBuilder.setQName(RPC_NAME); + rootBuilder.setQName(EDIT_CONFIG_QNAME); + + final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input")); + + final CompositeNodeBuilder targetBuilder = ImmutableCompositeNode.builder(); + targetBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "target")); + targetBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "running"), null); + + final CompositeNodeBuilder configBuilder = ImmutableCompositeNode.builder(); + configBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "config")); + + final CompositeNodeBuilder anyxmlTopBuilder = ImmutableCompositeNode.builder(); + anyxmlTopBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "top")); + + final CompositeNodeBuilder anyxmlInterfBuilder = ImmutableCompositeNode.builder(); + anyxmlInterfBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "interface")); + + anyxmlInterfBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "name"), "Ethernet0/0"); + anyxmlInterfBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "mtu"), "1500"); + + anyxmlTopBuilder.add(anyxmlInterfBuilder.toInstance()); + configBuilder.add(anyxmlTopBuilder.toInstance()); + + inputBuilder.add(targetBuilder.toInstance()); + inputBuilder.add(configBuilder.toInstance()); + + rootBuilder.add(inputBuilder.toInstance()); + final ImmutableCompositeNode root = rootBuilder.toInstance(); + + final NetconfMessage message = messageTransformer.toRpcRequest(EDIT_CONFIG_QNAME, root); + assertNotNull(message); + + final Document xmlDoc = message.getDocument(); + org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild(); + assertEquals(rpcChild.getLocalName(), "rpc"); + + final org.w3c.dom.Node editConfigNode = rpcChild.getFirstChild(); + assertEquals(editConfigNode.getLocalName(), "edit-config"); + + final org.w3c.dom.Node targetNode = editConfigNode.getFirstChild(); + assertEquals(targetNode.getLocalName(), "target"); + + final org.w3c.dom.Node runningNode = targetNode.getFirstChild(); + assertEquals(runningNode.getLocalName(), "running"); + + final org.w3c.dom.Node configNode = targetNode.getNextSibling(); + assertEquals(configNode.getLocalName(), "config"); + + final org.w3c.dom.Node topNode = configNode.getFirstChild(); + assertEquals(topNode.getLocalName(), "top"); + + final org.w3c.dom.Node interfaceNode = topNode.getFirstChild(); + assertEquals(interfaceNode.getLocalName(), "interface"); + + final org.w3c.dom.Node nameNode = interfaceNode.getFirstChild(); + assertEquals(nameNode.getLocalName(), "name"); + + final org.w3c.dom.Node mtuNode = nameNode.getNextSibling(); + assertEquals(mtuNode.getLocalName(), "mtu"); + } + + @Test + public void testIsGetOperation() throws Exception { + messageTransformer.onGlobalContextUpdated(cfgCtx); + + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); + rootBuilder.setQName(GET_QNAME); + + final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input")); + + rootBuilder.add(inputBuilder.toInstance()); + final ImmutableCompositeNode root = rootBuilder.toInstance(); + + final NetconfMessage message = messageTransformer.toRpcRequest(GET_QNAME, 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 get = rpcChild.getFirstChild(); + assertEquals(get.getLocalName(), "get"); + } + + @Test + public void testIsGetConfigOperation() throws Exception { + messageTransformer.onGlobalContextUpdated(cfgCtx); + + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); + rootBuilder.setQName(GET_CONFIG_QNAME); + + final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input")); + + final CompositeNodeBuilder sourceBuilder = ImmutableCompositeNode.builder(); + sourceBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "source")); + sourceBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "running"), null); + + final CompositeNodeBuilder anyxmlFilterBuilder = ImmutableCompositeNode.builder(); + anyxmlFilterBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "filter")); + + final CompositeNodeBuilder anyxmlTopBuilder = ImmutableCompositeNode.builder(); + anyxmlTopBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "top")); + anyxmlTopBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "users"), null); + + anyxmlFilterBuilder.add(anyxmlTopBuilder.toInstance()); + + inputBuilder.add(sourceBuilder.toInstance()); + inputBuilder.add(anyxmlFilterBuilder.toInstance()); + rootBuilder.add(inputBuilder.toInstance()); + final ImmutableCompositeNode root = rootBuilder.toInstance(); + + final NetconfMessage message = messageTransformer.toRpcRequest(GET_CONFIG_QNAME, 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 getConfig = rpcChild.getFirstChild(); + assertEquals(getConfig.getLocalName(), "get-config"); + + final org.w3c.dom.Node sourceNode = getConfig.getFirstChild(); + assertEquals(sourceNode.getLocalName(), "source"); + + final org.w3c.dom.Node runningNode = sourceNode.getFirstChild(); + assertEquals(runningNode.getLocalName(), "running"); + + final org.w3c.dom.Node filterNode = sourceNode.getNextSibling(); + assertEquals(filterNode.getLocalName(), "filter"); + + final org.w3c.dom.Node topNode = filterNode.getFirstChild(); + assertEquals(topNode.getLocalName(), "top"); + + final org.w3c.dom.Node usersNode = topNode.getFirstChild(); + assertEquals(usersNode.getLocalName(), "users"); + } + + @Test + public void testUserDefinedRpcCall() throws Exception { + messageTransformer.onGlobalContextUpdated(notifCtx); + + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); + rootBuilder.setQName(SUBSCRIBE_RPC_NAME); final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); inputBuilder.setQName(INPUT_QNAME); @@ -75,7 +239,51 @@ public class NetconfToRpcRequestTest { assertNotNull(inputNode); assertTrue(inputNode.isEmpty()); - final NetconfMessage message = messageTransformer.toRpcRequest(RPC_NAME, root); + final NetconfMessage message = messageTransformer.toRpcRequest(SUBSCRIBE_RPC_NAME, 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 subscribeName = rpcChild.getFirstChild(); + assertEquals(subscribeName.getLocalName(), "subscribe"); + + final org.w3c.dom.Node streamName = subscribeName.getFirstChild(); + 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/md-sal/sal-netconf-connector/src/test/resources/schemas/config-test-rpc.yang b/opendaylight/md-sal/sal-netconf-connector/src/test/resources/schemas/config-test-rpc.yang new file mode 100644 index 0000000000..f67c2df256 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/resources/schemas/config-test-rpc.yang @@ -0,0 +1,167 @@ +module config-test-rpc { + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:rpc:config:defs"; + prefix "rpc"; + + organization + "Cisco Systems, Inc."; + + contact + "lsedlak@cisco.com"; + + description "Test model containing hacked definition of rpc edit-config and definitions for + get and get-config rpc operations. + The rpc definition is copied from rfc 6241 Appendix C: http://tools.ietf.org/html/rfc6241#appendix-C"; + + revision 2014-07-21 { + description "Initial revision."; + } + + extension get-filter-element-attributes { + description + "If this extension is present within an 'anyxml' + statement named 'filter', which must be conceptually + defined within the RPC input section for the + and protocol operations, then the + following unqualified XML attribute is supported + within the element, within a or + protocol operation: + + type : optional attribute with allowed + value strings 'subtree' and 'xpath'. + If missing, the default value is 'subtree'. + + If the 'xpath' feature is supported, then the + following unqualified XML attribute is + also supported: + + select: optional attribute containing a + string representing an XPath expression. + The 'type' attribute must be equal to 'xpath' + if this attribute is present."; + } + + rpc edit-config { + description "The operation loads all or part of a specified + configuration to the specified target configuration."; + + reference "RFC 6241, Section 7.2"; + + input { + container target { + description "Particular configuration to edit."; + + choice config-target { + mandatory true; + description "The configuration target."; + + leaf candidate { + if-feature candidate; + type empty; + description "The candidate configuration is the config target."; + } + + leaf running { + if-feature writable-running; + type empty; + description "The running configuration is the config source."; + } + } + } + + choice edit-content { + mandatory true; + description "The content for the edit operation."; + + anyxml config { + description + "Inline Config content."; + } + + leaf url { + if-feature url; + type string; + description + "URL-based config content."; + } + } + } + } + + rpc get-config { + description + "Retrieve all or part of a specified configuration."; + + reference "RFC 6241, Section 7.1"; + + input { + container source { + description "Particular configuration to retrieve."; + + choice config-source { + mandatory true; + description + "The configuration to retrieve."; + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source. + This is optional-to-implement on the server because + not all servers will support filtering for this + datastore."; + } + } + } + + anyxml filter { + description "Subtree or XPath filter to use."; + get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the source datastore subset that matched + the filter criteria (if any). An empty data container + indicates that the request did not produce any results."; + } + } + } + + rpc get { + description "Retrieve running configuration and device state information."; + + reference "RFC 6241, Section 7.7"; + + input { + anyxml filter { + description + "This parameter specifies the portion of the system + configuration and state data to retrieve."; + get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the running datastore subset and/or state + data that matched the filter criteria (if any). + An empty data container indicates that the request did not + produce any results."; + } + } + } +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml index ce3bfe9a4c..a2bee8ffee 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml @@ -34,7 +34,10 @@ com.typesafe.akka akka-testkit_${scala.version}
- + + com.typesafe.akka + akka-osgi_${scala.version} + diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java index 9824889b80..2be8ba47b9 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java @@ -2,8 +2,10 @@ package org.opendaylight.controller.config.yang.config.remote_rpc_connector; import org.opendaylight.controller.remote.rpc.RemoteRpcProviderFactory; import org.opendaylight.controller.sal.core.api.Broker; +import org.osgi.framework.BundleContext; public class RemoteRPCBrokerModule extends org.opendaylight.controller.config.yang.config.remote_rpc_connector.AbstractRemoteRPCBrokerModule { + private BundleContext bundleContext; public RemoteRPCBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } @@ -20,6 +22,10 @@ public class RemoteRPCBrokerModule extends org.opendaylight.controller.config.ya @Override public java.lang.AutoCloseable createInstance() { Broker broker = getDomBrokerDependency(); - return RemoteRpcProviderFactory.createInstance(broker); + return RemoteRpcProviderFactory.createInstance(broker, bundleContext); + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java index 330845b14f..f97338d329 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java @@ -10,6 +10,25 @@ package org.opendaylight.controller.config.yang.config.remote_rpc_connector; +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + public class RemoteRPCBrokerModuleFactory extends org.opendaylight.controller.config.yang.config.remote_rpc_connector.AbstractRemoteRPCBrokerModuleFactory { + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + RemoteRPCBrokerModule module = (RemoteRPCBrokerModule)super.createModule(instanceName,dependencyResolver,bundleContext); + module.setBundleContext(bundleContext); + return module; + } + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, + DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + RemoteRPCBrokerModule module = (RemoteRPCBrokerModule)super.createModule(instanceName, dependencyResolver, + old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java index 4a6124a3bc..bd49b6239c 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java @@ -9,25 +9,39 @@ package org.opendaylight.controller.remote.rpc; import akka.actor.ActorSystem; -import akka.actor.Props; -import com.google.common.base.Function; +import akka.osgi.BundleDelegatingClassLoader; import com.typesafe.config.ConfigFactory; +import org.osgi.framework.BundleContext; -import javax.annotation.Nullable; public class ActorSystemFactory { - private static final ActorSystem actorSystem = (new Function(){ + private static volatile ActorSystem actorSystem = null; - @Nullable @Override public ActorSystem apply(@Nullable Void aVoid) { - ActorSystem system = - ActorSystem.create("opendaylight-rpc", ConfigFactory - .load().getConfig("odl-cluster")); - system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor"); - return system; - } - }).apply(null); + public static final ActorSystem getInstance(){ + return actorSystem; + } + + /** + * This method should be called only once during initialization + * + * @param bundleContext + */ + public static final void createInstance(final BundleContext bundleContext) { - public static final ActorSystem getInstance(){ - return actorSystem; + if(actorSystem == null) { + // Create an OSGi bundle classloader for actor system + BundleDelegatingClassLoader classLoader = new BundleDelegatingClassLoader(bundleContext.getBundle(), + Thread.currentThread().getContextClassLoader()); + synchronized (ActorSystemFactory.class) { + // Double check + if (actorSystem == null) { + ActorSystem system = ActorSystem.create("opendaylight-rpc", + ConfigFactory.load().getConfig("odl-cluster"), classLoader); + actorSystem = system; + } + } + } else { + throw new IllegalStateException("Actor system should be created only once. Use getInstance method to access existing actor system"); } + } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java index 4c40ca1777..fc75f7747a 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java @@ -11,9 +11,12 @@ package org.opendaylight.controller.remote.rpc; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.osgi.framework.BundleContext; public class RemoteRpcProviderFactory { - public static RemoteRpcProvider createInstance(final Broker broker){ + public static RemoteRpcProvider createInstance(final Broker broker, final BundleContext bundleContext){ + + ActorSystemFactory.createInstance(bundleContext); RemoteRpcProvider rpcProvider = new RemoteRpcProvider(ActorSystemFactory.getInstance(), (RpcProvisionRegistry) broker); broker.registerProvider(rpcProvider); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java index 49ba843071..b4cca1ab48 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java @@ -185,7 +185,8 @@ public class XmlDocumentUtils { value = codec.deserialize(text); } - if (schema.getType() instanceof InstanceIdentifierType) { + final TypeDefinition baseType = XmlUtils.resolveBaseTypeFrom(schema.getType()); + if (baseType instanceof InstanceIdentifierType) { logger.debug("toSimpleNodeWithType: base type of node is instance identifier, deserializing element", xmlElement); value = InstanceIdentifierForXmlCodec.deserialize(xmlElement,schemaCtx); }