Implement the Streaming Real-Time Java Application with Kotlin Language

Overview

Kotlin is a statically-typed programming language developed by Jetbrains that runs on the Java virtual machine. Kotlin is a first-class programming language on Android OS. Kotlin interpolates with Java code and is reliant on Java code from the existing Java Class Library/Framework. Kotlin syntax aims for reducing Java language verbosity and complexity. The language is also designed with Java Interoperability in mind. Existing Java code can be naturally called from Kotlin.

This article shows how to implement the Real-Time Streaming Client (aka Consumer) and Real-Time Streaming server (aka OMM Provider or just Provider) applications with Kotlin programming language. The application source codes are implemented in Kotlin language with Refinitiv Enterprises Message API Java library. All source code will be compiled to Java Virtual Machine (JVM) compatible Java classes and run in a console.

Note: Although Kotlin source code can also be compiled to JavaScript and Native code, this example project focus only on the JVM target environment.

What is Refinitiv Real-Time SDK?

The Refinitiv Real-Time SDK Family (RTSDK C++ and Java Editions, formerly known as Elektron SDK) is a suite of modern and open APIs that aim to simplify development through a strong focus on ease of use and standardized access to a broad set of Refinitiv and 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.

This SDK is also available on GitHub with instructions to build the libraries.

The Real-Time SDK stack contains a set of capabilities ranging from low level ‘Transport’ interfaces to very high-level content aware stateful interfaces. The SDK consists of two following APIs

  1. Enterprise Transport API (ETA): Formerly known as UPA, or Ultra Performance API. The ETA API is the open source, high performance, low latency, foundation of the Refinitiv Real-Time SDK. This API provides the highest level of performance, scalability, tune-ability, low memory utilization, and low CPU utilization.
  2. Enterprise Message API (EMA): Formerly known as Elektron Message API, this API is a data-neutral, multi-threaded, ease-of-use API providing access to Refinitiv Real-Time data. As part of the Real-Time SDK, the Enterprise Message API allows applications to consume and provide OMM data at the message level of the API stack.

You can find more detail regarding the EMA Java from the following resources

EMA Application Life Cycle

The EMA Application (both Consumer and Provider) life cycle is the following:

  1. Establish a connection
  2. Send the login request message
  3. Issue requests & handle response
  4. Logout/Shutdown
EMA Application Life Cycle

Application files

The example project contains one Interactive-Provider application and two Consumer applications.

  • The Kotlin_IProvider_200 shows how to implement a basic RSSL Interactive Provider application.
  • The Kotlin_Consumer_100 shows how to implement a basic RSSL Consumer application.
  • The Kotlin_Consumer_220 shows how to implement a RSSL Consumer application that handles incoming data for each FID type.

The consumer applications can consume data from Kotlin_IProvider_200 application or other Elektron data sources (Refinitiv Real-Time Advanced Distribution Server, Refinitiv Real-Time Data Feed, etc).

connection diagram

You can find more detail regarding the OMM Consumer and OMM Interactive Provider interaction in EMA Java RDM Usage Guide sections 2.4 OMM Consumer / OMM Interactive Provider Initial Interaction and 2.5 Sending and Receiving Content. The EMA Java RDM Usage Guide is available on Refinitiv Real-Time SDK — Java: Documentation page.

The project includes completed Kotlin source codes, EMA Java Configurations file, and Maven POM file. You can download the latest version of RTSDK package from EMA Java: Download page or Maven Central Repository.

This example project and source code are compatible with Kotlin version 1.4.21, IntelliJ IDEA Java IDE versions 2020.3, and Refinitiv Real-Time SDK — Java edition 2.0.0 L1 (EMA Java 3.6.0 — Maven Central dependency: com.refinitiv.ema:ema:3.6.0.0).

Consumer Application Code Walkthrough

This article shows the Kotlin_Consumer_220.kt application code walkthrough. Please note that all Server, Data Dictionary, and Service name configurations are configured in EmaConfig.xml file.

Consumer Creation and Configuration

