Bug 453 - sal-rest-connector doesn't provide stream discovery feature 62/5562/5
authorMartin Bobak <mbobak@cisco.com>
Mon, 3 Mar 2014 15:46:11 +0000 (16:46 +0100)
committerMartin Bobak <mbobak@cisco.com>
Fri, 7 Mar 2014 14:26:32 +0000 (15:26 +0100)
Change-Id: I01f21b5b27512f9a8a4babac9148eacf6e6ac36a
Signed-off-by: Martin Bobak <mbobak@cisco.com>
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java

index 0683c45ebc82b7997a02cdbbceb90658a391fe5b..067b7d96ec8c94f0af3bef597621c1c7d62586f7 100644 (file)
@@ -141,4 +141,11 @@ public interface RestconfService {
     @Path("/streams/stream/{identifier:.+}")
     public Response subscribeToStream(@Encoded @PathParam("identifier") String identifier, @Context UriInfo uriInfo);
 
+    @GET
+    @Path("/streams")
+    @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+            MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+    public StructuredData getAvailableStreams();
+
+
 }
index e09dc7ac017d143c65f45564beeb1783ed97a8be..8ebf28f35f1771ec778fc6e1a5b16088f6aafe16 100644 (file)
@@ -60,6 +60,8 @@ class RestconfImpl implements RestconfService {
     val static RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE = "restconf"
     val static RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE = "modules"
     val static RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE = "module"
+    val static RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE = "streams"
+    val static RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE = "stream"
     val static RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE = "operations"
     val static SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
     val static SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription"
@@ -92,6 +94,17 @@ class RestconfImpl implements RestconfService {
         return new StructuredData(modulesNode, modulesSchemaNode, null)
     }
 
+    override getAvailableStreams(){
+        var Set<String> availableStreams = Notificator.getStreamNames();
+        val List<Node<?>> streamsAsData = new ArrayList
+        val streamSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE)
+        for (String streamName:availableStreams){
+            streamsAsData.add(streamName.toStreamCompositeNode(streamSchemaNode))
+        }
+        val streamsSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE)
+        val streamsNode = NodeFactory.createImmutableCompositeNode(streamsSchemaNode.QName, null, streamsAsData)
+        return new StructuredData(streamsNode, streamsSchemaNode, null)
+    }
     override getModules(String identifier) {
         var Set<Module> modules = null
         var MountInstance mountPoint = null
@@ -196,6 +209,25 @@ class RestconfImpl implements RestconfService {
         }
     }
 
+    private def CompositeNode toStreamCompositeNode(String streamName, DataSchemaNode streamSchemaNode) {
+        val List<Node<?>> streamNodeValues = new ArrayList
+        val nameSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("name").head
+        streamNodeValues.add(NodeFactory.createImmutableSimpleNode(nameSchemaNode.QName, null, streamName))
+
+        val descriptionSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("description").head
+        streamNodeValues.add(NodeFactory.createImmutableSimpleNode(descriptionSchemaNode.QName, null, "DESCRIPTION_PLACEHOLDER"))
+
+        val replaySupportSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("replay-support").head
+        streamNodeValues.add(NodeFactory.createImmutableSimpleNode(replaySupportSchemaNode.QName, null, true))
+
+        val replayLogCreationTimeSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("replay-log-creation-time").head
+        streamNodeValues.add(NodeFactory.createImmutableSimpleNode(replayLogCreationTimeSchemaNode.QName, null, ""))
+
+        val eventsSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("events").head
+        streamNodeValues.add(NodeFactory.createImmutableSimpleNode(eventsSchemaNode.QName, null, ""))
+
+        return NodeFactory.createImmutableCompositeNode(streamSchemaNode.QName, null, streamNodeValues)
+    }
     private def CompositeNode toModuleCompositeNode(Module module, DataSchemaNode moduleSchemaNode) {
         val List<Node<?>> moduleNodeValues = new ArrayList
         val nameSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("name").head
@@ -216,7 +248,12 @@ class RestconfImpl implements RestconfService {
         val restconfContainer = restconfGrouping.findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE).head
         if (schemaNodeName == RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE) {
             return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE).head
-        } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) {
+        } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE) {
+           return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE).head
+        } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE) {
+           val modules = (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE).head
+           return (modules as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE).head
+        }else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) {
             return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
         } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) {
             val modules = (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
index 36c9c67ffcd3281db279c858176291f4da571ef7..9c8351aa99fdecc737508a7b0487c95f39582495 100644 (file)
@@ -1,6 +1,7 @@
 package org.opendaylight.controller.sal.streams.listeners;
 
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -12,13 +13,21 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
  */
 public class Notificator {
 
-       private static Map<String, ListenerAdapter> listenersByStreamName = new ConcurrentHashMap<>();
+    private static Map<String, ListenerAdapter> listenersByStreamName = new ConcurrentHashMap<>();
        private static Map<InstanceIdentifier, ListenerAdapter> listenersByInstanceIdentifier = new ConcurrentHashMap<>();
        private static final Lock lock = new ReentrantLock();
 
        private Notificator() {
        }
 
+    /**
+     * Returns list of all stream names
+     */
+    public static Set<String> getStreamNames() {
+        return listenersByStreamName.keySet();
+    }
+
+
        /**
         * Gets {@link ListenerAdapter} specified by stream name.
         * 
@@ -132,7 +141,7 @@ public class Notificator {
        }
 
        /**
-        * Checks if listener has at least one subscriber. In case it has any, delete
+        * Checks if listener has at least one subscriber. In case it doesn't have any, delete
         * listener.
         * 
         * @param listener
index 6f507f96e27faf82550e4bc92a842528b888c5c0..dff9d65db3f043b3b264ad50bb83687dbb9bba10 100644 (file)
@@ -7,12 +7,6 @@
  */
 package org.opendaylight.controller.sal.restconf.impl.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 import java.io.FileNotFoundException;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
@@ -21,11 +15,9 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.BeforeClass;
@@ -45,6 +37,12 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class RestGetOperationTest extends JerseyTest {
 
@@ -164,6 +162,23 @@ public class RestGetOperationTest extends JerseyTest {
         response = target(uri).request("application/yang.api+xml").get();
         validateModulesResponseXml(response);
     }
+    // /streams/
+    @Test
+    public void getStreamsTest() throws UnsupportedEncodingException, FileNotFoundException {
+        ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
+
+        String uri = "/streams";
+
+        Response response = target(uri).request("application/yang.api+json").get();
+        String responseBody = response.readEntity(String.class);
+        assertNotNull(responseBody);
+        assertTrue(responseBody.contains("streams"));
+
+        response = target(uri).request("application/yang.api+xml").get();
+        responseBody = response.readEntity(String.class);
+        assertNotNull(responseBody);
+        assertTrue(responseBody.contains("<streams xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"/>"));
+    }
 
     // /modules/module
     @Test
index 359b68dc4c7dd000bcf0cefc385f69e714f80215..b681653d6b1a48b7020ac72d8960c86c07463ad0 100644 (file)
@@ -7,15 +7,8 @@
  */
 package org.opendaylight.controller.sal.restconf.impl.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 import java.io.FileNotFoundException;
 import java.util.Set;
-
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
@@ -26,6 +19,11 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class RestconfImplTest {