Implementing Real-Time Cloud Consumer Application with Kotlin

Wasin Waeosri
9 min readDec 7, 2023

Last Updated: December 2023

Introduction

The original article on the Refinitiv Developer Community is available here.

Refinitiv Real-Time SDK (Java Edition) (RTSDK, formerly known as Elektron SDK) is a suite of modern and open source APIs that aim to simplify development through a strong focus on ease of use and standardized access to a broad set of Refinitiv proprietary content and services via the proprietary TCP connection named RSSL and proprietary binary message encoding format named OMM Message. The capabilities range from low latency/high-performance APIs right through to simple streaming Web APIs.

The How to Implement EMA Java Application with Kotlin Language article shows how to implement Enterprise Message API (EMA) Java Consumer and Interactive Provider applications using Kotlin. This article shows a step-by-step guide to build the EMA Java Consumer application to connect and consume real-time streaming data from the Cloud (Refinitiv Real-Time Optimized, aka RTO).

EMA Java and Kotlin with Refinitiv Real-Time diagram

Note:

  • This example project uses Kotlin version 1.9.0 and EMA Java 3.7.1.0 (RTSDK 2.1.1.L1)
  • I am demonstrating with the Version 2 Authentication

Introduction to Kotlin

Kotlin is a modern, cross-platform, statically typed, high-level programming language developed by Jetbrains. The language syntax is concise, safe, interoperable with Java. Kotlin is designed with fully Java Interoperability in mind. It can be compiled to JavaScript and iOS/Android native code (via LLVM) with many ways to reuse code between multiple platforms for productive programming.

One major benefit for Java developers is integration with Java code and libraries (including RTSDK Java). Existing Java code can be called from Kotlin in a natural way. Kotlin syntax aims for reducing Java language verbosity and complexity, so Java developers can migrate to Kotlin easily. With a lot of potentials, Kotlin has been chosen by Google to be a first-class programming language on Android OS since 2019.

Kotlin syntax aims for “making developers happier” by reducing Java language verbosity and complexity like the following example:

That’s all I have to say about Kotlin introduction.

Prerequisite

Before I am going further, there is some prerequisite, dependencies, and libraries that the project is needed.

Java SDK

Firstly, you need Java SDK. Please check for the supported Java version from the API Compatibility Matrix page.

I am using the Open JDK version 11 in this project (as of April 2023).

Maven

Next, the Maven build automation tool. Please follow Apache Maven installation guide document.

Docker or IntelliJ IDEA

The example project is a console application that can be run on Docker or IntelliJ IDEA editor.

Access to the RTO

This project uses RTO access credentials for both Version 1 Authentication (Machine ID type) and Version 2 Authentication (Service ID)

Please contact your Refinitiv representative to help you with the RTO account and services.

Internet Access

This demonstration connects to RTO on AWS via a public internet.

Application Code Walkthrough

Maven pom.xml file

Let’s start with the Maven pom.xml file setting for Kotin. The pom.xml file the main Maven's project configuration. To use Kotlin with Maven, you need the kotlin-maven-plugin to compile Kotlin sources and modules. The first step is defining the version of Kotlin via the <properties> tag as follows:

And then set add the Kotlin standard library in the pom.xml file dependency setting.

For more detail about EMA Java dependency and Maven, please check the How to Set Up Refinitiv Real-Time SDK Java Application with Maven article.

Next, set the pom.xml file’s source directory and kotlin-maven-plugin plugins to let Maven knows where and how to compile the source code as follows:

You can see a full pom.xml file configurations in the project repository.

To learn more about Kotlin and Maven configurations, please see Kotlin: Maven build tool page.

Let’s leave the pom.xml file setting for the Kotlin project development there.

Consumer Creation and Configuration

