Merge "Fix failing IT tests"
authorTony Tkacik <ttkacik@cisco.com>
Tue, 5 Aug 2014 15:18:02 +0000 (15:18 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 5 Aug 2014 15:18:02 +0000 (15:18 +0000)
13 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/distribution/opendaylight/pom.xml
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java
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/NetconfToNotificationTest.java
opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java
opendaylight/md-sal/sal-netconf-connector/src/test/resources/schemas/config-test-rpc.yang [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java

index a7bbbe772d8514c150ec2a92de4acd3cdbca00d9..ff8735a518cff77569d1300cf451ea9f345ce12c 100644 (file)
         <artifactId>akka-testkit_${scala.version}</artifactId>
         <version>${akka.version}</version>
       </dependency>
+        <dependency>
+            <groupId>com.typesafe.akka</groupId>
+            <artifactId>akka-osgi_${scala.version}</artifactId>
+            <version>${akka.version}</version>
+        </dependency>
       <dependency>
         <groupId>commons-codec</groupId>
         <artifactId>commons-codec</artifactId>
         <version>${mdsal.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-remoterpc-connector</artifactId>
+        <version>${mdsal.version}</version>
+      </dependency>
+
+
       <!-- SAL Extension bundles -->
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
index e4468b6f2735f4c7189ccf236fc48b5d8384e0e6..f8796e0ae4468093bde4cb91a88174335bc3a434 100644 (file)
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>sal-restconf-broker</artifactId>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-remoterpc-connector</artifactId>
+        </dependency>
+
 
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
index 80d0f67ac49c72b47d35e6ca094ec4610099c1b1..47ef9039d1ac6f69065b1be2d8bd45b5115422a4 100644 (file)
@@ -70,10 +70,15 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
                 if (NetconfMessageTransformUtil.isDataEditOperation(rpc)) {
                     final DataNodeContainer schemaForEdit = NetconfMessageTransformUtil.createSchemaForEdit(schemaContext.get());
                     w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, schemaForEdit, codecProvider);
+                } else if (NetconfMessageTransformUtil.isGetOperation(rpc)) {
+                    final DataNodeContainer schemaForGet = NetconfMessageTransformUtil.createSchemaForGet(schemaContext.get());
+                    w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, schemaForGet, codecProvider);
+                } else if (NetconfMessageTransformUtil.isGetConfigOperation(rpc)) {
+                    final DataNodeContainer schemaForGetConfig = NetconfMessageTransformUtil.createSchemaForGetConfig(schemaContext.get());
+                    w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, schemaForGetConfig, codecProvider);
                 } else {
-                    // FIXME get and get-config needs schema as well to transform filter using schema context
-                    // e.g. Identityref nodes in filter fail to serialize properly to xml without schema
-                    w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, schemaContext.get(), codecProvider);
+                    final DataNodeContainer schemaForGetConfig = NetconfMessageTransformUtil.createSchemaForRpc(rpc, schemaContext.get());
+                    w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, schemaForGetConfig, codecProvider);
                 }
             } else {
                 w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, codecProvider);
@@ -97,24 +102,23 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
 
     private static RpcResult<CompositeNode> 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<org.opendaylight.yangtools.yang.data.api.Node<?>> dataNodes = XmlDocumentUtils.toDomNodes(xmlData,
                     Optional.of(context.getDataDefinitions()), context);
 
             final CompositeNodeBuilder<ImmutableCompositeNode> 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();
     }
 
index d3faddd471d0533c221b00cbe867a8b9d6431a12..4f792a0a7169b00c72672d182393bd011ad1ca74 100644 (file)
@@ -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.<DataSchemaNode>newHashSet(editConfigProxy));
     }
 