The Kotlin_Consumer_220.kt file implements the standard EMA Java Consumer applications. Firstly, we create OmmConsumer and OmmConsumerConfig objects. The OmmConsumerConfig object is configured to use “Consumer_1” configuration in the EmaConfig.xml file. The application then passes an OmmConsumerConfig object to an OmmConsumer object. By default, EMA will launch a background thread to manage communication and message dispatching when the application initiates an OmmConsumer object.

fun main(args: Array<String>) {
lateinit var consumer: OmmConsumer
try {
println("Starting Kotlin_Consumer_220 application")
//OmmConsumer, OmmConsumerConfig creation and establish communication.
consumer = EmaFactory.createOmmConsumer(EmaFactory.createOmmConsumerConfig().consumerName("Consumer_1"))
} catch (excp: InterruptedException) {
println(excp.message)
} catch (excp: OmmException) {
println(excp.message)
} finally {
consumer.uninitialize()
}
}

Create the Client application class

Next, we create the AppclientFieldListWalk class that implements the OmmConsumerClient interface. The AppclientFieldListWalk class defines a number of mandatory callback functions to capture the different events generated when the application registers interest in an item.

//Client class, implements OmmConsumerClient interface
class AppclientFieldListWalk : OmmConsumerClient {
override fun onRefreshMsg(refreshMsg: RefreshMsg, event: OmmConsumerEvent) {
println(refreshMsg)
}
override fun onUpdateMsg(updateMsg: UpdateMsg, event: OmmConsumerEvent) {
println(updateMsg)
}
override fun onStatusMsg(statusMsg: StatusMsg, event: OmmConsumerEvent) {
println(statusMsg)
}
override fun onGenericMsg(genericMsg: GenericMsg, event: OmmConsumerEvent): Unit {} override fun onAckMsg(ackMsg: AckMsg, event: OmmConsumerEvent): Unit {} override fun onAllMsg(msg: Msg, event: OmmConsumerEvent): Unit {}
}

Sending Market Price Item Request Message

Next, the application subscribes Euro currency Market Price data (EUR= RIC) to OMM Provider via the EMA Java OmmConsumer::registerClient() function. The application uses a default OmmConsumerConfig.OperationModel.API_DISPATCH dispatch model, so the application sleeps for one minute to lets the API dispatches all incoming messages to the AppclientFieldListWalk class.

fun main(args: Array<String>) {
lateinit var consumer: OmmConsumer
val appClient = AppclientFieldListWalk()
try {
println("Starting Kotlin_Consumer_220 application")
//OmmConsumer, OmmConsumerConfig creation and establish communication.
consumer = EmaFactory.createOmmConsumer(EmaFactory.createOmmConsumerConfig().consumerName("Consumer_1"))
println("Kotlin_Consumer_220: Send item request message")
consumer.registerClient(EmaFactory.createReqMsg().serviceName("DIRECT_FEED").name("EUR="), appClient) //Subscribe for EUR= RIC from DIRECT_FEED service
Thread.sleep(60000)
} catch (excp: InterruptedException) {
println(excp.message)
} catch (excp: OmmException) {
println(excp.message)
} finally {
consumer.uninitialize()
}
}

Handles incoming data

All messages (Refresh, Update, Status, etc) from the OMM Provider will be available via associate AppclientFieldListWalk callback functions. We implement a decode function to iterate each incoming OMM FieldList and FieldEntry data based on each field type, then parse and display it in a console. This function receives the FieldList data from Refresh and Update messages payload as a parameter.

