Elektron SDK - Java

API Family: Elektron

ETA Tutorial 2 - Establishing a connection to a Provider

Download tutorial source code

Click here to download

Last update May 2018
Environment Windows, Linux
Compilers JDK 1.7 or greater
Prerequisite ETA Tutorial 1 - Creating a bare-bones ETA starter application

Elektron Server Connection Configuration details.

Introduction

Utilizing the Consumer/client interface defined within Tutorial 1, our objective within this tutorial is to initiate a connection request to an OMM-based Provider and manage the server responses. Because all communication is asynchronous, our setup involves registering and implementing callback processing to manage all possible events such as success and failure. In addition, we'll introduce the main ValueAdd component, ETA Reactor, which manages and establishes communication between our consumer and the provider, i.e. Elektron.

Description

Derived from Tutorial 1, we will utilize the ValueAdd components to setup and initialize basic communication. A consumer in our definition simply acts as a client to a server of data. Prior to session establishment, requesting and receiving data, we must first establish basic communication.

ETA Reactor

The ETA Reactor is a connection management and event processing component that can significantly reduce the amount of code an application must write to connect to OMM-based devices. The component supports basic session management including user log in, source directory establishment and dictionary download. The reactor also supports event dispatch, flushing of user written content and network pings on the user's behalf. While the component supports both Consumers and Providers, these series of tutorials will only be demonstrating the consumption of market data thus we only require consumer use.

The following diagram shows how the Value Added Components fit within the core Transport API components.  Refer to the Value Added Components section within the ETA documentation for a detailed outline.

Implementation Overview - Communicating with our OMM-based Provider

As briefly outlined within Tutorial 1, all communication to an OMM-based Provider utilizes an event-driven, asynchronous paradigm. As such, the ETA interfaces expect callback functions to be defined to capture and react to these events. In this tutorial, we will enhance the basicConsumer class to perform the necessary steps to communicate with an OMM-based Provider. The following steps define communication:

Define and setup a role

When determining the type of connection our application must establish, we must specify whether we are acting as a consumer of data or a provider of data. This specification is referred to as a role. In our case, a Consumer role is defined because we are acting as a consumer of market data.  The role specification requires the registration of a number of event callbacks needed to successfully connect and communicate with a Provider.  Each registration notifies the consumer role what action it needs to perform.  For example:

...

// Consumer Role
ConsumerRole consumerRole = ReactorFactory.createConsumerRole();

...

private void init()
{
    ...

    // Define our RDM callback handlers
    consumerRole.defaultMsgCallback(this);
    consumerRole.channelEventCallback(this);

    ...
}
			

The above Consumer Role registration handlers, connect (channelEventCallback) and data (defaultMsgCallback) are mandatory when defining a consumer of data. Below are the associated callbacks for the above registration.

Define our callbacks

Within Tutorial 1, 5 mandatory callbacks with empty placeholders were created to manage the series of events when interfacing with our Provider. To support the basic Consumer role, the following callbacks must be registered:

channelEventCallback

The channelEventCallback is used to manage our connection into the OMM-based Provider. The code segment below outlines the primary function of this callback which involves capturing and reporting the connection status and registering of the connection channel with our reactor, etc. In addition, we also utilize the "Channel Ready" event to signal we're ready for further communication with our Provider.

@Override
public int reactorChannelEventCallback(ReactorChannelEvent event)
{
    switch(event.eventType())
    {
        case ReactorChannelEventTypes.CHANNEL_UP:
        {
            // A channel that we have requested has come up.  We must now register our channel within our
            // selectable channels. This will drive the process of detecting message events, i.e. Login,
            // Directory, Dictionary etc.
            System.out.println("\nConnection up!  Registering our connection within our event loop\n");

            // register selector with channel event's reactorChannel
            try
            {
                event.reactorChannel().selectableChannel().register(selector,
                                                                    SelectionKey.OP_READ,
                                                                    event.reactorChannel());
            }
            catch (ClosedChannelException e)
            {
               System.out.println("selector register failed: " + e.getLocalizedMessage());
               return ReactorCallbackReturnCodes.FAILURE;
            }
            break;
         }

         case ReactorChannelEventTypes.CHANNEL_READY:
            System.out.println("Channel is ready");

            // Capture the channel once we're ready
            channel = event.reactorChannel();
            break;

         ...
    }
}
		

defaultMsgCallback

The defaultMsgCallback specification is used to capture data events reported when we register interest in market data items. Within subsequent tutorials, we will be requesting for market data, however, because the ETA Reactor defines this registration as mandatory, it must be specified. Presently, no implementation is necessary.

