Elektron SDK - Java

API Family: Elektron

EMA NI Provider - Publishing updates

Download tutorial source code

Click here to download

Last update January 2017
Compilers

JDK 1.7.x, JDK 1.8.x

Prerequisites

EMA NI Provider - Publishing a Source Directory

Declare the NI_PUB and TEST_NI_PUB services in your TREP (see Before you start).

Tutorial purpose

In this tutorial you will learn how to send market price update data after you sent the initial refresh message.

To this aim we will go through the following sections:

Introduction

In the Publishing our first Market Price tutorial we described the message flow that takes place between NI Providers and Consumer applications. We also explained how to send the refresh messages that convey the initial data of market price data items. In this tutorial we will teach you how to encode and publish update messages your NI Provider must send when a market price data item changes.

Update messages

Update messages are sent by providers to notify the distribution system and the consumer applications that a data item has changed. For the sake of efficiency, these messages only convey the data that actually changed (for example, an update message of a market price item only contains the fields with new values). This is the most important difference between update messages and refresh messages.

Another notable difference is that NI Providers do not have to indicate the service name, the item name (RIC) and the domain type in the update messages they send. Indeed, as this information has already been sent in the initial refresh message, there is no absolute need to repeat it in the updates. However, repeating the service name and the item name is a good practice that may help the ADH to rebuild its cache in case of failover. This is especially true when the connection to the ADH is done via a RSSL_RELIABLE_MCAST channel. Because of the multicast connection, the provider application may not be aware when an ADH fails. Consequently, it will not send any refresh message for its data items when the ADH goes up again. Thus, the ADH that failed over will have to rebuild its cache based on the updates it receives. Adding the service name and the item name to the updates will help this process. This is a good practice we encourage and that we implemented in the update() method below.

So, basically, update messages sent by NI Providers just need to transport the fields that changed and the handle that uniquely identifies the item stream. However, adding the service name and the item name is a good practice we encourage.

The Item class

In the Publishing our first Market Price tutorial we published a single refresh message with hardcoded values. Now that we want to publish updates, we need a source of changing data. To this aim, we introduced an Item class that simulates a live data item. This class is in charge of:

  • generating random data for 5 predefined fields (Display name, Bid, Ask, Open price, Close price),
  • simulating changes for two of these fields (Bid and Ask),
  • generating the handle that uniquely identifies each item stream.

The NiProvider class

 

The only one item

As this tutorial uses only one item, the NiProvider holds only one instance of the Item class, that is preserved in its theOnlyOneItem private member.

    private Item theOnlyOneItem = new Item("SHARE-0", 14400);

This object is used by the refresh() and update() methods described below. It provides the RIC, the handle and the field values these methods need to build and send data for the item.

 

The Field IDs

For better readability, and because we now use field IDs in two different part of the code, we introduced private static members to describe them. They are used by the refresh() method and the new update() method (see below) that build and send refresh and update messages.

    // Field IDs and Acronyms used by this class
    private static int DSPLY_NAME = 3;
    private static int BID = 22;
    private static int ASK = 25;
    private static int OPEN_PRC = 19;
    private static int HST_CLOSE = 21;

 

The refresh() method

We refactored the refresh method so that it uses the new Item class and the Field IDs described above. We also added a test at the beginning of the method to verify that we will publish a message for the right item (theOnlyOneItem). If not, we exit the method. 