class AppclientFieldListWalk : OmmConsumerClient {
//EMA callbacks functions
//Iterates OMM FieldList, then parse each OMM FieldEntry based on FID type
fun decode(fieldList: FieldList): Unit {
for (fieldEntry: FieldEntry in fieldList) {
print("Fid: ${fieldEntry.fieldId()} Name = ${fieldEntry.name()} DataType: ${DataType.asString(fieldEntry.load().dataType())} Value: ")
if (fieldEntry.code() == Data.DataCode.BLANK) {
println(" blank")
} else {
when (fieldEntry.loadType()) {
DataTypes.REAL -> println(fieldEntry.real().asDouble())
DataTypes.DATE -> println("${fieldEntry.date().day()} / ${fieldEntry.date().month()} / ${fieldEntry.date().year()}")
DataTypes.TIME -> println("${fieldEntry.time().hour()} : ${fieldEntry.time().minute()} : ${fieldEntry.time().second()} : ${fieldEntry.time().millisecond()}")
DataTypes.INT -> println(fieldEntry.intValue())
DataTypes.UINT -> println(fieldEntry.uintValue())
DataTypes.ASCII -> println(fieldEntry.ascii())
DataTypes.ENUM -> println("${if(fieldEntry.hasEnumDisplay()) fieldEntry.enumDisplay() else fieldEntry.enumValue() }")
DataTypes.RMTES -> println(fieldEntry.rmtes())
DataTypes.ERROR -> println("(${fieldEntry.error().errorCodeAsString()})")
else -> println("")
}
}
}
}
}

Next, we update onRefreshMsg() and onUpdateMsg() callback functions to send incoming FieldList payload data to parse and display in console via a decode() function.

class AppclientFieldListWalk : OmmConsumerClient {    override fun onRefreshMsg(refreshMsg: RefreshMsg, event: OmmConsumerEvent): Unit {
if (refreshMsg.hasName()) println("Refresh: Item Name: ${refreshMsg.name()}")
if (refreshMsg.hasServiceName()) println("Refresh: Service Name: ${refreshMsg.serviceName()}") println("Refresh: Item State: ${refreshMsg.state()}") if(DataType.DataTypes.FIELD_LIST == refreshMsg.payload().dataType()) decode(refreshMsg.payload().fieldList()) println("")
}
override fun onUpdateMsg(updateMsg: UpdateMsg, event: OmmConsumerEvent): Unit {
if (updateMsg.hasName()) println("Update: Item Name: ${updateMsg.name()}")
if (updateMsg.hasServiceName()) println("Update: Service Name: ${updateMsg.serviceName()}") if(DataType.DataTypes.FIELD_LIST == updateMsg.payload().dataType()) decode(updateMsg.payload().fieldList()) println("")
}
override fun onStatusMsg(statusMsg: StatusMsg, event: OmmConsumerEvent): Unit {
if (statusMsg.hasName()) println("Status: Item Name: ${statusMsg.name()}")
if (statusMsg.hasServiceName()) println("Status: Service Name: ${statusMsg.serviceName()}") if(statusMsg.hasState()) println("Status: Item State: ${statusMsg.state()}")
}
override fun onGenericMsg(genericMsg: GenericMsg, event: OmmConsumerEvent): Unit {} override fun onAckMsg(ackMsg: AckMsg, event: OmmConsumerEvent): Unit {} override fun onAllMsg(msg: Msg, event: OmmConsumerEvent): Unit {} fun decode(fieldList: FieldList): Unit {
// Code from previous step
for (fieldEntry: FieldEntry in fieldList) {
//...
}
}
}

Now, Kotlin_Consumer_220.kt application is ready for connecting and consuming Market Price data from OMM Provider.

Interactive Provider Application Code Walkthrough

This section shows the Kotlin_IProvider_200.kt application code walkthrough. Please note that all Server, Data Dictionary, and Service name configurations are configured in EmaConfig.xml file.

Define the OmmProviderClient interface class

The Kotlin_IProvider_200.kt file implements the standard EMA Java Interactive Provider applications. Firstly, we create IProviderAppClient class that implements OmmProviderClient interface. This IProviderAppClient class will be responsible for the following tasks:

  • Processing incoming Login/Market Price request messages from the consumer application.
  • Sending Market Price Refresh message back to the consumer.

We define a number of mandatory OmmProviderClient’s callback functions to handle different consumer request events.

