Elektron SDK - C/C++

API Family: Elektron

EMA NI Provider - Introducing the EMA configuration file

Download tutorial source code

Click here to download

Last update June 2018
Compilers

Visual Studio 2015

For other compilers settings, please check out the EMA C++ Compiler Settings tutorial.

Prerequisites EMA NI Provider - Listening to the connection state

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

Tutorial purpose

In the previous tutorials we used hardcoded values for the connection parameters of our NI Provider application. In this tutorial you will learn how to leverage the EMA configuration file to store these parameters. This tutorial is focused on connection parameters. In the next tutorials you will learn how to personalize your NI Provider even more via the EMA configuration file.

In this tutorial we will go through the following sections:

Introduction

For the sake of simplicity, the NIProvider::connect() method of previous tutorials used hardcoded parameter values for the ADH IP address and port number. Obviously this solution is not very flexible and requires rebuilding the application every time you want to change these parameters. In this tutorial we will see that the EMA library uses a configuration file that is automatically loaded, and that you can leverage to store your connection parameters.

The EMA configuration file

EMA fosters convention over configuration, meaning that many default behaviors are hardcoded into the EMA library, and globally enforced. That way, as long as they follow the EMA conventions, EMA applications can work with a very small set of parameters.  For example, you don’t have to tell EMA the port number of the ADH your NI Provider must connect to, because, by convention, the EMA library assumes this port is 14003. You can change it if you want, but then you will have to tell EMA what the port number is, either programmatically or by using a configuration parameter.

The same way, by convention, the EMA configuration file should be named EmaConfig.xml and located in the working directory of the application. The EMA configuration file uses a simple XML schema. Here is the one we will use in this tutorial:

<?xml version="1.0" encoding="UTF-8"?>
<EmaConfig>

    <NiProviderGroup>
        <DefaultNiProvider value="NiProvider_1" />
        <NiProviderList>
            <NiProvider>
                <Name value="NiProvider_1" />
                <Channel value="Channel_1" />
            </NiProvider>
        </NiProviderList>
    </NiProviderGroup>

    <ChannelGroup>
        <ChannelList>
            <Channel>
                <Name value="Channel_1" />
                <ChannelType value="ChannelType::RSSL_SOCKET" />
                <Host value="YOUR_ADH_IP_ADDRESS" />
                <Port value="14003" />
            </Channel>
        </ChannelList>
    </ChannelGroup>

</EmaConfig>

In this schema the EMA configuration parameters are contained in the <EmaConfig> root node. This node may contain a number of sub-nodes, each of them grouping parameters for a specific domain. For example, connection parameters are contained in the <ChannelGroup> node. As explained above, most of these groups and parameters are optional. For an exhaustive list, please consult the EMA C++ Configuration Guide (see References).

Our first EMA configuration file uses just two groups, described below:

The <NiProviderGroup>

This is where you define the parameters of the NI Providers created by your application. The <NiProviderGroup> may declare one or several providers contained in the <NiProviderList>. In our case we only declare one. When the list declares several providers, the <DefaultNiProvider> parameter identifies the provider that must be used when the NiProvider application does not specify it (that is the case for this tutorial series).

Each provider of the <NiProviderList>. is defined in a <NiProvider> node which defines 2 parameters:

  • <Name>: This is the name of the provider.
  • <Channel>: This parameter identifies the communication channel used by this provider.

In our case we defined a provider called NiProvider_1. This name is totally arbitrary; you can use any name you want. Then, we declared that this provider uses a communication channel named Channel_1.

Notes:

  • <NiProvider> nodes may have other parameters that we do not use in this tutorial. They are described in the EMA C++ Configuration Guide (see References).
  • In a more complex configuration file, you may decide to declare several providers. In that case, EMA would use the first provider of the <NiProviderList> as the default provider. If you want to use another provider as the default, you must specify it using the <DefaultNiProvider> parameter. As in our case we have only one provider, the <DefaultNiProvider> parameter is useless. But we kept it anyway to be more explicit.

The <ChannelGroup>

This is the group where connection parameters are defined. The <ChannelGroup> may declare one or several channels contained in the <ChannelList>. In our case we only have Channel_1 that is used by NiProvider_1Channel_1 defines 3 parameters:

  • <ChannelType>: this parameter defines the type of connection (RSSL_SOCKET in our case).
  • <Host>: this parameter defines the IP address of the ADH to connect to (you must set the IP of your ADH here).
  • <Port>: this parameter defines the ADH port number to connect to (14003 in our case).