Specify our connection options and initiate a connection

The code segment below is responsible for setting up our connection and initiating an asynchronous request to our desired server/provider. Our connection defines specific options such as the server hostname (which must be adapted to your installation), server port and how the reactor handles loss of connection. Once setup and the connection request is initiated, we wait for connection events to determine the result.

// Server host name
private static final String srvrHostname = "elektron";

// Server port number
private static final String srvrPortNo = "14002";

...

private void init()
{
    ...

    // Prepare our connection
    connectOptions.connectionList().add(connectInfo);
    connectOptions.connectionList().get(0).connectOptions().majorVersion(Codec.majorVersion());
    connectOptions.connectionList().get(0).connectOptions().minorVersion(Codec.minorVersion());
    connectOptions.connectionList().get(0).connectOptions().connectionType(ConnectionTypes.SOCKET);
    connectOptions.connectionList().get(0).connectOptions().unifiedNetworkInfo().address(srvrHostname);
    connectOptions.connectionList().get(0).connectOptions().unifiedNetworkInfo().serviceName(srvrPortNo);
    connectOptions.reconnectAttemptLimit(-1); // attempt to recover forever
    connectOptions.reconnectMinDelay(1000); // 1 second minimum
    connectOptions.reconnectMaxDelay(60000); // 60 second maximum

    // Initialize connection
    int ret;
    if ((ret = reactor.connect(connectOptions, (ReactorRole)consumerRole, errorInfo)) 
                                                                         < ReactorReturnCodes.SUCCESS)
    {
        System.out.println("Reactor.connect failed with return code: " + ret + " error = " 
                                                                             + errorInfo.error().text());
        System.exit(ReactorReturnCodes.FAILURE);
    }
}
			

Dispatch events - Event Loop

Once we have our communication defined and our callbacks in place, we can begin to monitor events. The Event Loop, represented in the diagram below, will react to external events triggered by our OMM Provider. The moment activity is detected, the event is dispatched to the appropriate callback for processing. Once completed, processing is returned back into the event loop to process any further events or waits for the next available one. Refer to the code segment outlined within the run() method below.

EventLoop - UPA Java Tutorial 2

private void run()
{
    int selectRetVal, selectTime = 1000;
    while (true)
    {
        Set keySet = null;
        try
        {
            // Wait for events...
            selectRetVal = selector.select(selectTime);
            if (selectRetVal > 0)
            {
               keySet = selector.selectedKeys();
            }
        }

        ...

        // Pass control off to the Reactor to figure out proper dispatch...
        Iterator iter = keySet.iterator();
        int ret = ReactorReturnCodes.SUCCESS;
        while (iter.hasNext())
        {
            SelectionKey key = iter.next();
            iter.remove();
            try
            {
                if (key.isReadable())
                {
                    // retrieve associated reactor channel and dispatch on that channel
                    ReactorChannel reactorChnl = (ReactorChannel)key.attachment();

                    // dispatch until no more messages
                    while ((ret = reactorChnl.dispatch(dispatchOptions, errorInfo)) > 0) {}

                    ...
                }
            }
        }
    }
}

The keySet value in the above segment represents the set of channels that we have detected activity. In our tutorial, we typically only see activity on the channel where our data is coming down.

Setup and Configuration

Before building and running our project, you must ensure you can connect into a valid Elektron or TREP environment to test. Defined within the basicConsumer.java file, these tutorials assume the following server and port has been defined:

// Server host name
private static final String srvrHostname = "elektron";

// Server port number
private static final String srvrPortNo = "14002";

...
		

You can either define the server name 'elektron' within your environment to point to a valid market data server or simply modify these server configuration parameters to suit your setup.  Your market data administrator can provide these connection details.

Build and run

Refer to the Build and run section within the ETA Tutorial 1 - Creating a starter consumer application for instructions to successfully execute this tutorial.

Eg (Windows):

> buildConsumer 2 

> runConsumer 2

Running the tutorial will simply echo the connection status and if successful, report that our channel is ready.

Note: the application will not exit as it does in Tutorial 1. This is a result of us remaining within the event loop for additional events. Users must ^C to exit.

Running tutorial 2...
Ultra Performance API (UPA), Java Edition, LibraryVersionInfo
        productVersion: etaj3.0.0.L1.all.rrg
        productInternalVersion: etaj3.0.0.L1
        productDate: Fri April 29 12:24:15 CST 2016 Thomson Reuters
basicConsumer initializing...

Connection up!  Registering our connection within our event loop

Channel is ready
				

References

For more information, refer to the ETA Java Development Guides.

Tutorial Group: 
ETA Consumer