//Client class, implements OmmProviderClient interfaceclass IProviderAppClient : OmmProviderClient {
override fun onReqMsg(reqMsg: ReqMsg, providerEvent: OmmProviderEvent) {}
override fun onRefreshMsg(refreshMsg: RefreshMsg, providerEvent: OmmProviderEvent) {} override fun onStatusMsg(statusMsg: StatusMsg, providerEvent: OmmProviderEvent) {}

override fun onAllMsg(msg: Msg, providerEvent: OmmProviderEvent) {}
override fun onClose(closeMsg: ReqMsg, providerEvent: OmmProviderEvent) {} override fun onGenericMsg(genericMsg: GenericMsg, providerEvent: OmmProviderEvent) {} override fun onPostMsg(postMsg: PostMsg, providerEvent: OmmProviderEvent) {} override fun onReissue(reissueMsg: ReqMsg, providerEvent: OmmProviderEvent) {}
}
fun main(args: Array<String>){
val appCient = IProviderAppClient()
}

Provider Creation and Configuration

Next we create OmmProvider object with EmaFactory.createOmmProvider() function and configure it to use "Provider_1" configuration in the EmaConfig.xml file. This Interactive Provider application uses a OmmConsumerConfig.OperationModel.USER_DISPATCH dispatch model, so application calls the OmmProvider.dispatch() function manually to dispatch received messages to IProviderAppClient class. By default, EMA will launch a background thread to manage communication and establishes a server port when the application initiates an OmmProvider object.

fun main(args: Array<String>){
lateinit var provider: OmmProvider
val appCient = IProviderAppClient()
try{
println("Starting Kotlin_IProvider_200 application, waiting for a consumer application") //OMMProvider creation and establish sersver port.
provider = EmaFactory.createOmmProvider(EmaFactory.createOmmIProviderConfig().providerName("Provider_1").operationModel(OmmIProviderConfig.OperationModel.USER_DISPATCH), appCient)
while(appCient.itemHandle.toInt() == 0){
provider.dispatch(1000L)
Thread.sleep(1000L)
}
} catch (excp:OmmException ){
println(excp.message)
} catch (excp:InterruptedException ){
println(excp.message)
} finally {
provider.uninitialize()
}
}

Handles incoming Login Request Message

All request messages from Consumer applications will be delivered to IProviderAppClient class via the onReqMsg() callback function. We check if the incoming request message domain type is a Login domain, then send that request message to the processLoginRequest() function for processing this Login request message. The processLoginRequest() function then sends a Login Refresh Response message via the OmmProvider.submit() function to accept this Login request.

class IProviderAppClient : OmmProviderClient {    var itemHandle: Long = 0L // Initial item Handle
override fun onReqMsg(reqMsg: ReqMsg, providerEvent: OmmProviderEvent) {
//Verify incoming message type
when (reqMsg.domainType()) {
EmaRdm.MMT_LOGIN -> processLoginRequest(reqMsg,providerEvent) //Handle Login Request Message
else -> {
println("Wrong Request")
}
}
}
//OmmProviderClient callbacks functions. private fun processLoginRequest(reqMsg: ReqMsg, event: OmmProviderEvent) { println("Receive Login Request message from ${reqMsg.name()}, send Login Refresh")
//Send Login REFESH_RESP message to consumer
event.provider().submit(
EmaFactory.createRefreshMsg()
.domainType(EmaRdm.MMT_LOGIN)
.name(reqMsg.name())
.nameType(EmaRdm.USER_NAME)
.complete(true)
.solicited(true)
.state(OmmState.StreamState.OPEN, OmmState.DataState.OK, OmmState.StatusCode.NONE, "Login accept")
.attrib(EmaFactory.createElementList())
, event.handle())
}
}

Handle incoming Market Price Request Message

Next, we update the onReqMsg callback function to support the Market Price request message. The application checks if the incoming request message domain type is a Market Price domain, then sends that request message to the processMarketPriceRequest() function for processing this Market Price request message.

