I think there is shortage of tutorials on web related to Lightstreamer, which is one awesome technology. Initially you may become over whelmed at the terminologies and trying to understand each and every part of it. I use lightstreamer as a part of architecture of a trading platform. I have used it pretty extensively within limits for the application. Hence, I would like to give this tutorial for people who wants to use this push software in there app's. I will cover the concepts with some amount of examples that will make ME understand Lightstreamer. :)
The basic requirement to understand this tutorial is, you need to know the concept of push technology first. I have used BlazeDS Messaging initially, so, may be if you are a Flex developer, first check out BlazeDS messaging. Then understand the concept of Push technology. Then, come to this tutorial to make more sense out of it.
In Lightstreamer, there are two parts for the push (I will call it 'streaming') to work. A backend and a front end. The backend is explained in java and front end is explained in Flex.
This 1st part of Tutorial is about Java Backend. I will explain the Flex Client side UI in the next part of the Tutorial.
Installation:
Download the zip from http://www.lightstreamer.com/. Extract it in a directory which I will call $LS_HOME, and read the GETTING_STARTED.txt in $LS_HOME. Its neatly and clearly written. There should not be a problem in understanding it. I would suggest you download a trial version than using the Moderato, the free one. And, Also buy it if you find it very useful :) Anyway's, its valid for 60 days, which is more than enough for you to evaluate it and understand its capability.
The Backend:
Structure: The first thing is, where do you put the code that has been written and how do you put it. There are two approaches.
First one is, compile your java code, get the .class files, and put it under $LS_HOME/adapters/myadapter/classes.
Second one is, create a jar out of your class files, and put it in $LS_HOME/adapters/myadapter/lib.
Create the two folders myadapter and classes/lib as needed by your approach.
Once the structure is ready, copy the adapters.xml from the samples given in $LS_HOME/adapters/Demo.
So, what is Adapter? Simplest term, this is what is responsible for pushing your data to your UI.
Lets write an adapter. Also, there are three more terminologies which we need to know.
2. itemName: This is any String that can be used to uniquely identify the type of data that has been requested by the client to the server. The server, i.e this adapter should understand the data that client from UI is requesting to be pushed. In the example below, it is as simple as Symbol IBM, that the server pushes data to UI.
3. ItemEventListener: This is the interface defined by Lightstreamer(LS) that is instantiated by LS, when the LS server is started. This has a method 'update', that is used to push data to the UI.
4. Snapshot: If the data is not available to be pushed, but a snapshot of it is available then the isSnapShotAvailable method can return true, and the itemEvenListener can send true in the last arguments for snapshots. The UI can request for a snapshot if it needs it. In trading sample app that I give below, a snapshot is not of much use, so, is defined as false.
And, this is it, we are good to go for an example.
Its very simple, create a Class MyJavaAdapter and implement com.lightstreamer.interfaces.data.DataProvider. That is it.. :)
Below is a simple adapter, that can be used generically with any Class that extends DataGenerator abstract class and is capable of generating data from any source, either database or from another server that pumps data over a network. You can define your own implementation.
In the code sample below, the MyJavaAdapter delegates its work to any class that extends DataGenerator. DataGenerator, does the job of setting and working with Listener given by the LS. Any class, that extends the DataGenerator is hidden from the intricacies of the LS. The push method in the DataGenerator does the actual job of pushing data to the UI. The data is sent in form of a key=value pair. The extended class, has to worry just about its business logic, i.e, where to get data from and push it to the server by converting it to a map. The sample below is a very very simple design, and can be highly modified/replaced to make it more generic and better, I hope you get the point.
public abstract class DataGenerator{
private ItemEventListener listener
public void init();
public boolean isSnapshotAvailable(String arg0)
throws SubscriptionException {
return false;
}
public final void setListener(ItemEventListener listener) {
this.listener = listener;
}
public void subscribe(String itemName, boolean arg1);
public void unsubscribe(String itemName);
public void push(String itemName,Map<String, String> values, boolean isSnapShot){
listener.update(itemName , values, isSnapShot);
}
}
The sample QuotesStubber that extends DataGenerator is given below. It uses timer to generate data at regular interval and push it to the front end. The push is happening in the run method if you observe.
public class QuotesStubber extends DataGenerator {
private static final Timer dispatcher = new Timer();
private List<String> subscribedSymbols;
public void init(){
subscribedSymbols = new ArrayList<String>();
run();
}
public void subscribe(String symbol, boolean arg1){
subscribedSymbols.add(symbol);
}
public void unsubscribe(String symbol){
subscribedSymbols.remove(removalIndex);
}
private void run(){
dispatcher.scheduleAtFixedRate(new TimerTask(){
public void run(){
for(int i=0; i < subscribedSymbols.size(); i++){
String req = subscribedSymbols.get(i);
Map<String,String> response = generateQuotesResponse(req);
push(req,response,false)
if(i >= subscribedSymbols.size()){
i = 0;
}
}
}
private Map<String,String> generateQuotesResponse(String symbol) {
Map<String,String> response = new HashMap<String,String>();
response.put("LastAsk",getRandom(2,2));
response.put("LastBid",getRandom(2,2));
response.put("LastPrice",getRandom(2,2));
response.put("Symbol",symbol);
return response;
}
private String getRandom(int digitB4Decimal, int digitAfterDecimal) {
String sRand = null;
Random random = new Random();
String sB4Decimal = String.valueOf(Math.abs(random.nextLong())).substring(0, digitB4Decimal);
String sAfter4Decimal = String.valueOf(Math.abs(random.nextLong())).substring(0, digitB4Decimal);
sRand = sB4Decimal + "." + sAfter4Decimal;
return sRand;
}
}, 0, 500);
}
}
The Adapter is below, this is responsible for interactions with the DataGenerator given above. The methods defined here is called by LS server at appropriate times. The reference for the datagenerator in the adapter below can be either injected or instantiated as given in comment.
public class MyJavaAdapter implements DataProvider{
private ItemEventListener listener;
private DataGenerator generator;//injected using spring or can be instantiated in the init method below
public void init(Map arg0, File arg1) throws DataProviderException {
generator.init();
}
public boolean isSnapshotAvailable(String arg0)
throws SubscriptionException {
generator.isSnapshotAvailable(arg0);
}
public void setListener(ItemEventListener listener) {
generator.setListener(listener);
}
public void subscribe(String itemName, boolean arg1)
throws SubscriptionException, FailureException {
generator.subscribe(itemName,arg1);
}
public void unsubscribe(String itemName) throws SubscriptionException,
FailureException {
generator.unsubscribe(itemName,arg1);
}
}
Finally, open adapter.xml that you copied before, and define a dataprovider as:
<data_provider name="MYJAVAADAPTER">
<adapter_class>MyJavaAdapter</adapter_class>
</data_provider>
You will use the 'name' attribute defined here from the Flex UI when you start requesting data to be pushed to it.
The Flex part of it will be provided in my next post/tutorial as a continuation to this one.