Results 1 to 5 of 5
  1. #1
    Member
    Join Date
    Jan 2007
    Location
    Boston
    Posts
    1

    Request-Response APIs

    Does Lightstreamer have any Request-Response APIs? We want to query the data-provider via the lightstream server for some information such as profiles/ portfolios etc. before setting up to recieve streaming data; the sendMessage API seems to only return true or false.

  2. #2
    Power Member
    Join Date
    Jul 2006
    Location
    Cesano Maderno, Italy
    Posts
    784
    Hi,

    Lightstreamer’s paradigm and architecture is specialized for Publish/Subscribe, rather than Request/Response, because it is usually added to an existing application (web-based or thick) that already has an application server that delivers the “pulled” data.
    That said, it is possible to use Lightstreamer in a Request/Response fashion through one of the following techniques:
    1#
    - subscribe to specific items (e.g. profiles, portfolios) [= Request]
    - receive the data snapshot [= Response]
    - unsubscribe to that item after the snapshot has been received
    The Data Adapter will have to retrieve the right data according to the item names (or more precisely
    group names).

    2#
    - subscribe an user-related item
    - send requests through sendMessage
    [= Request]
    - receive response on the streaming connection [= Response]
    The MetaData Adapter receives messages via notifyUserMessage and communicates with the Data Adapter to send the right response back.


  3. #3
    Administrator
    Join Date
    Jul 2006
    Location
    Milan, Italy
    Posts
    521
    Due to the growing popularity of that feature request, we are thinking about adding a ready-made Request/Response mechanism in a future version of Lightstreamer.
    In the meanhwile, the two options outlined by Mone work great.

  4. #4
    Power Member
    Join Date
    Jul 2006
    Location
    Cesano Maderno, Italy
    Posts
    784

    Post Request-Response "hack" #1

    Quote Originally Posted by Mone
    1#
    - subscribe to specific items (e.g. profiles, portfolios) [= Request]
    - receive the data snapshot [= Response]
    - unsubscribe to that item after the snapshot has been received
    The Data Adapter will have to retrieve the right data according to the item names (or more precisely
    group names).
    I want to expand on this topic through a simple example.
    We will see a DataAdapter that responds to our requests with a list of 5 elements. Each element of the list has 2 fields, "key" that contains the name of the subscribed item plus a progressive and value that contains the string "Value" plus the same progressive.

    First of all we compose the adapters.xml file for the adapter. We will use the LiteralBasedProvider as MetaDataProvider and our custom class FakeSubAdapter as DataProvider.
    Moreover we configure the LiterBasedProvider with some parameters:
    • distinct_snapshot_length - is the maximum number of snapshot events available for each item of the adapter. This is the value returned by the getDistinctSnapshotLength method; implementing your own MetaDataProvider this value could be different per each item.
    • item_family_1 - is used as a Pattern to group items inside a family. Using .* we group in the same family all possible items.
    • modes_for_item_family_1 - lists the admitted subscription modes for items pertaining to item_family_1. We admit only DISTINCT subscriptions.
    This is the adapters.xml file
    Code xml:
    1. <?xml version="1.0"?>
    2.  
    3. <adapters_conf id="FAKESUB">
    4.     <metadata_provider>
    5.         <adapter_class>com.lightstreamer.adapters.metadata.LiteralBasedProvider</adapter_class>
    6.         <param name="distinct_snapshot_length">5</param>
    7.         <param name="item_family_1">.*</param>
    8.         <param name="modes_for_item_family_1">DISTINCT</param>
    9.     </metadata_provider>
    10.  
    11.     <data_provider>
    12.         <adapter_class>com.lightstreamer.req_resp_examples.fake_sub.FakeSubAdapter</adapter_class>
    13.     </data_provider>
    14. </adapters_conf>

    This is the DataProvider implementation (refer to comments inside the code for the explanations on how it works):
    Code java:
    1. package com.lightstreamer.req_resp_examples.fake_sub;
    2.  
    3. import java.io.File;
    4. import java.util.HashMap;
    5. import java.util.Map;
    6.  
    7. import com.lightstreamer.interfaces.data.DataProvider;
    8. import com.lightstreamer.interfaces.data.DataProviderException;
    9. import com.lightstreamer.interfaces.data.FailureException;
    10. import com.lightstreamer.interfaces.data.ItemEventListener;
    11. import com.lightstreamer.interfaces.data.SubscriptionException;
    12.  
    13. public class FakeSubAdapter implements DataProvider {
    14.  
    15.     private HashMap responseThreads = new HashMap();
    16.     private ItemEventListener listener;
    17.    
    18.     public void init(Map params, File configDir) throws DataProviderException {
    19.         return;
    20.     }
    21.  
    22.     public void setListener(ItemEventListener listener) {
    23.         //set the listener that will receive the updates
    24.         this.listener = listener;
    25.     }
    26.  
    27.     public void subscribe(String itemName, boolean needsIterator) throws SubscriptionException, FailureException {
    28.         //create the thread that will handle the response. In a production
    29.         //scenario you would probably use a pool, but for this example
    30.         //create a new thread per each subscription is enough
    31.         ResponseThread rt = new ResponseThread(itemName);
    32.         //take trace of each subscribtion-related thread
    33.         responseThreads.put(itemName,rt);
    34.         //starts the thread that will send the response to clients
    35.         rt.start();
    36.     }
    37.  
    38.     public void unsubscribe(String itemName) throws SubscriptionException, FailureException {
    39.         ResponseThread rt = (ResponseThread) responseThreads.get(itemName);
    40.         if (rt != null) {
    41.             //remove from subscription-related threads list
    42.             responseThreads.remove(itemName);
    43.             //if the thread is sending something (ie it has not finished to send the snapshot
    44.             //that is our response) we stop it
    45.             rt.end();
    46.         }
    47.     }
    48.  
    49.     public boolean isSnapshotAvailable(String itemName) throws SubscriptionException {
    50.         //in this case we send ONLY the snapshot, so it is obviously always available
    51.         return true;
    52.     }
    53.  
    54.     public class ResponseThread extends Thread {
    55.        
    56.         private String itemName;
    57.         private volatile boolean exit = false;
    58.    
    59.        
    60.         public ResponseThread(String itemName) {
    61.             //save the itemName, we will use this name as part of the
    62.             //updates
    63.             this.itemName = itemName;
    64.         }
    65.  
    66.         public void run() {
    67.             //the response will be a DISTINCT table with 5 rows
    68.             for(int i=1; i<=5 && !this.exit; i++) {
    69.                 //compose a Map to be passed to Lightstreamer kernel
    70.                 HashMap row = new HashMap();
    71.                 row.put("key",this.itemName + "->" +String.valueOf(i));
    72.                 row.put("value","Value"+i);
    73.                 //pass the map to Lightstreamer kernel. This is an update.
    74.                 if (!this.exit)listener.update(this.itemName,row,true);
    75.             }
    76.             //send the endOfSnapshot signal (ie response is finished)
    77.             if (!this.exit)listener.endOfSnapshot(this.itemName);
    78.         }
    79.        
    80.         public void end() {
    81.             //set a flag to stop updates
    82.             this.exit = true;
    83.         }
    84.        
    85.     }
    86.    
    87. }

    To be continued...

  5. #5
    Power Member
    Join Date
    Jul 2006
    Location
    Cesano Maderno, Italy
    Posts
    784

    Post Request-Response "hack" #1

    ...continue

    Now we need a client to test it, we implement a simple client with the web SDK.
    In this page we put a <div> that is filled with the "response" and a "response is complete" message. There is also a form, fill the input field and press submit to make a request to the server. NOTE that since LiteralBasedProvider is used as MetaDataProvider, and since the demo uses the string inside the inputField as a group string, if you try to send a reuqest like "something somethingElse" you subscribe 2 items (in this case 2 "requests").
    The page is made to be deployed under Lightstreamer internal web server so domain host and port are set to null.
    To gather the desired data we use a NonVisualTable. Refer to the comments inside the code for further explanations

    Code html:
    1. <html>
    2. <head>
    3.     <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">    
    4.     <!-- inclusion of Lightstreamer web client library-->
    5.     <script src="/LS/lscommons.js"></script>
    6.     <script src="/LS/lspushpage.js"></script>
    7. </head>
    8.  
    9. <body>
    10.     <!--this div will show the response-->
    11.     <div id="response"></div>        
    12.  
    13.     <!--this form is used to call a method that makes the requests-->
    14.     <form onsubmit="makeRequest();return false;">
    15.         <input id="requestQuery" type="text" />
    16.         <input type="submit" value="send request" />
    17.     </form>
    18. <script>
    19.  
    20.    
    21. /////////////////PushPage Configuration
    22.     lsPage = new PushPage();
    23.    
    24.     lsPage.context.setDomain(null);
    25.    
    26.     lsPage.onEngineReady = function(lsEngine) {
    27.                 lsEngine.connection.setLSHost(null);
    28.                 lsEngine.connection.setLSPort(null);
    29.                 lsEngine.connection.setAdapterName("FAKESUB");
    30.                 lsEngine.changeStatus("STREAMING");
    31.             }
    32.    
    33.     lsPage.bind();
    34.     lsPage.loadEngineMinimal("/LS/lsengine.html");
    35.    
    36. /////////////////////////////////Request/Response handler    
    37.     var responseDiv = document.getElementById("response");
    38.     var requestQuery = document.getElementById("requestQuery");
    39.  
    40.     function makeRequest() {
    41.         //this is the string of the input field
    42.         var request = requestQuery.value;
    43.         //create a NonVisualTable, the item is the string of the input field, as fields
    44.         //"key" and "value" and subscribe in DISTINCT mode
    45.         var table = new NonVisualTable(request, new Array("key","value"), "DISTINCT");
    46.         //we need just the snapshot
    47.         table.setSnapshotRequired(true);
    48.         //this callback is called after subscription notification. We clear the responseDiv
    49.         //so our response will be the only one inside it
    50.         table.onStart = function() {
    51.             responseDiv.innerHTML = "";
    52.         }
    53.         //this callback is called per each received update. We compose a string with
    54.         //the "key" and "value" fields and append this string to the responseDiv
    55.         table.onItemUpdate = function(itemPos, itemObj, itemName) {
    56.             var k = itemObj.getNewValue("key");
    57.             var v = itemObj.getNewValue("value");
    58.             responseDiv.innerHTML += k + ": " + v +"<br/>";
    59.         }
    60.         //this callback is called when all snapshot events have been received. Put
    61.         //this info in the responseDiv and remove the subscription
    62.         table.onEndOfSnapshot = function(itemPos,itemName) {
    63.             responseDiv.innerHTML += "Response COMPLETE " +itemPos+"<br/>";
    64.             //until we keep the table subscribed the data adapter will not be
    65.             //called for others clients making the same request (ie Lightstreamer
    66.             //kernel will handle directly responses for those clients). In this case
    67.             //we don't remove the subscription.
    68.             //lsPage.removeTable("req");
    69.         }
    70.         //this callback is called in case some updates were lost. Put the info inside
    71.         //the responseDiv
    72.         table.onLostUpdates = function(itemPos,lostUpdates,itemName) {
    73.             responseDiv.innerHTML += "We've lost updates!<br/>";
    74.         }
    75.        
    76.         //subscribe the table. In this demo we always use the same id ("req") to avoid
    77.         //multiple concurrent requests.
    78.         lsPage.addTable(table, "req");
    79.     }
    80. </script>
    81. </body>
    82.  
    83. </html>

    The sources of the demo are also available as a downloadable zip attacched to this post.
    Attached Files Attached Files

 

 

Similar Threads

  1. Replies: 3
    Last Post: January 27th, 2012, 10:26 AM
  2. Getting time out on initial subscription request
    By PeterHiross in forum Adapter SDKs
    Replies: 4
    Last Post: December 20th, 2010, 09:36 AM
  3. Bad request: LS_Session parameter missing
    By lstest in forum Adapter SDKs
    Replies: 5
    Last Post: February 26th, 2010, 03:47 PM
  4. User Specific Response
    By vishnugs in forum General
    Replies: 4
    Last Post: April 6th, 2007, 12:06 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
All times are GMT +1. The time now is 10:25 PM.