SitePen Support
Free Liberator

Liberator Tutorial

by Martin TylerMarch 7th, 2008

People seem to like code snippets and tutorials, so here is a quick run through of the basics of using Liberator to create a streaming Comet application.

Liberator provides you with a JavaScript library called StreamLink for Browsers (or SL4B). This is used to build real time web pages that talk to Liberator. SL4B can be used in two ways: one requires no JavaScript programming at all and the other provides a rich JavaScript API based on subscriptions and callbacks.

No JavaScript

SL4B can make a web page live by simply adding attributes to HTML tags. A typical example of this is making an HTML table contain live FX prices. To achieve this there are two things to change on your HTML page.

Firstly, add a script tag to load the SL4B library:


<script id=”sl4b”
        type=”text/javascript”
        src=”/sl4b/index.js”
        configurationfile=”common-attributes.js”
        includertml=”includertml”>
</script>

And secondly, add some attributes to the HTML:


<table>
  <tr>
    <th>Currency</th>
    <th>Bid</th>
    <th>Ask</th>
  </tr>
  <tr>
    <td>EUR</td>
    <td id=”quote” symbol=”/FX/EUR” field=”dBestBid”>-</td>
    <td id=”quote” symbol=”/FX/EUR” field=”dBestAsk”>-</td>
  </tr>
  <tr>
  <td>GBP</td>
    <td id=”quote” symbol=”/FX/GBP” field=”dBestBid”>-</td>
    <td id=”quote” symbol=”/FX/GBP” field=”dBestAsk”>-</td>
  </tr>
</table>

The above HTML has been enhanced with three extra attributes to the <td> tags:

The standard id attribute has been set to "quote". This allows the SL4B library to find all the HTML elements that might require real time data. A custom attribute called "symbol" is used to specify the subject to subscribe to, and another custom attribute called "field" specifies the name of the field to display in this HTML element.

Behind the scenes, all this information is collated and subscribed to by the SL4B library. When data is received back from Liberator, the relevant HTML elements are updated with the real time values.

You can see an example of this in action.

Add in some JavaScript programming

The previous example shows a very simple way to get live data into a web page. There are more things you can do using that style, but if you want more control over what is happening you will probably want an API to program with.

SL4B allows you to make subscriptions and handle the data in callbacks.

The same script tag is needed to load the SL4B library:


<script id=”sl4b”
        type=”text/javascript”
        src=”http://liberator.company.com:8080/sl4b”
        configurationfile=”common-attributes.js”>
</script>

To make subscriptions in SL4B you need to create a subscriber:


function ExampleSubscriber()
{
    // This is the constructor of our object.

    // Any subclass of SL4B_AbstractSubscriber must call
    // initialise in its constructor. Once initialisation
    // is finished, SL4B will call ready() on this object.
    this.initialise();
}

// Declares that the ExampleSubscriber is a subclass of
// SL4B_AbstractSubscriber
ExampleSubscriber.prototype = new SL4B_AbstractSubscriber();

ExampleSubscriber.prototype.ready =
  function() {
    // Once the SL4B Object has completed
    // this.initialise() it will call ready()
    alert(”SL4B has connected and is ready”);
  };

var Subscriber = new ExampleSubscriber();

The above code is a bare subscriber, but to be useful it needs to make subscriptions and implement a callback:


ExampleSubscriber.prototype.ready =
  function() {
    // The fields to subscribe to are in a comma separated
    // list as the third argument of getObject.
    SL4B_Accessor.getRttpProvider().getObject(this,
                    “/Examples/Records/FX/GBP”,
                    “dBestBid,dBestAsk”);
  };

ExampleSubscriber.prototype.recordMultiUpdated =
  function(sObjectName, oFieldData) {
    var oElement = document.getElementById(’messages’)

    for (var i = 0, size = oFieldData.size(); i < size; i = i + 1) {
        oElement.innerHTML = sObjectName+” “+
                             oFieldData.getFieldName(i)+” = “+
                             oFieldData.getFieldValue(i)+”<br />”+
                             oElement.innerHTML;
    }
  };

The additional code above makes a subscription for a subject called /Examples/Records/FX/GBP and implements a callback to handle the returning data. In this case it is simply inserting the data into an HTML element.

You can see a more detailed version of this tutorial, which adds a few more steps to this example and has working examples.