Now we come to the consumer code walkthrough. The demo application (KonsumerRTO.kt) is based on the EMA Java ex451_MP_OAuth2Callback_V2, ex333_Login_Streaming_DomainRep, series300.ex360_MP_View and ex113_MP_SessionMgmt examples source code to connect and consume real-time streaming from RTO with the View feature.

The KonsumerRTO.kt file implements the standard EMA Java Consumer applications with Kotlin syntax mindset.

1. Set the application entry point

An entry point of a Kotlin application is in the main function, and it does not need to be inside a class like Java. The main function creates the KonsumerRTO object, pass the RTO Service ID credential (Version 2 Authentication), and service name information to the KonsumerRTO object for further EMA-RTO workflow.

The code uses the dotenv-kotlin library to load the RTO credentials and configuration from the environment variable .env file or the System Environment Variables. The OS/system's environment variables always override .env configurations by default.

That’s all I have to say about the consumer application entry point.

2. Setting RDP Version 2 Authentication credentials to the OmmConsumer Class

The next step is creating the OmmConsumer object. Then set the V2 auth Client Credentials (client ID and client secret) to the OmmConsumer instance via the OmmConsumerConfig class.

The “Consumer_4” is defined to connect to RTO in the EmaConfig.xml file as follows.

Please refer to the Refinitiv Real-Time — Optimized Install and Config Guide document to find more detail about RTO endpoints locations.

3. Setting a client secret in the ReactorOAuthCredentialRenewal

By default, the EMA API will store all credential information. To use secure credential storage, a callback function can be specified by the user. If an OmmOAuth2ConsumerClient instance is specified when creating the OmmConsumer object, the EMA API does not store the password or clientSecret. In this case, the application must supply the password or clientSecret whenever the OAuth credential event OmmOAuth2ConsumerClient.onCredentialRenewal callback method is invoked. This call back must call set the credentials to the OAuth2CredentialRenewal instance and set it to the OmmConsumer.renewOAuthCredentials method to provide the updated credentials.

The main purpose of the CredentialStore class is for holding the credentials only, so I am using the Kotlin Data Class feature to shorten this POJO class implementation.

Then add the oAuthCallback and credentials objects to the OmmConsumer.createOmmConsumer(OmmConsumerConfig config,OmmOAuth2ConsumerClient OAuthClient,java.lang.Object closure) method as follows.

That covers how to initialize connection with RTO using the Version 2 Authentication.

4. Registering Login Stream

My next point is how to monitors the state of connectivity when connecting to the RTO. The application can open a login stream to receive the stream’s status and information.

Note: If you are connecting to the RTDS (either on-prem or hosted solution), registering a a login stream to receive the stream’s status and information can be helpful for monitoring a connection.

5. Requesting Data

Now we come to the item subscription process. I am using the View feature to subscribe only interested FIDs.

That completes the OmmConsumer main part, let's move on the the OmmConsumerClient part that handles the login and item streams incoming messages.

Create the Client application class.

That brings us to client application AppClient class which implements the OmmConsumerClient interface.

6. Defining the mandatory callbacks

The OmmConsumerClient interface needs to contain the mandatory callback functions to capture the different events generated when the application registers interest in an item as follows.

Now the AppClient class can receive and print incoming data from the API.

7. Handling Login Stream Messages

Since the KonsumerRTO class has registered the Login stream, the Login stream event messages will come to the AppClient as well. To handle the Login stream message, you can check the incoming message domain type in the onRefreshMsg and onStatusMsg callback methods to parse the Login stream message accordingly.

Example messages:

Received Refresh. Item Handle: 1 Closure: null
Item Name: xXXXXXXXXXXXXXXX
Service Name: <not set>
Item State: Open / Ok / None / 'Login accepted by host ads-fanout-sm-az1-apse1-prd.'
AllowSuspectData : true
ApplicationId : 256
ApplicationName : RTO
Position : 192.168.XX.XXX/WIN-XXXXXX
ProvidePermissionExpressions : true
ProvidePermissionProfile : false
SingleOpen : true
SupportBatchRequests : 7
SupportOMMPost : true
SupportOptimizedPauseResume : false
SupportViewRequests : true
SupportStandby : true
SupportEnhancedSymbolList : 1
AuthenticationErrorCode : 0
Solicited : true
UserName : xXXXXXXXXXXXXXXX
UserNameType : 1
State : StreamState: 1 DataState: 1 StatusCode: 0StatusText: Login accepted by host ads-fanout-sm-az1-apse1-prd.