The processMarketPriceRequest() function creates a Market Price Payload. Firstly, we create an OMM FieldList object via the EmaFactory.createFieldList() function, set each Field value and FID in an OMM FieldEntry object, add each FieldEntry object to FieldList object. Finally, the application sends a Market Price Refresh Response message with FieldList Payload to Consumer application via the OmmProvider.submit() function.

class IProviderAppClient : OmmProviderClient {    var itemHandle: Long = 0L // Initial item Handle
override fun onReqMsg(reqMsg: ReqMsg, providerEvent: OmmProviderEvent) {
//Verify incoming message type
when (reqMsg.domainType()) {
EmaRdm.MMT_LOGIN -> processLoginRequest(reqMsg,providerEvent) //Handle Login Request Message
EmaRdm.MMT_MARKET_PRICE -> processMarketPriceRequest(reqMsg,providerEvent) //Handle Market Request Message
else -> {
println("Wrong Request")
}
}
}
//OmmProviderClient callbacks functions.
fun processLoginRequest(reqMsg: ReqMsg, event: OmmProviderEvent) {
//Handle Login Request Message
}
private fun processMarketPriceRequest(reqMsg: ReqMsg,event: OmmProviderEvent){
println("Kotlin_IProvider_200: Receive Market Price Request message")
//Creates Market Price Payload and Send Refresh Message
val fieldList:FieldList = EmaFactory.createFieldList()
//Add each FID data to the message
fieldList.add(EmaFactory.createFieldEntry().ascii(3, reqMsg.name()))
fieldList.add(EmaFactory.createFieldEntry().enumValue(15, 840))
fieldList.add(EmaFactory.createFieldEntry().real(21, 3900, OmmReal.MagnitudeType.EXPONENT_NEG_2))
fieldList.add(EmaFactory.createFieldEntry().real(22, 3990, OmmReal.MagnitudeType.EXPONENT_NEG_2))
fieldList.add(EmaFactory.createFieldEntry().real(25, 3994, OmmReal.MagnitudeType.EXPONENT_NEG_2))
fieldList.add(EmaFactory.createFieldEntry().real(30, 9 , OmmReal.MagnitudeType.EXPONENT_0))
fieldList.add(EmaFactory.createFieldEntry().real(31, 19 , OmmReal.MagnitudeType.EXPONENT_0))
println("Kotlin_IProvider_200: Send Market Price Refresh message") //Send Market Price REFESH_RESP message to consumer
event.provider().submit(
EmaFactory.createRefreshMsg()
.serviceName(reqMsg.serviceName())
.name(reqMsg.name())
.state(OmmState.StreamState.OPEN, OmmState.DataState.OK, OmmState.StatusCode.NONE , "Refresh Completed")
.solicited(true)
.payload(fieldList)
.complete(true)
, event.handle())
itemHandle = event.handle()
}
}

Sending Market Price Update Message

The application sends Market Price Update Messages to Consumer application in a main() function. Firstly, the application creates OMM FieldList and Update Message objects via the EmaFactory class. The application creates the Update Message Payload with OMM FieldList and OMM FieldEntry objects, and sends Update Message object with a payload via the OmmProvider.submit() function.

We iterate integer value from 1 to 59 and adds that value to the Price value of each Update message payload. This behavior simulates Elektron Update Message behavior in that each tick contains a different updated value.

fun main(args: Array<String>){    //OMMProvider creation and establish sersver port.    provider = EmaFactory.createOmmProvider(EmaFactory.createOmmIProviderConfig().providerName("Provider_1").operationModel(OmmIProviderConfig.OperationModel.USER_DISPATCH), appCient)    //Creats OMM FieldList and Update Message objects
val fieldList: FieldList = EmaFactory.createFieldList()
val updateMsg: UpdateMsg = EmaFactory.createUpdateMsg()
for(index in 1..59){
val startTime: Long = System.currentTimeMillis()
provider.dispatch(1000L) //Add each FID data to the message
fieldList.clear()
fieldList.add(EmaFactory.createFieldEntry().real(22, 3991 + index.toLong(), OmmReal.MagnitudeType.EXPONENT_NEG_2))
fieldList.add(EmaFactory.createFieldEntry().real(25, 3994 + index.toLong(), OmmReal.MagnitudeType.EXPONENT_NEG_2))
fieldList.add(EmaFactory.createFieldEntry().real(30, 10 + index.toLong(), OmmReal.MagnitudeType.EXPONENT_0))
fieldList.add(EmaFactory.createFieldEntry().real(31, 19 + index.toLong(), OmmReal.MagnitudeType.EXPONENT_0))

//Send Market Price UPDATE_RESP message to consumer
provider.submit(updateMsg.clear().payload(fieldList), appCient.itemHandle)
println("Kotlin_IProvider_200: Send Market Price Update messages")
while(System.currentTimeMillis() - startTime < 1000){}
}
}