+    /**
+     * Creates artificial schema node for edit-config rpc. This artificial schema looks like:
+     * <pre>
+     * {@code
+     * rpc
+     *   get
+     *     filter
+     *         // All schema nodes from remote schema
+     *     filter
+     *   get
+     * rpc
+     * }
+     * </pre>
+     *
+     * 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.<DataSchemaNode>newHashSet(configProxy));
+        return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.<DataSchemaNode>newHashSet(editConfigProxy));
+    }
+
+    /**
+     * Creates artificial schema node for get rpc. This artificial schema looks like:
+     * <pre>
+     * {@code
+     * rpc
+     *   get-config
+     *     filter
+     *         // All schema nodes from remote schema
+     *     filter
+     *   get-config
+     * rpc
+     * }
+     * </pre>
+     *
+     * 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.<DataSchemaNode>newHashSet(configProxy));
+        return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.<DataSchemaNode>newHashSet(editConfigProxy));
+    }
+
+    /**
+     * Creates artificial schema node for schema defined rpc. This artificial schema looks like:
+     * <pre>
+     * {@code
+     * rpc
+     *   rpc-name
+     *      // All schema nodes from remote schema
+     *   rpc-name
+     * rpc
+     * }
+     * </pre>
+     *
+     * 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.<DataSchemaNode>newHashSet(rpcBodyProxy));
+
+    }
+
     public static CompositeNodeTOImpl wrap(final QName name, final Node<?> node) {
         if (node != null) {
             return new CompositeNodeTOImpl(name, null, Collections.<Node<?>> singletonList(node));
index 521a55df682340cfacdcf4e11513641ce64c0107..127b0cbfcdd510f569af8b1d71d0e773d9e1f740 100644 (file)
@@ -31,6 +31,7 @@ public class NetconfToNotificationTest {
 
     NetconfMessage userNotification;
 
+    @SuppressWarnings("deprecation")
     @Before
     public void setup() throws Exception {
         final List<InputStream> modelsToParse = Collections.singletonList(getClass().getResourceAsStream("/schemas/user-notification.yang"));
index 18a3b9f0ff65d9055daf13d6f7e70f01653de6ea..e744e11bc9212fc58666654b454a804e1e7f06ce 100644 (file)
@@ -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<InputStream> modelsToParse = Collections
-            .singletonList(getClass().getResourceAsStream("/schemas/rpc-notification-subscription.yang"));
-        final YangContextParser parser = new YangParserImpl();
-        final Set<Module> modules = parser.parseYangModelsFromStreams(modelsToParse);
-        assertTrue(!modules.isEmpty());
-        final SchemaContext schemaContext = parser.resolveSchemaContext(modules);
-        assertNotNull(schemaContext);
+    @BeforeClass
+    public static void setup() throws Exception {
+        List<InputStream> modelsToParse = Collections
+            .singletonList(NetconfToRpcRequestTest.class.getResourceAsStream("/schemas/rpc-notification-subscription.yang"));
+        YangContextParser parser = new YangParserImpl();
+        final Set<Module> 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<Module> 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<ImmutableCompositeNode> rootBuilder = ImmutableCompositeNode.builder();
-        rootBuilder.setQName(RPC_NAME);
+        rootBuilder.setQName(EDIT_CONFIG_QNAME);
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> inputBuilder = ImmutableCompositeNode.builder();
+        inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input"));
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> 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<ImmutableCompositeNode> configBuilder = ImmutableCompositeNode.builder();
+        configBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "config"));
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> anyxmlTopBuilder = ImmutableCompositeNode.builder();
+        anyxmlTopBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "top"));
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> 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<ImmutableCompositeNode> rootBuilder = ImmutableCompositeNode.builder();
+        rootBuilder.setQName(GET_QNAME);
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> 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<ImmutableCompositeNode> rootBuilder = ImmutableCompositeNode.builder();
+        rootBuilder.setQName(GET_CONFIG_QNAME);
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> inputBuilder = ImmutableCompositeNode.builder();
+        inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input"));
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> 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<ImmutableCompositeNode> anyxmlFilterBuilder = ImmutableCompositeNode.builder();
+        anyxmlFilterBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "filter"));
+
+        final CompositeNodeBuilder<ImmutableCompositeNode> 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<ImmutableCompositeNode> rootBuilder = ImmutableCompositeNode.builder();
+        rootBuilder.setQName(SUBSCRIBE_RPC_NAME);
 
         final CompositeNodeBuilder<ImmutableCompositeNode> 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<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");
     }
 }
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 (file)
index 0000000..f67c2df
--- /dev/null
@@ -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 <get>
+             and <get-config> protocol operations, then the
+             following unqualified XML attribute is supported
+             within the <filter> element, within a <get> or
+             <get-config> 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 <edit-config> 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.";
+            }
+        }
+    }
+}
index ce3bfe9a4c81a65decaf51625c7505c07cafc05e..a2bee8ffee7295c8c086365fafa1651235f4efdc 100644 (file)
       <groupId>com.typesafe.akka</groupId>
       <artifactId>akka-testkit_${scala.version}</artifactId>
     </dependency>
-
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-osgi_${scala.version}</artifactId>
+    </dependency>
     <!-- SAL Dependencies -->
 
     <dependency>
index 9824889b8023d4e31e20d835731c59ef7047c314..2be8ba47b99f9881304f58eeee3dede71497821c 100644 (file)
@@ -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;
   }
 }
index 330845b14fc28bedbc9268467a2fa5075addc5a4..f97338d32971c277de5f258c15c94102f94120a6 100644 (file)
 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;
+  }
 }
index 4a6124a3bc37fbf2a46079dd82df6f1d3ba80283..bd49b6239c443ccd04f70da3dabd964da00c504f 100644 (file)
@@ -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<Void, ActorSystem>(){
+ 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");
     }
+  }
 }
index 4c40ca177756877f121f0c5187b747241342655c..fc75f7747a0d25361c96f96e77aac30538bb05a5 100644 (file)
@@ -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);
index 49ba84307109e650b07e25420506e73bbae57842..b4cca1ab485c3e99373dfd731166c6615e3903d3 100644 (file)
@@ -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);
     }