X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=docs%2Fdev-guide.rst;h=7d12d7a9a722629149c4973d8a132cce44264e9b;hb=16bcd8d75886f4d9d8ad4e6833147aa516358adf;hp=58e3b0df680d34358e90636e2137cae56c1a9b01;hpb=6c8865b7937fd5a301d9066e4bf938129eec1fbe;p=controller.git diff --git a/docs/dev-guide.rst b/docs/dev-guide.rst index 58e3b0df68..7d12d7a9a7 100644 --- a/docs/dev-guide.rst +++ b/docs/dev-guide.rst @@ -1370,314 +1370,6 @@ Something practical Status: 200 OK -Websocket change event notification subscription tutorial ---------------------------------------------------------- - -Subscribing to data change notifications makes it possible to obtain -notifications about data manipulation (insert, change, delete) which are -done on any specified **path** of any specified **datastore** with -specific **scope**. In following examples *{odlAddress}* is address of -server where ODL is running and *{odlPort}* is port on which -OpenDaylight is running. - -Websocket notifications subscription process -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In this section we will learn what steps need to be taken in order to -successfully subscribe to data change event notifications. - -Create stream -^^^^^^^^^^^^^ - -In order to use event notifications you first need to call RPC that -creates notification stream that you can later listen to. You need to -provide three parameters to this RPC: - -- **path**: data store path that you plan to listen to. You can - register listener on containers, lists and leaves. - -- **datastore**: data store type. *OPERATIONAL* or *CONFIGURATION*. - -- **scope**: Represents scope of data change. Possible options are: - - - BASE: only changes directly to the data tree node specified in the - path will be reported - - - ONE: changes to the node and to direct child nodes will be - reported - - - SUBTREE: changes anywhere in the subtree starting at the node will - be reported - -The RPC to create the stream can be invoked via RESTCONF like this: - -- URI: - http://{odlAddress}:{odlPort}/restconf/operations/sal-remote:create-data-change-event-subscription - -- HEADER: Content-Type=application/json - -- OPERATION: POST - -- DATA: - - .. code:: json - - { - "input": { - "path": "/toaster:toaster/toaster:toasterStatus", - "sal-remote-augment:datastore": "OPERATIONAL", - "sal-remote-augment:scope": "ONE" - } - } - -The response should look something like this: - -.. code:: json - - { - "output": { - "stream-name": "data-change-event-subscription/toaster:toaster/toaster:toasterStatus/datastore=CONFIGURATION/scope=SUBTREE" - } - } - -**stream-name** is important because you will need to use it when you -subscribe to the stream in the next step. - -.. note:: - - Internally, this will create a new listener for *stream-name* if it - did not already exist. - -Subscribe to stream -^^^^^^^^^^^^^^^^^^^ - -In order to subscribe to stream and obtain WebSocket location you need -to call *GET* on your stream path. The URI should generally be -http://{odlAddress}:{odlPort}/restconf/streams/stream/{streamName}, -where *{streamName}* is the *stream-name* parameter contained in -response from *create-data-change-event-subscription* RPC from the -previous step. - -- URI: - http://{odlAddress}:{odlPort}/restconf/streams/stream/data-change-event-subscription/toaster:toaster/datastore=CONFIGURATION/scope=SUBTREE - -- OPERATION: GET - -The subscription call may be modified with the following query parameters defined in the RESTCONF RFC: - -- `filter `__ - -- `start-time `__ - -- `end-time `__ - -In addition, the following ODL extension query parameter is supported: - -:odl-leaf-nodes-only: - If this parameter is set to "true", create and update notifications will only - contain the leaf nodes modified instead of the entire subscription subtree. - This can help in reducing the size of the notifications. - -The expected response status is 200 OK and response body should be -empty. You will get your WebSocket location from **Location** header of -response. For example in our particular toaster example location header -would have this value: -*ws://{odlAddress}:8185/toaster:toaster/datastore=CONFIGURATION/scope=SUBTREE* - -.. note:: - - During this phase there is an internal check for to see if a - listener for the *stream-name* from the URI exists. If not, new a - new listener is registered with the DOM data broker. - -Receive notifications -^^^^^^^^^^^^^^^^^^^^^ - -You should now have a data change notification stream created and have -location of a WebSocket. You can use this WebSocket to listen to data -change notifications. To listen to notifications you can use a -JavaScript client or if you are using chrome browser you can use the -`Simple WebSocket -Client `__. - -Also, for testing purposes, there is simple Java application named -WebSocketClient. The application is placed in the -*-sal-rest-connector-classes.class* project. It accepts a WebSocket URI -as and input parameter. After starting the utility (WebSocketClient -class directly in Eclipse/InteliJ Idea) received notifications should be -displayed in console. - -Notifications are always in XML format and look like this: - -.. code:: xml - - - 2014-09-11T09:58:23+02:00 - - - /meae:toaster - updated - - - - - - - -Example use case -~~~~~~~~~~~~~~~~ - -The typical use case is listening to data change events to update web -page data in real-time. In this tutorial we will be using toaster as the -base. - -When you call *make-toast* RPC, it sets *toasterStatus* to "down" to -reflect that the toaster is busy making toast. When it finishes, -*toasterStatus* is set to "up" again. We will listen to this toaster -status changes in data store and will reflect it on our web page in -real-time thanks to WebSocket data change notification. - -Simple javascript client implementation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We will create simple JavaScript web application that will listen -updates on *toasterStatus* leaf and update some element of our web page -according to new toaster status state. - -Create stream -^^^^^^^^^^^^^ - -First you need to create stream that you are planing to subscribe to. -This can be achieved by invoking "create-data-change-event-subscription" -RPC on RESTCONF via AJAX request. You need to provide data store -**path** that you plan to listen on, **data store type** and **scope**. -If the request is successful you can extract the **stream-name** from -the response and use that to subscribe to the newly created stream. The -*{username}* and *{password}* fields represent your credentials that you -use to connect to OpenDaylight via RESTCONF: - -.. note:: - - The default user name and password are "admin". - -.. code:: javascript - - function createStream() { - $.ajax( - { - url: 'http://{odlAddress}:{odlPort}/restconf/operations/sal-remote:create-data-change-event-subscription', - type: 'POST', - headers: { - 'Authorization': 'Basic ' + btoa('{username}:{password}'), - 'Content-Type': 'application/json' - }, - data: JSON.stringify( - { - 'input': { - 'path': '/toaster:toaster/toaster:toasterStatus', - 'sal-remote-augment:datastore': 'OPERATIONAL', - 'sal-remote-augment:scope': 'ONE' - } - } - ) - }).done(function (data) { - // this function will be called when ajax call is executed successfully - subscribeToStream(data.output['stream-name']); - }).fail(function (data) { - // this function will be called when ajax call fails - console.log("Create stream call unsuccessful"); - }) - } - -Subscribe to stream -^^^^^^^^^^^^^^^^^^^ - -The Next step is to subscribe to the stream. To subscribe to the stream -you need to call *GET* on -*http://{odlAddress}:{odlPort}/restconf/streams/stream/{stream-name}*. -If the call is successful, you get WebSocket address for this stream in -**Location** parameter inside response header. You can get response -header by calling *getResponseHeader(\ *Location*)* on HttpRequest -object inside *done()* function call: - -.. code:: javascript - - function subscribeToStream(streamName) { - $.ajax( - { - url: 'http://{odlAddress}:{odlPort}/restconf/streams/stream/' + streamName; - type: 'GET', - headers: { - 'Authorization': 'Basic ' + btoa('{username}:{password}'), - } - } - ).done(function (data, textStatus, httpReq) { - // we need function that has http request object parameter in order to access response headers. - listenToNotifications(httpReq.getResponseHeader('Location')); - }).fail(function (data) { - console.log("Subscribe to stream call unsuccessful"); - }); - } - -Receive notifications -^^^^^^^^^^^^^^^^^^^^^ - -Once you got WebSocket server location you can now connect to it and -start receiving data change events. You need to define functions that -will handle events on WebSocket. In order to process incoming events -from OpenDaylight you need to provide a function that will handle -*onmessage* events. The function must have one parameter that represents -the received event object. The event data will be stored in -*event.data*. The data will be in an XML format that you can then easily -parse using jQuery. - -.. code:: javascript - - function listenToNotifications(socketLocation) { - try { - var notificatinSocket = new WebSocket(socketLocation); - - notificatinSocket.onmessage = function (event) { - // we process our received event here - console.log('Received toaster data change event.'); - $($.parseXML(event.data)).find('data-change-event').each( - function (index) { - var operation = $(this).find('operation').text(); - if (operation == 'updated') { - // toaster status was updated so we call function that gets the value of toasterStatus leaf - updateToasterStatus(); - return false; - } - } - ); - } - notificatinSocket.onerror = function (error) { - console.log("Socket error: " + error); - } - notificatinSocket.onopen = function (event) { - console.log("Socket connection opened."); - } - notificatinSocket.onclose = function (event) { - console.log("Socket connection closed."); - } - // if there is a problem on socket creation we get exception (i.e. when socket address is incorrect) - } catch(e) { - alert("Error when creating WebSocket" + e ); - } - } - -The *updateToasterStatus()* function represents function that calls -*GET* on the path that was modified and sets toaster status in some web -page element according to received data. After the WebSocket connection -has been established you can test events by calling make-toast RPC via -RESTCONF. - -.. note:: - - for more information about WebSockets in JavaScript visit `Writing - WebSocket client - applications `__ - .. _config_subsystem: Config Subsystem