Download tutorial source code |
Click here to download |
Last update | Dec 2020 |
Compilers | JDK 1.7.x, JDK 1.8.x |
Prerequisites | EMA NI Provider - Introducing the EMA configuration file |
The aim of this tutorial is to explain the concepts related to data item publication and to teach you how to use EMA to publish a refresh message for a market price instrument.
To this aim we will go through the following sections:
Now that we know how to properly connect a NI Provider application to a Real-Time Distribution System, it is time to get to the meat and actually publish data for the consuming applications. In this tutorial, you will learn how to use the EMA library to encode and publish data for a MarketPrice item.
The aim of this section is to give you a brief overview of real-time infrastructures, concepts, and workflows. For further details please consult the Real-Time SDK Concepts Guide and the EMA Java RDM Usage Guide.
Distribution systems
The real-time infrastructures like RTDS or Real-Time platform are efficient and reliable distributed systems that enable the exchange of data items between Provider and Consumer applications. Before you start learning how to publish data, it is important you become familiar with the concepts described below.
Services
The system distributes data items via services. Each service provides a universe of data items (a.k.a instruments) and domain models that are served by provider applications. Several providers can serve the same service and a provider can serve several services.
A service is said Up when at least one of its providers is running and connected to the system. If no provider is available, the service is said Down and none of its data items can be consumed.
Different services may deliver different data and different domain models for the same item. For example, on the Enterprise Platform IDN_RDF may provide market price level1 data for MSFT.O while DF_NAS_L2 provides market by order level 2 data for the same item.
Services and providers deliver data items for one or several domain models (aka capabilities). Some of these models are defined by LSEG. They are then called Domain Models (RDM) - Market price, order book, and yield curve are well known Domain Models. Other domain models can be defined by users. They are then called User Domain Models (UDM).
Items distributed on the system are identified by a unique RIC. They may be distributed by several services and provided for different domain models. For this reason, a RIC alone is not enough to identify a data item. It must be completed by the service and the domain model.
These three elements (Service / RIC / Domain Model) uniquely identify the data items distributed by the infrastructure. In this tutorial, we will publish Market Price data for the RIC SHARE-0 via the service NI-PUB.
Note: The naming of the RIC with the -0 (zero) suffix is intentional as in later tutorials we will demonstrate multiple items to publish, i.e. SHARE-0, SHARE-1, etc.
Non-Interactive Providers
NI Provider applications publish data items that are cached by the infrastructure and then distributed to the requesting consumers. Ni Providers can publish several data items of several domain models for one or several services. For this reason, they must indicate the service, the RIC, and the domain model of the item they publish.
Consumers
When a consuming application requests a data item, it must specify the three elements described above (Service, RIC, Domain Model). In return, and if the item is available, a refresh message (a.k.a image) is sent back by the system. In the case of market price data items, the refresh message contains the state and the complete data (all the fields) of the item. If the request indicated an interest in streaming data, the consumer may also receive subsequent updates and statuses.
Provider / Consumer message flow
The diagram below illustrates an example of a message flow between a consumer that requested a streaming MarketPrice data item published by a NI Provider. This provider is connected to a remote source system that provides the actual data.
The MarketPrice domain allows to publish Level I market information such as trades, indicative quotes, and top-of-book quotes. All information is sent as a list of field/value pairs that contain the information related to the data item (i.e. net change, bid, ask, volume, high, low, or last price). Each field is identified by a unique id and has an associated value of a predefined data type. The exhaustive list of fields with their ids, names and data types are defined by a field dictionary held by the infrastructure.
The diagram below illustrates the structure of a Market Price message. The FieldList conveys several field entries. Each FieldEntry holds a FieldId (a.k.a FID) and the current value of the related field. Details like the field name and the value type are defined in the field dictionary. In this example, the first FieldEntry is for the DSPLY_NAME field and contains a 16 characters long string.
Notes:
For MarketPrice data items, NI Providers can publish Refresh messages, Update messages, and Status messages.
For more details about the MarketPrice model and the related messages, please consult the Real-Time SDK Concepts Guide and the EMA Java RDM Usage Guide.
For our first publication, we will send a Refresh message for the SHARE-0 market price item on the NI_PUB service. In order to tell the infrastructure what data item this message is published for, we will use the following information:
The message will also transport the item state, and the item payload made of a field list.
To create a refresh message using EMA, you just have to create a RefreshMsg object and initialize it by calling its different methods. Then, when you finished setting the different parts of the message, you must call the complete() method to indicate that the message is complete. For example, you could do something like:
RefreshMsg refreshMsg = EmaFactory.createRefreshMsg();
refreshMsg.serviceName("NI_PUB");
refreshMsg.name("SHARE-0");
refreshMsg.domainType(MMT_MARKET_PRICE);
.
.
.
refreshMsg.complete();
refreshMsg.state(
OmmState.StreamState.OPEN,
OmmState.DataState.OK,
OmmState.StatusCode.NONE,
"UnSolicited Refresh Completed");
This method gets 4 parameters:
Please consult the EMA Java Reference Manual and the RDM Usage Guide for more details about the market price state.
The refresh message will transport a payload made of the following field list:
Name | Fid | Type | Value |
DSPLY_NAME | 3 | String | "My Company Share" |
BID | 22 | Real | 14.4 |
ASK | 25 | Real | 14.7 |
OPEN_PRC | 19 | Real | 14.1 |
HST_CLOSE | 21 | Real | 14.9 |
The payload is simply added to the refresh message by calling the payload() method. But before you do that you must build the market price payload itself. To this aim, you must create a FieldList object and initialize it by adding the fields and their values one by one using field entries. The FieldEntries class provides one method per field type. For example, to set a string value in a FieldEntry you must call the ascii() method, to set a real value you must call the real() method, etc. Here is how you could proceed for the field list described above:
FieldList fieldList = EmaFactory.createFieldList();
fieldList.add(EmaFactory.createFieldEntry()
.ascii(
3, // DSPLY_NAME
"My Company Share"));
fieldList.add(EmaFactory.createFieldEntry()
.real(
22, // BID
14400, OmmReal.MagnitudeType.EXPONENT_NEG_2));
fieldList.add(EmaFactory.createFieldEntry()
.real(
25, // ASK
14700, OmmReal.MagnitudeType.EXPONENT_NEG_2));
fieldList.add(EmaFactory.createFieldEntry()
.real(
19, // OPEN_PRC
14100, OmmReal.MagnitudeType.EXPONENT_NEG_2));
fieldList.add(EmaFactory.createFieldEntry()
.real(
21, // HST_CLOS
14900, OmmReal.MagnitudeType.EXPONENT_NEG_2));
refreshMsg.payload(fieldList);
long itemHandle = 2;
provider.submit(refreshMsg, itemHandle);
The first parameter is the refresh message to publish. The second parameter is a handle that uniquely identifies the item stream. This number is chosen by the provider application and will be used for every subsequent message sent for this item stream. Let us say you want to publish an update for the same data item, then you must submit the update message using the exact same handle (2 in this case).
Now that we saw how to build the payload, the state and how to send a refresh message for a data item, we will put all this together in a new refresh() method of the NiProvider class.
public void refresh(String serviceName, String itemName)
{
if (!isConnected())
{
System.out.println(" ERROR: Can't refresh " + itemName + ". The provider is not connected.");
return;
}
System.out.println(" Refreshing " + itemName);
long itemHandle = 2;
FieldList fieldList = EmaFactory.createFieldList();
fieldList.add(EmaFactory.createFieldEntry()
.ascii(
3, // DSPLY_NAME
"My Company Share"));
fieldList.add(EmaFactory.createFieldEntry()
.real(
22, // BID
14400, OmmReal.MagnitudeType.EXPONENT_NEG_2));
fieldList.add(EmaFactory.createFieldEntry()
.real(
25, // ASK
14700, OmmReal.MagnitudeType.EXPONENT_NEG_2));
fieldList.add(EmaFactory.createFieldEntry()
.real(
19, // OPEN_PRC
14100, OmmReal.MagnitudeType.EXPONENT_NEG_2));
fieldList.add(EmaFactory.createFieldEntry()
.real(
21, // HST_CLOS
14900, OmmReal.MagnitudeType.EXPONENT_NEG_2));
provider.submit(
EmaFactory.createRefreshMsg()
.serviceName(serviceName)
.name(itemName)
.domainType(EmaRdm.MMT_MARKET_PRICE)
.state(
OmmState.StreamState.OPEN,
OmmState.DataState.OK,
OmmState.StatusCode.NONE,
"UnSolicited Refresh Completed")
.payload(fieldList)
.complete(true),
itemHandle);
}
This method takes two arguments, the service name and the item name which is the actual RIC. It is a public method of the NiProvider class, that we will call in our main workflow.
First of all, we test if the provider is connected and exit the method if it's not.
Then, we build and publish the message. As you can see, we leveraged the chained method call facility provided by EMA. This allows us to write a more concise and readable code. The code is indented in a way that you can easily tell what methods are called on what object. For example, from the indentation you can tell that the serviceName(), name(), domainType(), state(), payload() and the complete() methods have been called on the RefreshMsg object that we created using the EmaFactory. From the indentation, you can also tell that the submit() method has two parameters: the RefreshMsg and the itemHandle.
Also to be mentioned:
We chose to implement this tutorial this way for the sake of simplicity, and because we are publishing only one data item. We will improve this code in the next tutorials.
The main workflow leverages the new refresh() method of the NiProvider class to implement the following:
public static void main(String[] args)
{
.
.
.
NiProvider provider = new NiProvider();
provider.connectAs("YOUR_PROVIDER_USER_NAME");
waitFor(5);
provider.refresh("NI_PUB", "SHARE-0");
waitFor(60);
provider.disconnect();;
.
.
.
}
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:
-------------------------------------------------------------------------------
| Non Interactive Provider EMA Tutorial |
| |
| Tutorial 5 - Publishing our first Market Price |
-------------------------------------------------------------------------------
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 60 seconds...
Disconnecting...
Exiting the application
2. During the 60 seconds wait, open a RTDS consuming application and subscribe to the SHARE-0 market price item of the 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.
As an example, this is a screenshot of the Eikon Quote object that we used to subscribe to NI_PUB/SHARE-0. In the Eikon configuration, the NI_PUB service has been associated to the 'N' key letter:
3. After 60 seconds, the NI_PUB service goes down and the application exits.
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 Real-Time SDK Java.
Finding Jar files in C:\RTSDK\Java\Ema\Libs\
The system cannot find the path specified.
A: The cause could be:
Q: When I build or run the tutorial, I get "<path to /*jar>: No such file or directory” error like
/home/user/RTSDK-2.0.0.L1.java.rrg/Java/Ema/Libs/*.jar: No such file or directory
A: The cause could be:
Q: When I build the tutorial, I get "package ... does not exist" and "cannot find symbol" errors like:
Main.java:20: error: package com.refinitiv.ema.access does not exist
import com.refinitiv.ema.access.OmmException;
^
Main.java:56: error: cannot find symbol
catch (OmmException exception)
^
symbol: class OmmException
location: class Main
A: The RTSDK_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/refinitiv/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.refinitiv.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 RTSDK_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 RTDS 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 RTDS administrator to help you to investigate with RTDS 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 'NI_PUB' is not found.'"
Or
State: OPEN, SUSPECT, NONE, "Waiting for service 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 RTDS administrator to help you to check the NI Service name defined in your RTDS infrastructure.