Providing some data

Both the above examples assume there is some data available for the subjects subscribed to, e.g. /Examples/Records/FX/GBP. This data has to get into Liberator from somewhere. In some Comet applications the clients provide the data as well as consuming it, but in most financial Comet applications the data is provided on the server side.

The Liberator server receives data from DataSources, a DataSource being a separate process that communicates with Liberator via a socket connection. How this data is created in the DataSource is application specific, but in a typical financial application the DataSource is also connected to a third party data feed and is acting as a protocol converter.

DataSources are usually written in Java and a simple API is provided to do so.

The following code snippet shows the creation of a DataSource. Connections are handled internally and are specified by the configuration file.


    // Configures the datasource's connectivity - amongst other things
    final File dataSourceConfig = new File("conf/DataSource.xml");
    // Configures the mapping of field numbers to field names
    final File fieldsConfig = new File("conf/Fields.xml");

    // Create our local DataSource
    DataSource datasrc = new DataSource(dataSourceConfig,fieldsConfig);

    // Start the DataSource
    System.out.println(”Starting DataSource …”);
    datasrc.start();
    System.out.println(”DataSource started”);

To provide data to a Liberator, callbacks must be registered to handle subscriptions and interfaces must be implemented.


public class Stage2 implements DSRequestListener, DSDiscardListener
{
    public static void main(String[] args)throws IOException, SAXException
    {
        // Configures the datasource’s connectivity - amongst other things
        final File dataSourceConfig = new File(”conf/DataSource.xml”);
        // Configures the mapping of field numbers to field names
        final File fieldsConfig = new File(”conf/Fields.xml”);

        // Create our local DataSource
        DataSource datasrc = new DataSource(dataSourceConfig,fieldsConfig);

        // Create a listener for the relevant DataSource message types
        // so we may respond appropriately
        final Stage2 listener = new Stage2();
        // Listen for requests
        datasrc.setDSRequestListener(listener);
        // Listen for discards (un-requests)
        datasrc.setDSDiscardListener(listener);

        // Start the DataSource
        System.out.println(”Starting DataSource …”);
        datasrc.start();
        System.out.println(”DataSource started”);
    }

    public void receiveRequest( int peerIndex, String[] subjects )
    {
        for(int i=0;i<subjects.length;i++)
        {
            System.out.println(”Received request for “+subjects[i]);
        }
    }

    public void receiveDiscard( int peerIndex, String[] subjects )
    {
        for(int i=0;i<subjects.length;i++)
        {
            System.out.println(”Received discard for “+subjects[i]);
        }
    }

In this code we are implementing two interface methods and registering them with the created DataSource object. The callbacks are simply logging when requests and discards are received.

To actually respond to a request, a data message must be created and sent back to the Liberator. The following code shows this:


public void receiveRequest( int peerIndex, String[] subjects )
{
    for(int i=0;i<subjects.length;i++)
    {
        // Create the new record
        DSRecord update = DSFactory.createDSRecord(dataSource, subjects[i]);
        // Populate the new update’s fields
        update.addRecordData(”Counter”, 1234);
        // Send ‘Hello, World!’ in the ‘Message’ field
        update.addRecordData(”Message”, “Hello, World!”);
        // Send the update to the peer that requested it
        update.sendToPeer(peerIndex);
    }
}

Now we have sent back some initial data for the request, but there isn’t much point to Comet if you can’t send further data to a subscription. The same code seen above that sends the initial response can be used to send data at any point. If a discard (or unsubscribe) is received then you should stop sending any data for that subject.

How you send that data is obviously up to you and your application, but purely as a demonstration, the following code will send some subsequent updates every two seconds on a separate thread.


public void run()
{
    int counter = 0;

    while(alive)
    {
        try
        {
            Thread.sleep(2000);

            DSRecord update = DSFactory.createDSRecord(dataSource, symbol);
            update.addRecordData("Counter", ++counter);
            update.addRecordData("Message", "Hello, World! "+counter);
            update.sendToPeer(peerIndex);
        }
        catch(InterruptedException e)
        {
        }
    }
}

A full version of this DataSource tutorial is available in the Liberator kit.

The code above, and much more, is available in the online examples and as part of the free download for Liberator.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]
Free Liberator

Leave a Reply



Copyright 2009 Comet Daily, LLC. All Rights Reserved