Handles Invalid Request Message

The application needs to handle invalid request messages from Consumer applications as well. We create a processInvalidItemRequest() function to send OMM Status message with Stream State: Closed, Data State: Suspect to Consumer application for following cases:

  • Incoming request messages are not Login and Market Price domains
  • An Item Handle is an invalid number.
class IProviderAppClient : OmmProviderClient {    var itemHandle: Long = 0L // Initial item Handle
override fun onReqMsg(reqMsg: ReqMsg, providerEvent: OmmProviderEvent) {
when (reqMsg.domainType()) {
EmaRdm.MMT_LOGIN -> processLoginRequest(reqMsg,providerEvent) //Handle Login Request Message
EmaRdm.MMT_MARKET_PRICE -> processMarketPriceRequest(reqMsg,providerEvent) //Handle Market Price Request Message
else -> {
processInvalidItemRequest(reqMsg,providerEvent)
}
}
}
//OmmProviderClient callbacks functions.
fun processLoginRequest(reqMsg: ReqMsg, event: OmmProviderEvent) {
//Handle Login Request Message
}
private fun processMarketPriceRequest(reqMsg: ReqMsg,event: OmmProviderEvent){
if(itemHandle.toInt() != 0){
processInvalidItemRequest(reqMsg,event)
return
}
//Creates Market Price Payload and Send Refresh Message
}
private fun processInvalidItemRequest(reqMsg: ReqMsg, event: OmmProviderEvent){
event.provider().submit(
EmaFactory.createStatusMsg()
.name(reqMsg.name())
.serviceName(reqMsg.serviceName())
.domainType(reqMsg.domainType())
.state(OmmState.StreamState.CLOSED, OmmState.DataState.SUSPECT, OmmState.StatusCode.NOT_FOUND, "Item not found")
, event.handle())
}
}

Now, Kotlin_Consumer_220.kt application is ready for publishing Market Price data for OMM Consumer.

Application Setup

The application source code and Intelli IDEA Community Edition project files are available on GitHub website. You can get it via the following git command

$>git clone git@github.com:Refinitiv-API-Samples/Example.EMA.Java.Kotlin.git

This example requires the following dependencies software.

  1. Oracle Java 8 SDK.
  2. IntelliJ IDEA Java IDE version 2020.3 and above. You can download IntelliJ IDEA Community Edition from this page.
  3. Refinitiv Real-Time SDK (RTSDK) Java Libraries via Maven Central website. You can also download the SDK documents and examples from Refinitiv Real-Time SDK — Java: Download page or GitHub page.
  4. Apache Maven project management and comprehension tool.
  5. Internet connection.

please check the README.md in the source code project for more detail.

Build and run the Project with Apache Maven via a command line

  1. Create a development directory of your choice (for example, C:\drive_d\Project\Kotlin_project).
  2. Unzip or download the example project folder to a development directory.
  3. Open a console or command prompt to your development directory.
  4. Run $>mvn package command in a console to build the demo applications into a single-all-dependencies rtsdk200_kotlin-1.0-SNAPSHOT-jar-with-dependencies.jar file in the project's target folder.
Building project with Maven
Building project with Maven success

Then you can run Kotlin_IProvider_200 application demo application with the following command in Windows Command Prompt application:

