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...