As the <ChannelType> default value is RSSL_SOCKET and as the Port default value is 14003, we could just get rid of these parameters for NiProvider. We kept them anyway in order to be more explicit.

Below is a simplified version that relies on the default values for the <DefaultNiProvider>, <ChannelType> and <Port> parameters:

<?xml version="1.0" encoding="UTF-8"?>
<EmaConfig>

    <NiProviderGroup>
        <NiProviderList>
            <NiProvider>
                <Name value="NiProvider_1" />
                <Channel value="Channel_1" />
            </NiProvider>
        </NiProviderList>
    </NiProviderGroup>

    <ChannelGroup>
        <ChannelList>
            <Channel>
                <Name value="Channel_1" />
                <Host value="YOUR_ADH_IP_ADDRESS" />
            </Channel>
        </ChannelList>
    </ChannelGroup>

</EmaConfig>

NI Provider refactoring

Now that the connection parameters are stored in the EmaConfig.xml configuration file, we can refactor our code to get rid of the hardcoded values. To this aim we removed the host variable (it contained both the ADH IP and port number) and also removed the .host() call to the OmmNiProviderConfig object.

The user name is the one connection parameter that we cannot move to the EMA configuration file. For more flexibility, we decided to move it to the main() function at the application level. It is still hardcoded in the main() but you can easily turn it into a parameter of the application. We also renamed the NiProvider connect() method to connectAs(username) so that the main() function can call it with the user name as a parameter.

Here is the new NiProvider connection method:

​
void NiProvider::connectAs(const std::string & userName)
{

    // Exit the method if already connected
    if (_provider != 0)
        return;

    cout << "  Connecting Provider to ADH as " << userName << endl;

    // Create a Non Interactive Provider using harcoded parameters
    _provider = new OmmProvider(
                        OmmNiProviderConfig()
                        .username(userName.c_str()));

    // Registers to login messages to be notified when the connection state changes
    UInt64 loginHandle = _provider->registerClient(
                                        ReqMsg()
                                            .domainType(MMT_LOGIN)
                                            .name(userName.c_str()),
                                        _connectionStateListener, 
                                        (void*)0);
}

The main workflow

The main workflow is still the same. As described above, we just replaced the connect() call of the _provider by connectAs() with the user name as parameter.

​int main(int argc, char* argv[])
{
    .
    .
    .

        NiProvider provider;

        provider.connectAs("YOUR_PROVIDER_USER_NAME");

        waitFor(60);

        provider.disconnect();
    .
    .
    .

}

Build and run the application

Edit the EmaConfig.xml and set the Host parameter with the IP of your ADH.

Then, 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.

A console application should open and display something like:

-------------------------------------------------------------------------------
|                    Non Interactive Provider EMA Tutorial                    |
|                                                                             |
|             Tutorial 4 - Introducing the EMA configuration file             |
-------------------------------------------------------------------------------
  Provider created
  Connecting Provider to ADH 10.2.43.49:14003 as nip-user
  Waiting for 60 seconds...
  Provider is connected. OmmState:Open / Ok / None / 'Refresh Completed'
  Disconnecting...
  Provider is disconnected. OmmState:Open / Suspect / None / 'channel down'
  Exiting the application
Press any key to continue . . .

The behavior of the application should be the same as that for the previous tutorial.

Troubleshooting

Q: When I build the tutorial project, I get errors like:

error MSB3073: The command "copy "\Ema\Libs\WIN_64_VS140\Debug_MDd\Shared\*.*" .\Debug_WIN_64_VS140_Shared\

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

 

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

After a while the application displays an error like: 

Exception Type='OmmInvalidUsageException', 
          Text='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 “Waiting for 60 seconds...” message and the “Provider is connected” message get mixed up when displayed in the console.

A: This is perfectly normal and actually caused by the EMA background thread that prints the “Provider is connected” message at the same time the main application thread prints the “Waiting for 30 seconds...” message. This can be fixed either by choosing a mono threaded application model (see the Message Processing - dispatch section of the Requesting MarketPrice data EMA Consumer tutorial) or by printing these messages atomically (use critical sections or a single cout << call to print the whole message).

Tutorial Group: 
EMA NI Provider