java -cp .;target/rtsdk200_kotlin-1.0-SNAPSHOT-jar-with-dependencies.jar com.refinitiv.realtime.kotlin.Kotlin_IProvider_200Kt

To run Kotlin_Consumer_220.kt demo application, open another console for ema_example folder and run the following command:

java -cp .;target/rtsdk200_kotlin-1.0-SNAPSHOT-jar-with-dependencies.jar com.refinitiv.realtime.kotlin.Kotlin_Consumer_220Kt

Example Results

Kotlin_IProvider_200 application demo application example result:

com.refinitiv.realtime.kotlin.Kotlin_IProvider_200Kt
Starting Kotlin_IProvider_200 application, waiting for a consumer application
Feb 19, 2021 5:33:43 PM com.refinitiv.ema.access.ServerChannelHandler reactorChannelEventCallback
INFO: loggerMsg
ClientName: ServerChannelHandler
Severity: Info
Text: Received ChannelUp event on ClientHandle 1
Instance Name Provider_1_1
Component Version ETA Java Edition|EMA Java Edition
loggerMsgEnd
Receive Login Request message from U8004042, send Login Refresh
Kotlin_IProvider_200: Receive Market Price Request message
Kotlin_IProvider_200: Send Market Price Refresh message
Kotlin_IProvider_200: Send Market Price Update messages
Kotlin_IProvider_200: Send Market Price Update messages

Kotlin_Consumer_220.kt demo application example result:

com.refinitiv.realtime.kotlin.Kotlin_Consumer_220Kt
Starting Kotlin_Consumer_220 application
Feb 19, 2021 5:33:42 PM com.refinitiv.ema.access.ChannelCallbackClient reactorChannelEventCallback
INFO: loggerMsg
ClientName: ChannelCallbackClient
Severity: Info
Text: Received ChannelUp event on channel Channel_1
Instance Name Consumer_1_1
Component Version ETA Java Edition|EMA Java Edition
loggerMsgEnd
Kotlin_Consumer_220: Send item request message
Refresh: Item Name: EUR=
Refresh: Service Name: DIRECT_FEED
Refresh: Item State: Open / Ok / None / 'Refresh Completed'
Fid: 3 Name = DSPLY_NAME DataType: Rmtes Value:
Fid: 15 Name = CURRENCY DataType: Enum Value: USD
Fid: 21 Name = HST_CLOSE DataType: Real Value: 39.0
Fid: 22 Name = BID DataType: Real Value: 39.9
Fid: 25 Name = ASK DataType: Real Value: 39.94
Fid: 30 Name = BIDSIZE DataType: Real Value: 9.0
Fid: 31 Name = ASKSIZE DataType: Real Value: 19.0
Update: Item Name: EUR=
Update: Service Name: DIRECT_FEED
Fid: 22 Name = BID DataType: Real Value: 39.92
Fid: 25 Name = ASK DataType: Real Value: 39.95
Fid: 30 Name = BIDSIZE DataType: Real Value: 11.0
Fid: 31 Name = ASKSIZE DataType: Real Value: 20.0
Update: Item Name: EUR=
Update: Service Name: DIRECT_FEED
Fid: 22 Name = BID DataType: Real Value: 39.93
Fid: 25 Name = ASK DataType: Real Value: 39.96
Fid: 30 Name = BIDSIZE DataType: Real Value: 12.0
Fid: 31 Name = ASKSIZE DataType: Real Value: 21.0

Build and run the Project with IntelliJ IDEA

If you prefer to build and run the project with the IntelliJ IDEA, please follow Build and run the Project with IntelliJ IDEA section in the project’s README.md file.

Conclusion

Kotlin is now a rising star cross-platform, statically typed, general-purpose programming language. The language lets developers implement a concise and expressive code while maintaining full compatibility with Java.

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

References

For further details, please check out the following resources:

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

GitHub

https://github.com/Refinitiv-API-Samples/Example.EMA.Java.Kotlin

Developer Advocate at Refinitiv, an LSEG business. https://developers.refinitiv.com/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store