Now you can monitor the connectivity health from the Login stream messages.

8. Handling incoming messages Field-By-Field

Now, what about the market price message handling. The code above just prints incoming messages “as is” which is not useful. I am implementing the decode method to iterate incoming data's FieldList object and handle data field by field. Please be noticed that the decode method handles only a few data types because the KonsumerRTO uses the View feature to request only interested FIDs, so the method can check only subscription FIDs data types.

Example Messages:

Received Refresh. Item Handle: 2 Closure: null
Item Name: EUR=
Service Name: ELEKTRON_DD
Item State: Open / Ok / None / ''
Fid 15 Name = CURRENCY DataType: Enum Value: USD
Fid 22 Name = BID DataType: Real Value: 1.0942
Fid 25 Name = ASK DataType: Real Value: 1.0943
Fid 875 Name = VALUE_DT1 DataType: Date Value: 15 / 8 / 2023
Fid 1010 Name = VALUE_TS1 DataType: Time Value: 9 : 50 : 6 : 0
Received Update. Item Handle: 2 Closure: null
Item Name: EUR=
Service Name: ELEKTRON_DD
Fid 22 Name = BID DataType: Real Value: 1.094
Fid 25 Name = ASK DataType: Real Value: 1.0944
Fid 875 Name = VALUE_DT1 DataType: Date Value: 15 / 8 / 2023
Fid 1010 Name = VALUE_TS1 DataType: Time Value: 9 : 50 : 8 : 0

That covers the OmmConsumer Client application source code with Kotlin explanation.

How to run the demo application

My next point is how to run the demo application. The first step is to unzip or download the example project folder into a directory of your choice.

Then, go to the project’s folder and create a file name .env with the following content.

#Authentication V2
CLIENT_ID=<Client ID V2>
CLIENT_SECRET=<Client Secret V2>
SERVICENAME=<ELEKTRON_DD or ERT_FD3_LF1>

The Kotlin source code can be compiled to Java, so the demo application can run with the same Dockerfile setting as the native Java application

To build a Docker image, run the following command.

docker build . -t kotlin_rto

Once the building process is success, run the following command to run a Docker container:

docker run -it --name kotlin_rto --env-file .env kotlin_rto
Running RTO Kotlin example with Docker

To stop and delete a Docker container, press Ctrl+C (or run docker stop kotlin_rto) then run the docker rm kotlin_rto command.

To delete a Docker image, run the docker rmi kotlin_rto after a container is removed.

That covers how to run an example.

Conclusion

Before I finish, let me just say Kotlin is now a rising star cross-platform, general-purpose programming language. The language has been used by both mobile, front-end, and the back-end developers. Kotlin lets developers implements a shorter and easier-to-read source code while maintaining full compatibility with Java.

The Java language is trying to simplify itself via the JEP 445 Unnamed Classes and Instance Main Methods specification which is currently available as a preview feature of Java version 21. However, it takes time until Java developers can migrate their supported JVM to Java 21. But with Kotlin, developers can build applications with concise, simply, and expressive, code with fully supports the current JVM versions without waiting for Java 21.

This language simplicity helps developers implements the Real-Time application using EMA in a simple way that simpler than implement on the native-Java.

Kodee, the Kotlin mascot

That’s all I have to say about Kotlin and RTO.

References

For further details, please check out the following resources:

For any question related to this article or the RTSDK page, please use the Developer Community Q&A Forum.

--

--