public void refresh(String itemName)
{
    if (!isConnected())
    {
        System.out.println("  ERROR: Can't refresh " + itemName + ". The provider is not connected.");
        return;
    }

    if (itemName != theOnlyOneItem.getName())
    {
        System.out.println("  ERROR: Can't refresh " + itemName + ". Unknown item name.");
        return;
    }

    Item item = theOnlyOneItem;

    System.out.println("  Refreshing " + item.getName());

    FieldList fieldList = EmaFactory.createFieldList();
    fieldList.add(EmaFactory.createFieldEntry()
            .ascii(
                DSPLY_NAME, 
                item.getDisplayName()));
    fieldList.add(EmaFactory.createFieldEntry()
            .real(
                BID, 
                item.getBidPrice(), OmmReal.MagnitudeType.EXPONENT_NEG_2));
    fieldList.add(EmaFactory.createFieldEntry()
            .real( 
                ASK, 
                item.getAskPrice(), OmmReal.MagnitudeType.EXPONENT_NEG_2));
    fieldList.add(EmaFactory.createFieldEntry()
            .real(
                OPEN_PRC, 
                item.getOpenPrice(), OmmReal.MagnitudeType.EXPONENT_NEG_2));
    fieldList.add(EmaFactory.createFieldEntry()
            .real(
                HST_CLOSE, 
                item.getClosePrice(), OmmReal.MagnitudeType.EXPONENT_NEG_2));

    provider.submit(
                EmaFactory.createRefreshMsg()
                    .serviceName(getServiceName())
                    .name(item.getName())
                    .domainType(EmaRdm.MMT_MARKET_PRICE)
                    .state(
                        OmmState.StreamState.OPEN, 
                        OmmState.DataState.OK, 
                        OmmState.StatusCode.NONE, 
                        "UnSolicited Refresh Completed")
                    .payload(fieldList)
                    .complete(true), 
                item.getHandle());
}

 

The update() method

We added an update() method to the NiProvider class for publishing market price update messages. This method is a kind of simplified version of the refresh() method. It uses the UpdateMsg class instead of the RefreshMsg class to build the message. An overloaded version of the submit() method of the OmmProvider is used to send the message.

Note that before sending the message we call the generateNextTick() method of the item to compute new random values for the Bid price and Ask price.

public void update(String itemName)
{
    if (!isConnected())
    {
        System.out.println("  ERROR: Can't update " + itemName + ". The provider is not connected.");
        return;
    }

    if (itemName != theOnlyOneItem.getName())
    {
        System.out.println("  ERROR: Can't update " + itemName + ". Unknown item name.");
        return;
    }

    Item item = theOnlyOneItem;

    System.out.println("  Updating " + item.getName());

    item.generateNextTick();

    FieldList fieldList = EmaFactory.createFieldList();
    fieldList.add(EmaFactory.createFieldEntry()
            .real(
                BID, 
                item.getBidPrice(), OmmReal.MagnitudeType.EXPONENT_NEG_2));
    fieldList.add(EmaFactory.createFieldEntry()
            .real(
                ASK, 
                item.getAskPrice(), OmmReal.MagnitudeType.EXPONENT_NEG_2));

    provider.submit(
                EmaFactory.createUpdateMsg()
                    .serviceName(getServiceName())
                    .name(item.getName())
                    .payload(fieldList), 
                item.getHandle());
}

 

The data item stream

The refresh and update messages published for a data item are part of the same stream of messages. Each data item has its own stream that is identified by a unique handle. This handle is unique at the provider level. When you want to publish a new message for an item, you must indicate this handle as the second parameter of the submit() method. In our case, this handle is held by the theOnlyOneItem object and can be retreived thanks to the getHandle() method. As we use the same handle for the refresh message and the update messages, all these messages are part of the same item stream, updating the values of the same data item.

The main workflow

The main workflow now leverages the new refresh() method of the NiProvider to publish updates for our single MarketPrice item. After having published the refresh, the workflow waits for 1 second and publishes 30 updates, one every second. Then, it disconnects and exits the application as usual.

public static void main(String[] args)
{
    .
    .
    .
        NiProvider provider = new NiProvider(); 
        provider.setServiceName("TEST_NI_PUB");
        provider.connectAs("YOUR_PROVIDER_USER_NAME");
        waitFor(5);

        provider.refresh("SHARE-0");
        waitFor(1);

        for (int i = 0; i < 30; ++i)
        {
            provider.update("SHARE-0");
            waitFor(1);
        }

        provider.disconnect();
    .
    .
    .
}

Build and run the application

Build the application and start it. Please refer to the Build and Run section within the first tutorial of this series (A barebones EMA NIP application shell) for detailed instructions.

This is what you should get:

  1. The application should display something like:
-------------------------------------------------------------------------------
|                    Non Interactive Provider EMA Tutorial                    |
|                                                                             |
|                       Tutorial 7 - Publishing updates                       |
-------------------------------------------------------------------------------
  Provider created
  Connecting Provider to ADH 10.2.43.49:14003 as nip-user
  Waiting for 5 seconds...
  Provider is connected. OmmState:Open / Ok / None / 'Refresh Completed'
  Refreshing SHARE-0
  Waiting for 1 seconds...
  Updating SHARE-0
  Waiting for 1 seconds...
  Updating SHARE-0
  Waiting for 1 seconds...
    .
    .
    .
  Updating SHARE-0
  Waiting for 1 seconds...
  Disconnecting...
  Exiting the application
  1. Open a TREP consuming application and subscribe to the SHARE-0 market price item of the TEST_NI_PUB service. After a short while, you should receive values for the 5 fields (DSPLY_NAME/3, OPEN_PRC/19, HST_CLOSE/21, BID/22 and ASK/25) published by the Ni Provider. Then, every second the BID and ASK fields are updated.

    As an example, this is a screenshot of the Eikon Quote object that we used to subscribe to TEST_NI_PUB/SHARE-0. In this Eikon, updated fields are displayed in yellow for a short while:

  2. After the 30 updates, the TEST_NI_PUB service goes down and the application exits.

Troubleshooting

Q: When I build or run the tutorial, it fails with an error like:

The system cannot find the path specified

A: The JAVA_HOME environment variable is not set, or set to the wrong path. See Setup the development environment section of the first tutorial.

 

Q: When I build the tutorial, I get ”<path>/javac: No such file or directory” or when I run the tutorial, I get  ”<path>/java: No such file or directory” error like

line 59: /home/user/jdk/bin/javac: No such file or directory

A: The JAVA_HOME environment variable is not set, or set to the wrong path. See Setup the development environment.

 

Q: When I build or run the tutorial, I get "Finding Jar files in <path>” and “The system cannot find the path specified.” errors like

Build the NIP application with Elektron SDK Java version 1.2.x or higher.

Finding Jar files in C:\Elektron-SDK\Java\Ema\Libs\
The system cannot find the path specified.

A: There are 2 possible causes:

 

Q: When I build or run the tutorial, I get "<path to /*jar> : No such file or directory” error like

/home/user/Elektron-SDK1.1.1.E2.java.eload/Java/Ema/Libs/*.jar: No such file or directory

A: There are 2 possible causes:

 

Q: When I build the tutorial, I get "package ... does not exist" and "cannot find symbol" errors like:

Main.java:20: error: package com.thomsonreuters.ema.access does not exist
import com.thomsonreuters.ema.access.OmmException;
                                    ^
Main.java:56: error: cannot find symbol
                catch (OmmException exception)
                       ^
  symbol:   class OmmException
  location: class Main

A: The ELEKTRON_JAVA_HOME environment variable is not set, or set to the wrong path. See Setup the development environment section of the first tutorial.

 

Q: When I run the tutorial, I get a JNI error with a NoClassDefFoundError exception like:

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/thomsonreuters/ema/access/OmmException
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
        at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
        at java.lang.Class.getMethod0(Class.java:3018)
        at java.lang.Class.getMethod(Class.java:1784)
        at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: com.thomsonreuters.ema.access.OmmException
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 7 more

A: The ELEKTRON_JAVA_HOME environment variable is not set, or set to the wrong path. See Setup the development environment section of the first tutorial.

 

Q: The application is stuck after the "Connecting Provider to ADH…" message is displayed.

After a while the application displays an error like: 

login failed (timed out after waiting 45000 milliseconds) for 10.2.43.149:14003)

A: Verify that the ADH of your TREP infrastructure is up and that you properly set the host parameter in the EmaConfig.xml file. 

You can also use the telnet command tool to verify that your NIP application machine can connect to the ADH (telnet <ADH host> <port>). If the telnet succeeds but you still can’t connect, verify that you don’t have any firewall blocking the messages sent/received by the application.  

Ultimately, ask your TREP administrator to help you to investigate with TREP monitoring tools like adhmon.

 

Q: The NI Provider application can connect and publish data to ADH, but the consumer application does not receive data and shows the following Status Message

state="Closed / Suspect / None / 'Service name of 'TEST_NI_PUB' is not found.'"

Or

State: OPEN, SUSPECT, NONE,  "Waiting for service TEST_NI_PUB UP. Item recovery in progress..."

A: It means the published Service is not match with the NI Service defined in the ADH configurations. Please contact TREP administrator to help you to check the NI Service name defined in your TREP infrastructure.

Tutorial Group: 
EMA NI Provider