支持Retifive

This commit is contained in:
Achilles
2024-04-10 13:56:34 +08:00
parent 03e6d9ecb9
commit 9d3bac8a9d
11 changed files with 2589 additions and 0 deletions

12
pom.xml
View File

@@ -42,6 +42,11 @@
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId> <artifactId>druid-spring-boot-starter</artifactId>
@@ -185,6 +190,13 @@
<version>30.1-jre</version> <version>30.1-jre</version>
</dependency> </dependency>
<dependency>
<groupId>com.thomsonreuters.ema</groupId>
<artifactId>ema</artifactId>
<version>3.5.1.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -0,0 +1,32 @@
package cn.stock.market.dto;
import lombok.Builder;
import lombok.Data;
/**
* @author gs
* @date 2024/4/9 10:53
*/
@Data
@Builder
/**
* RetifiveStockInfo类用于存储股票信息。
* 该类包含了股票的基本信息和交易数据。
*/
public class RetifiveStockInfo {
private String stockCode; // 股票代码
private String symbol; // 交易代码
private String stockName; // 股票名称
private String stockType; // 股票类型
private String currentPrice; // 当前价格
private String changePercent; // 变动百分比
private String openPrice; // 开盘价格
private String previousPrice; // 昨日收盘价格
private String volume; // 成交量
private String highPrice; // 最高价格
private String lowPrice; // 最低价格
private String week52HighPrice; // 52周最高价格
private String week52LowPrice; // 52周最低价格
private String status;
}

View File

@@ -0,0 +1,84 @@
package cn.stock.market.listener;
import com.thomsonreuters.ema.access.AckMsg;
import com.thomsonreuters.ema.access.EmaFactory;
import com.thomsonreuters.ema.access.GenericMsg;
import com.thomsonreuters.ema.access.Msg;
import com.thomsonreuters.ema.access.OmmConsumer;
import com.thomsonreuters.ema.access.OmmConsumerClient;
import com.thomsonreuters.ema.access.OmmConsumerConfig;
import com.thomsonreuters.ema.access.OmmConsumerEvent;
import com.thomsonreuters.ema.access.RefreshMsg;
import com.thomsonreuters.ema.access.ReqMsg;
import com.thomsonreuters.ema.access.StatusMsg;
import com.thomsonreuters.ema.access.UpdateMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@Service
@Slf4j
public class AppClient implements OmmConsumerClient {
private CompletableFuture<RefreshMsg> messageFuture = new CompletableFuture<>();
private OmmConsumer consumer;
@Autowired
public AppClient(OmmConsumer consumer) {
this.consumer = consumer;
}
// 根据itemName进行订阅的方法
public void subscribe(String itemName) {
resetMessageFuture(); // 重置Future以便新的请求
ReqMsg reqMsg = EmaFactory.createReqMsg().serviceName("ELEKTRON_DD").name(itemName);
consumer.registerClient(reqMsg, this);
}
public CompletableFuture<RefreshMsg> getMessageFuture() {
return messageFuture;
}
private void resetMessageFuture() {
this.messageFuture = new CompletableFuture<>();
}
@Override
public void onRefreshMsg(RefreshMsg refreshMsg, OmmConsumerEvent event) {
log.error("监听的消息:"+refreshMsg.toString());
messageFuture.complete(refreshMsg);
}
@Override
public void onUpdateMsg(UpdateMsg updateMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onStatusMsg(StatusMsg statusMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onGenericMsg(GenericMsg genericMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onAckMsg(AckMsg ackMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onAllMsg(Msg msg, OmmConsumerEvent consumerEvent) {
}
// 其他消息处理...
}

View File

@@ -0,0 +1,75 @@
package cn.stock.market.listener;
import com.thomsonreuters.ema.access.AckMsg;
import com.thomsonreuters.ema.access.EmaFactory;
import com.thomsonreuters.ema.access.GenericMsg;
import com.thomsonreuters.ema.access.Msg;
import com.thomsonreuters.ema.access.OmmConsumer;
import com.thomsonreuters.ema.access.OmmConsumerClient;
import com.thomsonreuters.ema.access.OmmConsumerEvent;
import com.thomsonreuters.ema.access.RefreshMsg;
import com.thomsonreuters.ema.access.ReqMsg;
import com.thomsonreuters.ema.access.StatusMsg;
import com.thomsonreuters.ema.access.UpdateMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author gs
* @date 2024/4/8 22:01
*/
@Service
public class ConcurrentAppClient implements OmmConsumerClient {
private final ConcurrentHashMap<String, CompletableFuture<RefreshMsg>> futures = new ConcurrentHashMap<>();
private OmmConsumer consumer;
@Autowired
public ConcurrentAppClient(OmmConsumer consumer) {
this.consumer = consumer;
}
public CompletableFuture<RefreshMsg> subscribe(String itemName) {
CompletableFuture<RefreshMsg> future = new CompletableFuture<>();
futures.put(itemName, future);
ReqMsg reqMsg = EmaFactory.createReqMsg().serviceName("ELEKTRON_DD").name(itemName);
consumer.registerClient(reqMsg, this);
return future;
}
@Override
public void onRefreshMsg(RefreshMsg refreshMsg, OmmConsumerEvent event) {
String itemName = refreshMsg.name();
CompletableFuture<RefreshMsg> future = futures.remove(itemName);
if (future != null) {
future.complete(refreshMsg);
}
}
@Override
public void onUpdateMsg(UpdateMsg updateMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onStatusMsg(StatusMsg statusMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onGenericMsg(GenericMsg genericMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onAckMsg(AckMsg ackMsg, OmmConsumerEvent consumerEvent) {
}
@Override
public void onAllMsg(Msg msg, OmmConsumerEvent consumerEvent) {
}
}

View File

@@ -0,0 +1,898 @@
<?xml version="1.0" encoding="UTF-8"?>
<EmaConfig>
<!-- ConsumerGroup provides set of detailed configurations to be used by named consumers -->
<!-- Application specifies which configuration to use by setting OmmConsumerConfig::consumerName() -->
<ConsumerGroup>
<!-- DefaultConsumer parameter defines which consumer configuration is used by OmmConsumer -->
<!-- if application does not specify it through OmmConsumerConfig::consumerName() -->
<!-- first consumer on the ConsumerList is a DefaultConsumer if this parameter is not specified -->
<DefaultConsumer value="Consumer_1"/>
<ConsumerList>
<Consumer>
<!-- Name is mandatory -->
<Name value="Consumer_1"/>
<!-- Channel is optional: defaulted to "RSSL_SOCKET + localhost + 14002" -->
<!-- Channel or ChannelSet may be specified -->
<Channel value="Channel_1"/>
<!-- Dictionary is optional: defaulted to "ChannelDictionary" -->
<Dictionary value="Dictionary_1"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<Name value="Consumer_2"/>
<!-- ChannelSet specifies an ordered list of Channels to which OmmConsumer will attempt to -->
<!-- connect, one at a time, if the previous one fails to connect -->
<ChannelSet value="Channel_1, Channel_2"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<Name value="Consumer_3"/>
<!-- Channel set to "RSSL_ENCRYPTED" -->
<Channel value="Channel_3"/>
<!-- Dictionary is optional: defaulted to "ChannelDictionary" -->
<Dictionary value="Dictionary_1"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<Name value="Consumer_4"/>
<Channel value="Channel_4"/>
<Dictionary value="Dictionary_1"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<!-- Channel is specified to provide RSSL_WEBSOCKET connection options -->
<Name value="Consumer_5"/>
<Channel value="Channel_5"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
<DefaultServiceID value="1"/>
</Consumer>
<Consumer>
<!-- Name is mandatory -->
<Name value="Consumer_6"/>
<Channel value="Channel_6"/>
<!-- Dictionary is optional: defaulted to "ChannelDictionary" -->
<Dictionary value="Dictionary_1"/>
<XmlTraceToStdout value="0"/>
<DefaultServiceID value="1"/>
</Consumer>
<!-- Consumer with enabled RTT feature -->
<Consumer>
<Name value="Consumer_7"/>
<Channel value="Channel_1"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
<DefaultServiceID value="1"/>
<EnableRtt value="1"/>
</Consumer>
<!-- Consumer for warm standby feature -->
<Consumer>
<Name value="Consumer_8"/>
<WarmStandbyChannelSet value="WarmStandbyChannel_1"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<!-- Performance tools consumers -->
<Consumer>
<Name value="Perf_Consumer_1"/>
<Channel value="Perf_Channel_1"/>
<Dictionary value="Dictionary_1"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
</Consumer>
<Consumer>
<Name value="Perf_Consumer_WSJSON_1"/>
<Channel value="Perf_Channel_WSJSON_1"/>
<Dictionary value="Dictionary_2"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
</Consumer>
<Consumer>
<Name value="Perf_Consumer_WSRWF_1"/>
<Channel value="Perf_Channel_WSRWF_1"/>
<Dictionary value="Dictionary_1"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
</Consumer>
<Consumer>
<Name value="Consumer_RRTViewer_SE"/>
<Channel value="Channel_RRTViewer_SE"/>
<Dictionary value="Dictionary_1"/>
<!-- 'XmlTraceToStdout == 1' is required for proper working of 'Debug' mode in RRTViewer -->
<!-- If XmlTraceToStdout set into '0', 'debug' mode will print only EMA logs. -->
<XmlTraceToStdout value="1"/>
</Consumer>
<Consumer>
<Name value="Consumer_RRTViewer_DE"/>
<Channel value="Channel_RRTViewer_DE"/>
<Dictionary value="Dictionary_1"/>
<!-- 'XmlTraceToStdout == 1' is required for proper working of 'Debug' mode in RRTViewer -->
<!-- If XmlTraceToStdout set into '0', 'debug' mode will print only EMA logs. -->
<XmlTraceToStdout value="1"/>
</Consumer>
</ConsumerList>
</ConsumerGroup>
<!-- NiProviderGroup provides set of detailed configurations to be used by named providers -->
<!-- Application specifies which configuration to use by setting OmmNiProviderConfig::providerName() -->
<NiProviderGroup>
<!-- DefaultNiProvider parameter defines which provider configuration is used by OmmProvider -->
<!-- if application does not specify it through OmmNiProviderConfig::providerName() -->
<!-- first provider on the NiProviderList is a DefaultNiProvider if this parameter is not specified -->
<DefaultNiProvider value="Provider_1"/>
<NiProviderList>
<!-- Regular providers -->
<NiProvider>
<!-- Name is mandatory -->
<Name value="Provider_1"/>
<!-- Channel is optional: defaulted to "RSSL_SOCKET + localhost + 14003" -->
<Channel value="Channel_7"/>
<!-- Directory is optional. -->
<!-- the EMA provides hardcoded directory containing a single service named "NI_PUB". -->
<!-- the EMA defaults the OmmNiProviderConfig::adminControlDirectory() to ApiControlEnum.-->
<!-- the applications may just use the hardcoded "NI_PUB" service to publish all the items.-->
<!-- if desired, a custom directory may be configured, named and used instead of the -->
<!-- hardcoded one. Please see examples in the DirectoryGroup.-->
<!-- the directory may also be specified using OmmNiProviderConfig::addAdminMsg(). -->
<!-- if desired the OmmNiProviderConfig::adminControlDirectory() to UserControlEnum -->
<!-- which allows applications to specify and control the directory. -->
<Directory value="Directory_1"/>
<XmlTraceToStdout value="0"/>
</NiProvider>
<NiProvider>
<Name value="Provider_2"/>
<Channel value="Channel_6"/>
<Directory value="Directory_2"/>
<XmlTraceToStdout value="0"/>
</NiProvider>
<NiProvider>
<Name value="Provider_3"/>
<Channel value="Channel_6"/>
<Directory value="Directory_3"/>
</NiProvider>
<NiProvider>
<Name value="Provider_4"/>
<Channel value="Channel_7"/>
<Directory value="Directory_1"/>
<XmlTraceToStdout value="0"/>
</NiProvider>
<!-- Performance tools niprovider -->
<NiProvider>
<Name value="Perf_NIProvider_1"/>
<Channel value="Perf_NIP_Channel_1"/>
<Directory value="Perf_Directory_1"/>
<XmlTraceToStdout value="0"/>
<ItemCountHint value="100000"/>
<MaxDispatchCountApiThread value="500"/>
<MaxDispatchCountUserThread value="500"/>
</NiProvider>
</NiProviderList>
</NiProviderGroup>
<!-- IProviderGroup provides set of detailed configurations to be used by named providers -->
<!-- Application specifies which configuration to use by setting OmmIProviderConfig::providerName() -->
<IProviderGroup>
<!-- DefaultIProvider parameter defines which provider configuration is used by OmmProvider -->
<!-- if application does not specify it through OmmIProviderConfig::providerName() -->
<!-- first provider on the IProviderList is a default provider if this parameter is not specified -->
<DefaultIProvider value="Provider_1"/>
<IProviderList>
<IProvider>
<!-- Name is mandatory -->
<Name value="Provider_1"/>
<!-- Server is optional: defaulted to "RSSL_SOCKET + 14002" -->
<Server value="Server_1"/>
<!-- Directory is optional: defaulted to AdminControl::UserControlEnum -->
<!-- source directory configuration to use if OmmIProviderConfig::adminModel() -->
<!-- was set to ApiControlEnum -->
<!-- this configuration also decides which dictionaries will be loaded at startup -->
<!-- this configuration may be overwritten by OmmIProviderConfig::addAdminMsg() -->
<Directory value="Directory_2"/>
<ItemCountHint value="10000"/>
<ServiceCountHint value="10000" />
<DispatchTimeoutApiThread value="500" />
<MaxDispatchCountApiThread value="500" />
<MaxDispatchCountUserThread value="500" />
<PipePort value="9009" />
<RefreshFirstRequired value="1" />
</IProvider>
<IProvider>
<!-- Name is mandatory -->
<Name value="Provider_3"/>
<!-- Server is optional: now it specifies RSSL_WEBSOCKET connection options -->
<Server value="Server_2"/>
<!-- Directory is optional: defaulted to AdminControl::UserControlEnum -->
<!-- source directory configuration to use if OmmIProviderConfig::adminModel() -->
<!-- was set to ApiControlEnum -->
<!-- this configuration also decides which dictionaries will be loaded at startup -->
<!-- this configuration may be overwritten by OmmIProviderConfig::addAdminMsg() -->
<Directory value="Directory_2"/>
<ItemCountHint value="10000"/>
<ServiceCountHint value="10000" />
<DispatchTimeoutApiThread value="500" />
<MaxDispatchCountApiThread value="500" />
<MaxDispatchCountUserThread value="500" />
<PipePort value="9009" />
<RefreshFirstRequired value="1" />
<SendJsonConvError value="1" />
</IProvider>
<IProvider>
<!-- Name is mandatory -->
<Name value="EncryptedProvider"/>
<!-- Server is optional: defaulted to "RSSL_SOCKET + 14002" -->
<Server value="EncryptedServer"/>
<!-- Directory is optional: defaulted to AdminControl::UserControlEnum -->
<!-- source directory configuration to use if OmmIProviderConfig::adminModel() -->
<!-- was set to ApiControlEnum -->
<!-- this configuration also decides which dictionaries will be loaded at startup -->
<!-- this configuration may be overwritten by OmmIProviderConfig::addAdminMsg() -->
<Directory value="Directory_2"/>
<ItemCountHint value="10000"/>
<ServiceCountHint value="10000" />
<DispatchTimeoutApiThread value="500" />
<MaxDispatchCountApiThread value="500" />
<MaxDispatchCountUserThread value="500" />
<PipePort value="9009" />
<RefreshFirstRequired value="1" />
</IProvider>
<!-- Performance tools provider -->
<IProvider>
<Name value="Perf_Provider_1"/>
<Server value="Perf_Server_1"/>
<Directory value="Directory_2"/>
<ItemCountHint value="100000"/>
<ServiceCountHint value="10000"/>
<DispatchTimeoutApiThread value="5000" />
<MaxDispatchCountApiThread value="10"/>
<MaxDispatchCountUserThread value="6500"/>
<RefreshFirstRequired value="1"/>
<XmlTraceToStdout value="0"/>
</IProvider>
</IProviderList>
</IProviderGroup>
<ChannelGroup>
<ChannelList>
<Channel>
<Name value="Channel_1"/>
<!-- ChannelType possible values are: -->
<!-- ChannelType::RSSL_SOCKET - TCP IP connection type -->
<!-- ChannelType::RSSL_HTTP - Http tunnel connection type -->
<!-- ChannelType::RSSL_ENCRYPTED - Https tunnel connection type -->
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<!-- CompressionType is optional: defaulted to None -->
<!-- possible values: None, ZLib, LZ4 -->
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- ConnectionPingTimeout is optional: defaulted to 30000 -->
<ConnectionPingTimeout value="30000"/>
<!-- TcpNodelay is optional: defaulted to 1 -->
<!-- possible values: 1 (tcp_nodelay option set), 0 (tcp_nodelay not set) -->
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Channel_2"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Channel_3"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_4"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- EMA discovers a host and a port from RDP service discovery for the specified location
when both of them are not set and the session management is enable. -->
<Location value="us-east-1"/>
<EnableSessionManagement value="1"/>
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_5"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- EMA discovers a host and a port from RDP service discovery for the specified location
when both of them are not set and the session management is enable. -->
<Location value="us-east-1"/>
<EnableSessionManagement value="1"/>
<EncryptedProtocolType value="EncryptedProtocolType::RSSL_WEBSOCKET"/>
<WsMaxMsgSize value="61440"/>
<WsProtocols value="tr_json2"/>
</Channel>
<Channel>
<Name value="Channel_6"/>
<ChannelType value="ChannelType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="15000"/>
<WsMaxMsgSize value="61440"/>
<WsProtocols value="rssl.json.v2, rssl.rwf, tr_json2"/>
</Channel>
<Channel>
<Name value="Channel_7"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14003"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_8"/>
<ChannelType value="ChannelType::RSSL_HTTP"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="14003"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_9"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="14003"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_RRTViewer_SE"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Channel_RRTViewer_DE"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- EMA discovers a host and a port from RDP service discovery for the specified location
when both of them are not set and the session management is enable. -->
<Location value="us-east-1"/>
<EnableSessionManagement value="1"/>
<ObjectName value=""/>
</Channel>
<!--Performance tools channels -->
<Channel>
<Name value="Perf_Channel_1"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<NumInputBuffers value="2048"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Perf_Channel_WSJSON_1"/>
<ChannelType value="ChannelType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="50000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<DirectWrite value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
<WsMaxMsgSize value="18432"/>
<WsProtocols value="rssl.json.v2"/>
</Channel>
<Channel>
<Name value="Perf_Channel_WSRWF_1"/>
<ChannelType value="ChannelType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<DirectWrite value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
<WsProtocols value="rssl.rwf"/>
</Channel>
<Channel>
<Name value="Perf_NIP_Channel_1"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<GuaranteedOutputBuffers value="100000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<DirectWrite value="1"/>
<Host value="localhost"/>
<Port value="14003"/>
<InterfaceName value=""/>
<HighWaterMark value="6144"/>
<NumInputBuffers value="10000"/>
<SysRecvBufSize value="65535"/>
<SysSendBufSize value="65535"/>
</Channel>
</ChannelList>
</ChannelGroup>
<ServerGroup>
<ServerList>
<Server>
<Name value="Server_1"/>
<ServerType value="ServerType::RSSL_SOCKET"/>
<!-- CompressionType is optional: defaulted to None -->
<!-- possible values: None, ZLib, LZ4 -->
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- ConnectionPingTimeout is optional: defaulted to 30000 -->
<ConnectionPingTimeout value="30000"/>
<!-- TcpNodelay is optional: defaulted to 1 -->
<!-- possible values: 1 (tcp_nodelay option set), 0 (tcp_nodelay not set) -->
<TcpNodelay value="1"/>
<Port value="14002"/>
</Server>
<Server>
<Name value="Server_2"/>
<!-- For WS connection server could use also RSSL_SOCKET type -->
<ServerType value="ServerType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Port value="15000"/>
<!-- There are optional and used for applying WS connection -->
<MaxFragmentSize value="6144"/>
<WsProtocols value="rssl.json.v2, rssl.rwf, tr_json2"/>
</Server>
<Server>
<Name value="EncryptedServer"/>
<ServerType value="ServerType::RSSL_ENCRYPTED"/>
<!-- CompressionType is optional: defaulted to None -->
<!-- possible values: None, ZLib, LZ4 -->
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- ConnectionPingTimeout is optional: defaulted to 30000 -->
<ConnectionPingTimeout value="30000"/>
<!-- TcpNodelay is optional: defaulted to 1 -->
<!-- possible values: 1 (tcp_nodelay option set), 0 (tcp_nodelay not set) -->
<TcpNodelay value="1"/>
<Port value="14002"/>
</Server>
<!--Performance tools server -->
<Server>
<Name value="Perf_Server_1"/>
<ServerType value="ServerType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<Port value="14002"/>
<HighWaterMark value="0"/>
<InterfaceName value=""/>
<DirectWrite value="1" />
<MaxFragmentSize value="6144"/>
<NumInputBuffers value="10000"/>
<SysRecvBufSize value="65535"/>
<SysSendBufSize value="65535"/>
</Server>
</ServerList>
</ServerGroup>
<WarmStandbyServerInfoGroup>
<WarmStandbyServerInfoList>
<WarmStandbyServerInfo>
<Name value="Server_Info_1"/>
<Channel value="Channel_1"/>
<PerServiceNameSet value=""/>
</WarmStandbyServerInfo>
<WarmStandbyServerInfo>
<Name value="Server_Info_2"/>
<Channel value="Channel_7"/>
<PerServiceNameSet value=""/>
</WarmStandbyServerInfo>
</WarmStandbyServerInfoList>
</WarmStandbyServerInfoGroup>
<WarmStandbyGroup>
<WarmStandbyList>
<WarmStandbyChannel>
<Name value="WarmStandbyChannel_1"/>
<StartingActiveServer value="Server_Info_1"/>
<StandbyServerSet value="Server_Info_2"/>
<WarmStandbyMode value="WarmStandbyMode::LOGIN_BASED"/>
</WarmStandbyChannel>
</WarmStandbyList>
</WarmStandbyGroup>
<!-- source directory refresh configuration used by provider -->
<DirectoryGroup>
<!-- DefaultDirectory specifies Directory used as default if providers do not specify Directory name -->
<DefaultDirectory value="Directory_1"/>
<DirectoryList>
<!-- providers refer to the Directory by name -->
<!-- Directory is a set of Services (one or more) on which a provider will provide item data -->
<Directory>
<Name value="Directory_1"/>
<Service>
<Name value="TEST_NI_PUB"/>
<InfoFilter>
<!-- optional value; if not specified EMA will assign it -->
<ServiceId value="11"/>
<!-- optional value -->
<Vendor value="company name"/>
<!-- possible values: 0 - means consolidation service, 1 - means original provider -->
<IsSource value="0"/>
<!-- an array of market domains supported by this service -->
<!-- domains defined in the RDM Usage Guide may be refered by name -->
<!-- names of the RDM defined domains are listed in the EmaRdm.h file -->
<!-- e.g. MMT_MARKET_PRICE, MMT_MARKET_BY_ORDER -->
<!-- note that the capabilities may be specified with names and or numbers -->
<Capabilities>
<CapabilitiesEntry value="MMT_MARKET_PRICE"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<!-- list of dictionary names specified in the DictionaryGroup -->
<!-- EMA will populate the Service::InfoFilter::DictionariesProvided element -->
<!-- with the respective <>ItemName values -->
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<!-- list of dictionary names specified in the DictionaryGroup -->
<!-- EMA will populate the Service::InfoFilter::DictionariesUsed element -->
<!-- with the respective <>ItemName values -->
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<!-- list of QoS values supported by this service -->
<!-- possible values are listed in the OmmQos.h file of the EMA -->
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="Timeliness::InexactDelayed"/>
<Rate value="Rate::JustInTimeConflated"/>
</QoSEntry>
</QoS>
<!-- 0 means does not support, 1 - means supports QoS range -->
<SupportsQoSRange value="0"/>
<!-- name of item list -->
<ItemList value="#.itemlist"/>
<!-- 0 means does not accept, 1 - means accepts consumer status -->
<AcceptingConsumerStatus value="0"/>
<!-- 0 means does not support, 1 - means supports out of band snapshots -->
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<!-- StateFilter is optional -->
<!-- EMA will default the values as follows: -->
<!-- for interactive provider -->
<!-- - ServiceState is "up" and AcceptingRequests is "Yes" -->
<!-- for non interactive provider -->
<!-- - ServiceState is "up" and AcceptingRequests is "No" -->
<StateFilter>
<!-- 0 means service is down, 1 - means service is up (default; 1) -->
<ServiceState value="1"/>
<!-- 0 means service does not accept, 1 - means service accepts (default; 1) -->
<AcceptingRequests value="1"/>
<!-- optional; specifies status change to apply to all items provided by this service -->
<!-- possible values are listed in the OmmState.h file of the EMA -->
<Status>
<!-- possible values are: Open, Close, CloseRecover -->
<StreamState value="StreamState::Open"/>
<!-- possibe values are: NoChange, Ok, Suspect -->
<DataState value="DataState::Ok"/>
<!-- possible values are: None, DacsDown, etc -->
<StatusCode value="StatusCode::None"/>
<!-- a text field -->
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
<Service>
<Name value="NI_PUB"/>
<InfoFilter>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
<Status>
<StreamState value="StreamState::Open"/>
<DataState value="DataState::Ok"/>
<StatusCode value="StatusCode::None"/>
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Directory_2"/>
<Service>
<Name value="DIRECT_FEED"/>
<InfoFilter>
<ServiceId value="1"/>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
<CapabilitiesEntry value="MMT_MARKET_BY_PRICE"/>
<CapabilitiesEntry value="MMT_DICTIONARY"/>
<CapabilitiesEntry value="200"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="100"/>
<Rate value="100"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Directory_3"/>
<Service>
<Name value="TEST_NI_PUB"/>
<InfoFilter>
<ServiceId value="11"/>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="MMT_MARKET_PRICE"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="Timeliness::InexactDelayed"/>
<Rate value="Rate::JustInTimeConflated"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
<Status>
<StreamState value="StreamState::Open"/>
<DataState value="DataState::Ok"/>
<StatusCode value="StatusCode::None"/>
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
<Service>
<Name value="NI_PUB"/>
<InfoFilter>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
<Status>
<StreamState value="StreamState::Open"/>
<DataState value="DataState::Ok"/>
<StatusCode value="StatusCode::None"/>
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Directory_4"/>
<Service>
<Name value="DIRECT_FEED"/>
<InfoFilter>
<ServiceId value="1"/>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
<CapabilitiesEntry value="MMT_MARKET_BY_PRICE"/>
<CapabilitiesEntry value="MMT_DICTIONARY"/>
<CapabilitiesEntry value="200"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="100"/>
<Rate value="100"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Perf_Directory_1"/>
<Service>
<Name value="NI_PUB"/>
<InfoFilter>
<ServiceId value="1"/>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="RefinitivDevTestLab"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="MMT_DICTIONARY"/>
<CapabilitiesEntry value="MMT_MARKET_PRICE"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
<CapabilitiesEntry value="MMT_MARKET_BY_PRICE"/>
<CapabilitiesEntry value="200"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="100"/>
<Rate value="100"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
</StateFilter>
</Service>
</Directory>
</DirectoryList>
</DirectoryGroup>
<DictionaryGroup>
<DictionaryList>
<Dictionary>
<Name value="Dictionary_1"/>
<!-- dictionaryType is optional: defaulted to ChannelDictionary" -->
<!-- possible values: ChannelDictionary, FileDictionary -->
<!-- if dictionaryType is set to ChannelDictionary, file names are ignored -->
<DictionaryType value="DictionaryType::ChannelDictionary"/>
</Dictionary>
<Dictionary>
<Name value="Dictionary_2"/>
<DictionaryType value="DictionaryType::FileDictionary"/>
<!-- dictionary names are optional: defaulted to RDMFieldDictionary and enumtype.def -->
<RdmFieldDictionaryFileName value="./RDMFieldDictionary"/>
<EnumTypeDefFileName value="./enumtype.def"/>
</Dictionary>
<Dictionary>
<Name value="Dictionary_3"/>
<!-- providers always assume DictionaryType = DictionaryType::FileDictionary -->
<DictionaryType value="DictionaryType::FileDictionary"/>
<!-- dictionary file names are optional: defaulted to ./RDMFieldDictionary and ./enumtype.def -->
<RdmFieldDictionaryFileName value="./RDMFieldDictionary"/>
<EnumTypeDefFileName value="./enumtype.def"/>
<!-- <dictionary>ItemName represents the names shown in DictionariesProvided and DictionariesUsed
elements of the Directory InfoFilter -->
<!-- <dictionary>ItemName is optional; default values are "RWFFld" for the RdmFieldDictionary
and "RWFEnum" for the enumtype.def -->
<RdmFieldDictionaryItemName value="RWFFld"/>
<EnumTypeDefItemName value="RWFEnum"/>
</Dictionary>
</DictionaryList>
</DictionaryGroup>
</EmaConfig>

View File

@@ -0,0 +1,25 @@
package cn.stock.market.listener;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
@Configuration
public class MongoConfig {
@Bean
public MongoClient mongoClient() {
// 连接到MongoDB服务器示例中使用默认的MongoDB端口
// 请根据你的实际情况修改这里的连接字符串
return MongoClients.create("mongodb://root:123456@localhost:27017");
}
@Bean
public MongoTemplate mongoTemplate() {
// 创建并返回MongoTemplate的实例需要提供MongoClient实例和数据库名
// 替换"yourDatabase"为你的数据库名
return new MongoTemplate(mongoClient(), "company");
}
}

View File

@@ -0,0 +1,36 @@
package cn.stock.market.listener;
import com.thomsonreuters.ema.access.EmaFactory;
import com.thomsonreuters.ema.access.OmmConsumer;
import com.thomsonreuters.ema.access.OmmConsumerConfig;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class MyAppRunner implements ApplicationRunner {
static String userName = "GE-A-10288435-3-15856";
static String password = "8EyCWDQ%XITcGRM@RhKokxX05FZJe1";
static String clientId = "662b37b071144c9f8f2507d93037a019a010ae0e";
@Override
public void run(ApplicationArguments args) throws Exception {
// 在这里写入您的初始化代码
System.out.println("应用已启动,执行初始化代码...");
// The "Consumer_4" uses EncryptedProtocolType::RSSL_SOCKET while the "Consumer_5" uses EncryptedProtocolType::RSSL_WEBSOCKET predefined in EmaConfig.xml
}
@Bean
public OmmConsumer getOmmConsumer() {
OmmConsumer consumer = null;
OmmConsumerConfig config = EmaFactory.createOmmConsumerConfig();
config.username(userName);
config.password(password);
config.clientId(clientId);
consumer = EmaFactory.createOmmConsumer(config.consumerName( "Consumer_4"));
return consumer;
}
}

View File

@@ -0,0 +1,22 @@
package cn.stock.market.listener;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @author gs
* @date 2024/4/8 21:00
*/
@Document("stock_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StockInfoRefinitiv {
private String stockName;
private String stockCode;
private String stockType;
private String status;
private String commandStr;
}

View File

@@ -0,0 +1,19 @@
package cn.stock.market.listener;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @author gs
* @date 2024/4/8 17:20
*/
@Data
@AllArgsConstructor
@Document("symbol")
public class SymbolRefinitiv {
private String symbol;
private String stockType;
private String commandStr;
}

View File

@@ -0,0 +1,488 @@
package cn.stock.market.web;
import cn.stock.market.dto.RetifiveStockInfo;
import cn.stock.market.listener.AppClient;
import cn.stock.market.listener.ConcurrentAppClient;
import cn.stock.market.listener.StockInfoRefinitiv;
import cn.stock.market.listener.SymbolRefinitiv;
import cn.stock.market.utils.ServerResponse;
import com.google.common.collect.Lists;
import com.thomsonreuters.ema.access.DataType;
import com.thomsonreuters.ema.access.FieldEntry;
import com.thomsonreuters.ema.access.FieldList;
import com.thomsonreuters.ema.access.Map;
import com.thomsonreuters.ema.access.MapEntry;
import com.thomsonreuters.ema.access.RefreshMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@RestController
@Slf4j
@RequestMapping("/retifive/**")
public class MessageRetifiveController {
@Autowired
private AppClient appClient;
@Autowired
private ConcurrentAppClient concurrentAppClient;
@Autowired
private MongoTemplate mongoTemplate;
@GetMapping("/message")
public ServerResponse<?> getMessage(@RequestParam String itemName) {
RefreshMsg refreshMsg = null;
try {
appClient.subscribe(itemName); // 根据itemName订阅
// 等待消息
refreshMsg = appClient.getMessageFuture().get(10, TimeUnit.SECONDS);// 设置超时时间例如10秒
return ServerResponse.createBySuccess("操作成功",refreshMsg.toString());
} catch (Exception e) {
return ServerResponse.createByError();
}
}
@GetMapping("/getStockSymbolList")
public ServerResponse<?> getStockList() {
RefreshMsg refreshMsg = null;
List<String> itemNameList = generateItemNames();
String nextLink = "";
for (String itemName : itemNameList) {
try {
appClient.subscribe(itemName); // 根据itemName订阅
// 等待消息
refreshMsg = appClient.getMessageFuture().get(10, TimeUnit.SECONDS);// 设置超时时间例如10秒
System.out.println(refreshMsg.name());
if (DataType.DataTypes.FIELD_LIST == refreshMsg.payload().dataType()){
nextLink = decode1(refreshMsg.payload().fieldList(),refreshMsg.name());
while (StringUtils.isNotBlank(nextLink)&&!nextLink.contains("blank data")){
appClient.subscribe(nextLink); // 根据itemName订阅
// 等待消息
refreshMsg = appClient.getMessageFuture().get(10, TimeUnit.SECONDS);// 设置超时时间例如10秒
nextLink = decode1(refreshMsg.payload().fieldList(),refreshMsg.name());
}
}
} catch (Exception e) {
log.error("获取列表异常link:"+nextLink,e);
return ServerResponse.createByError();
}
}
return ServerResponse.createBySuccess("操作成功");
}
/* @GetMapping("/getStockInfoList")
@Deprecated
public ServerResponse<?> getStockInfoList() {
ExecutorService executorService = Executors.newFixedThreadPool(5); // 创建一个固定大小的线程池
List<SymbolRefinitiv> collect = mongoTemplate.query(SymbolRefinitiv.class).stream().collect(Collectors.toList());
List<StockInfoRefinitiv> collect2 = mongoTemplate.query(StockInfoRefinitiv.class).stream().collect(Collectors.toList());
List<SymbolRefinitiv> difference = collect.stream()
.filter(symbol -> collect2.stream()
.noneMatch(stockInfo -> stockInfo.getCommandStr().equals(symbol.getSymbol())))
.collect(Collectors.toList());
List<String> itemNameList = difference.stream().map(SymbolRefinitiv::getSymbol).collect(Collectors.toList());
// 计算每个线程应处理的元素数量
int size = itemNameList.size();
int chunkSize = size / 5; // 假设列表可以均匀分配
for (int i = 0; i < 5; i++) {
int start = i * chunkSize;
int end = (i == 4) ? size : (start + chunkSize); // 最后一个线程可能需要处理更多的元素
List<String> sublist = itemNameList.subList(start, end);
// 将子列表的处理提交给线程池
executorService.submit(() -> {
for (String itemName : sublist) {
try {
CompletableFuture<RefreshMsg> future = concurrentAppClient.subscribe(itemName);
RefreshMsg refreshMsg = future.get(10, TimeUnit.SECONDS);
if (DataType.DataTypes.FIELD_LIST == refreshMsg.payload().dataType()){
// List<FieldEntry> safeList = Collections.synchronizedList(new ArrayList<>(refreshMsg.payload().fieldList()));
decode2(refreshMsg.payload().fieldList(),refreshMsg.name());
}
} catch (Exception e) {
log.error("获取列表异常link:"+itemName,e);
}
}
});
}
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException ie) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
return ServerResponse.createBySuccess("操作成功");
}*/
@GetMapping("/getStockInfoList2")
public ServerResponse<?> getStockInfoList2() {
List<String> collect = mongoTemplate.query(SymbolRefinitiv.class).stream().map(SymbolRefinitiv::getSymbol).collect(Collectors.toList());
// 计算每个线程应处理的元素数量
for (String itemName : collect) {
try {
appClient.subscribe(itemName); // 根据itemName订阅
// 等待消息
RefreshMsg refreshMsg = appClient.getMessageFuture().get(10, TimeUnit.SECONDS);// 设置超时时间例如10秒
if (DataType.DataTypes.FIELD_LIST == refreshMsg.payload().dataType()){
// List<FieldEntry> safeList = Collections.synchronizedList(new ArrayList<>(refreshMsg.payload().fieldList()));
decode2(refreshMsg.payload().fieldList(),refreshMsg.name());
}
} catch (Exception e) {
log.error("获取列表异常link:"+itemName,e);
}
}
return ServerResponse.createBySuccess("操作成功");
}
@GetMapping("/getStockDetail")
public ServerResponse<?> getStockInfoList2(String itemName) {
// 计算每个线程应处理的元素数量
try {
appClient.subscribe(itemName); // 根据itemName订阅
// 等待消息
RefreshMsg refreshMsg = appClient.getMessageFuture().get(10, TimeUnit.SECONDS);// 设置超时时间例如10秒
if (DataType.DataTypes.FIELD_LIST == refreshMsg.payload().dataType()){
RetifiveStockInfo retifiveStockInfo = decode3(refreshMsg.payload().fieldList(), refreshMsg.name());
return ServerResponse.createBySuccess("操作成功",retifiveStockInfo);
}
} catch (Exception e) {
log.error("获取股票详情link:"+itemName,e);
}
return ServerResponse.createBySuccess("操作成功");
}
@GetMapping("/getStockDetailList")
public ServerResponse<?> getStockDetailList(String itemName) {
// 计算每个线程应处理的元素数量
String[] itemNames = itemName.split(",");
List<RetifiveStockInfo> list = Lists.newArrayList();
for (String name : itemNames) {
try {
appClient.subscribe(name); // 根据itemName订阅
// 等待消息
RefreshMsg refreshMsg = appClient.getMessageFuture().get(10, TimeUnit.SECONDS);// 设置超时时间例如10秒
if (DataType.DataTypes.FIELD_LIST == refreshMsg.payload().dataType()){
RetifiveStockInfo retifiveStockInfo = decode3(refreshMsg.payload().fieldList(), refreshMsg.name());
list.add(retifiveStockInfo);
}
} catch (Exception e) {
log.error("获取股票详情link:"+name,e);
}
}
return ServerResponse.createBySuccess("操作成功",list);
}
/* void decode(FieldList fieldList)
{
for (FieldEntry fieldEntry : fieldList)
{
System.out.print("Fid: " + fieldEntry.fieldId() + " Name = " + fieldEntry.name() + " DataType: " + DataType.asString(fieldEntry.load().dataType()) + " Value: ");
if (Data.DataCode.BLANK == fieldEntry.code())
System.out.println(" blank");
else
switch (fieldEntry.loadType())
{
case DataType.DataTypes.REAL :
System.out.println(fieldEntry.real().asDouble());
break;
case DataType.DataTypes.DATE :
System.out.println(fieldEntry.date().day() + " / " + fieldEntry.date().month() + " / " + fieldEntry.date().year());
break;
case DataType.DataTypes.TIME :
System.out.println(fieldEntry.time().hour() + " / " + fieldEntry.time().minute() + " / " + fieldEntry.time().second() + fieldEntry.time().millisecond());
break;
case DataType.DataTypes.INT :
System.out.println(fieldEntry.intValue());
break;
case DataType.DataTypes.UINT :
System.out.println(fieldEntry.uintValue());
break;
case DataType.DataTypes.ASCII :
System.out.println(fieldEntry.ascii());
break;
case DataType.DataTypes.ENUM :
System.out.println(fieldEntry.hasEnumDisplay() ? fieldEntry.enumDisplay() : fieldEntry.enumValue());
break;
case DataType.DataTypes.RMTES :
System.out.println(fieldEntry.rmtes());
break;
case DataType.DataTypes.ERROR :
System.out.println("(" + fieldEntry.error().errorCodeAsString() + ")");
break;
default :
System.out.println();
break;
}
}
}*/
String decode1(FieldList fieldList,String name)
{
Iterator<FieldEntry> iter = fieldList.iterator();
FieldEntry fieldEntry;
String nextLink = "";
while (iter.hasNext())
{
fieldEntry = iter.next();
System.out.println("Fid: " + fieldEntry.fieldId() + " Name: " + fieldEntry.name() + " value: " + fieldEntry.load());
if(fieldEntry.name().startsWith("LINK_")){
if(fieldEntry.loadType() == DataType.DataTypes.ASCII){
String symbol = fieldEntry.load().toString();
if(!symbol.contains("blank data")){
mongoTemplate.insert(new SymbolRefinitiv(symbol,"bse",name));
}
}
}
if(fieldEntry.name().startsWith("NEXT_LR")){
nextLink = fieldEntry.load().toString();
if(nextLink.contains("blank data")){
break;
}
}
if(fieldEntry.name().startsWith("NEXT_LR")){
nextLink = fieldEntry.load().toString();
if(nextLink.contains("blank data")){
break;
}
}
String stockName = "";
if(fieldEntry.name().equals("DSPLY_NAME")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
stockName = fieldEntry.load().toString();
}
}
String stockCode = "";
if(fieldEntry.name().equals("PROV_SYMB")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
stockCode = fieldEntry.load().toString();
}
}
String status = "";
if(fieldEntry.name().equals("TRD_STATUS")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
status = fieldEntry.load().toString();
}
}
StockInfoRefinitiv stockInfoRefinitiv = new StockInfoRefinitiv();
stockInfoRefinitiv.setStockName(stockName);
stockInfoRefinitiv.setStockCode(stockCode);
stockInfoRefinitiv.setStatus(status);
stockInfoRefinitiv.setStockType("bse");
stockInfoRefinitiv.setCommandStr(name);
}
return nextLink;
}
synchronized void decode2(FieldList fieldList,String name)
{
List<FieldEntry> safeList = new CopyOnWriteArrayList<>();
for(FieldEntry fieldEntry : fieldList) {
safeList.add(fieldEntry); // 假设这里是安全的但实际上你可能需要根据FieldEntry的实现来确定
}
String stockName = "";
String stockCode = "";
String status = "";
for(FieldEntry fieldEntry : safeList)
{
System.out.println("Fid: " + fieldEntry.fieldId() + " Name: " + fieldEntry.name() + " value: " + fieldEntry.load());
if(fieldEntry.name().startsWith("LINK_")){
if(fieldEntry.loadType() == DataType.DataTypes.ASCII){
String symbol = fieldEntry.load().toString();
if(!symbol.contains("blank data")){
mongoTemplate.insert(new SymbolRefinitiv(symbol,"bse",name));
}
}
}
if(fieldEntry.name().equals("DSPLY_NAME")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
stockName = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("PROV_SYMB")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
stockCode = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("TRD_STATUS")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
status = fieldEntry.load().toString();
}
}
}
StockInfoRefinitiv stockInfoRefinitiv = new StockInfoRefinitiv();
stockInfoRefinitiv.setStockName(stockName);
stockInfoRefinitiv.setStockCode(stockCode);
stockInfoRefinitiv.setStatus(status);
stockInfoRefinitiv.setStockType("bse");
stockInfoRefinitiv.setCommandStr(name);
mongoTemplate.insert(stockInfoRefinitiv);
}
RetifiveStockInfo decode3(FieldList fieldList, String name)
{
Iterator<FieldEntry> iter = fieldList.iterator();
FieldEntry fieldEntry;
String stockName = "";
String stockCode = "";
String status = "";
String price = "";
String openPrice = "";
String previousPrice = "";
String percentChange = "";
String week52High ="";
String week52Low = "";
String high = "";
String low = "";
String volume = "";//实时交易数量
String stockType = "";
while (iter.hasNext())
{
fieldEntry = iter.next();
System.out.println("Fid: " + fieldEntry.fieldId() + " Name: " + fieldEntry.name() +" Unit: "+DataType.asString(fieldEntry.loadType()) + " value: " + fieldEntry.load());
if(fieldEntry.name().equals("DSPLY_NAME")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
stockName = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("PROV_SYMB")){
if(fieldEntry.loadType() == DataType.DataTypes.RMTES) {
stockCode = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("INST_PHASE")){
if(fieldEntry.loadType() == DataType.DataTypes.ENUM) {
status = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("OPEN_PRC")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
openPrice = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("HST_CLOSE")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
previousPrice = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("52WK_HIGH")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
week52High = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("52WK_LOW")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
week52Low = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("NETCHNG_1")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
percentChange = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("HIGH_1")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
high = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("LOW_1")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
low = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("IRGVOL")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
volume = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("TRDPRC_1")){
if(fieldEntry.loadType() == DataType.DataTypes.REAL) {
price = fieldEntry.load().toString();
}
}
if(fieldEntry.name().equals("RDN_EXCHID")){
if(fieldEntry.loadType() == DataType.DataTypes.ENUM) {
stockType = fieldEntry.load().toString();
if(StringUtils.equals(stockType,"145")){
stockType = "bse";//孟买国家交易所
}else if(StringUtils.equals(stockType,"147")){
stockType = "nse";//印度国家交易所
}
}
}
}
RetifiveStockInfo retifiveStockInfo = RetifiveStockInfo.builder().stockCode(stockCode).stockName(stockName).symbol(name).status(status)
.openPrice(openPrice).currentPrice(price).highPrice(high).lowPrice(low).previousPrice(previousPrice).changePercent(percentChange)
.volume(volume).week52HighPrice(week52High).week52LowPrice(week52Low).stockType(stockType)
.build();
return retifiveStockInfo;
}
private static List<String> generateItemNames() {
List<String> itemNames = new ArrayList<>();
// 从字母 'A' 到 'Z'
for (char letter = 'A'; letter <= 'Z'; letter++) {
String itemName = "0#" + letter + ".BO";
itemNames.add(itemName);
}
return itemNames;
}
}

View File

@@ -0,0 +1,898 @@
<?xml version="1.0" encoding="UTF-8"?>
<EmaConfig>
<!-- ConsumerGroup provides set of detailed configurations to be used by named consumers -->
<!-- Application specifies which configuration to use by setting OmmConsumerConfig::consumerName() -->
<ConsumerGroup>
<!-- DefaultConsumer parameter defines which consumer configuration is used by OmmConsumer -->
<!-- if application does not specify it through OmmConsumerConfig::consumerName() -->
<!-- first consumer on the ConsumerList is a DefaultConsumer if this parameter is not specified -->
<DefaultConsumer value="Consumer_1"/>
<ConsumerList>
<Consumer>
<!-- Name is mandatory -->
<Name value="Consumer_1"/>
<!-- Channel is optional: defaulted to "RSSL_SOCKET + localhost + 14002" -->
<!-- Channel or ChannelSet may be specified -->
<Channel value="Channel_1"/>
<!-- Dictionary is optional: defaulted to "ChannelDictionary" -->
<Dictionary value="Dictionary_1"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<Name value="Consumer_2"/>
<!-- ChannelSet specifies an ordered list of Channels to which OmmConsumer will attempt to -->
<!-- connect, one at a time, if the previous one fails to connect -->
<ChannelSet value="Channel_1, Channel_2"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<Name value="Consumer_3"/>
<!-- Channel set to "RSSL_ENCRYPTED" -->
<Channel value="Channel_3"/>
<!-- Dictionary is optional: defaulted to "ChannelDictionary" -->
<Dictionary value="Dictionary_1"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<Name value="Consumer_4"/>
<Channel value="Channel_4"/>
<Dictionary value="Dictionary_1"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<Consumer>
<!-- Channel is specified to provide RSSL_WEBSOCKET connection options -->
<Name value="Consumer_5"/>
<Channel value="Channel_5"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
<DefaultServiceID value="1"/>
</Consumer>
<Consumer>
<!-- Name is mandatory -->
<Name value="Consumer_6"/>
<Channel value="Channel_6"/>
<!-- Dictionary is optional: defaulted to "ChannelDictionary" -->
<Dictionary value="Dictionary_1"/>
<XmlTraceToStdout value="0"/>
<DefaultServiceID value="1"/>
</Consumer>
<!-- Consumer with enabled RTT feature -->
<Consumer>
<Name value="Consumer_7"/>
<Channel value="Channel_1"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
<DefaultServiceID value="1"/>
<EnableRtt value="1"/>
</Consumer>
<!-- Consumer for warm standby feature -->
<Consumer>
<Name value="Consumer_8"/>
<WarmStandbyChannelSet value="WarmStandbyChannel_1"/>
<Dictionary value="Dictionary_2"/>
<XmlTraceToStdout value="0"/>
</Consumer>
<!-- Performance tools consumers -->
<Consumer>
<Name value="Perf_Consumer_1"/>
<Channel value="Perf_Channel_1"/>
<Dictionary value="Dictionary_1"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
</Consumer>
<Consumer>
<Name value="Perf_Consumer_WSJSON_1"/>
<Channel value="Perf_Channel_WSJSON_1"/>
<Dictionary value="Dictionary_2"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
</Consumer>
<Consumer>
<Name value="Perf_Consumer_WSRWF_1"/>
<Channel value="Perf_Channel_WSRWF_1"/>
<Dictionary value="Dictionary_1"/>
<MaxDispatchCountApiThread value="6500"/>
<MaxDispatchCountUserThread value="6500"/>
</Consumer>
<Consumer>
<Name value="Consumer_RRTViewer_SE"/>
<Channel value="Channel_RRTViewer_SE"/>
<Dictionary value="Dictionary_1"/>
<!-- 'XmlTraceToStdout == 1' is required for proper working of 'Debug' mode in RRTViewer -->
<!-- If XmlTraceToStdout set into '0', 'debug' mode will print only EMA logs. -->
<XmlTraceToStdout value="1"/>
</Consumer>
<Consumer>
<Name value="Consumer_RRTViewer_DE"/>
<Channel value="Channel_RRTViewer_DE"/>
<Dictionary value="Dictionary_1"/>
<!-- 'XmlTraceToStdout == 1' is required for proper working of 'Debug' mode in RRTViewer -->
<!-- If XmlTraceToStdout set into '0', 'debug' mode will print only EMA logs. -->
<XmlTraceToStdout value="1"/>
</Consumer>
</ConsumerList>
</ConsumerGroup>
<!-- NiProviderGroup provides set of detailed configurations to be used by named providers -->
<!-- Application specifies which configuration to use by setting OmmNiProviderConfig::providerName() -->
<NiProviderGroup>
<!-- DefaultNiProvider parameter defines which provider configuration is used by OmmProvider -->
<!-- if application does not specify it through OmmNiProviderConfig::providerName() -->
<!-- first provider on the NiProviderList is a DefaultNiProvider if this parameter is not specified -->
<DefaultNiProvider value="Provider_1"/>
<NiProviderList>
<!-- Regular providers -->
<NiProvider>
<!-- Name is mandatory -->
<Name value="Provider_1"/>
<!-- Channel is optional: defaulted to "RSSL_SOCKET + localhost + 14003" -->
<Channel value="Channel_7"/>
<!-- Directory is optional. -->
<!-- the EMA provides hardcoded directory containing a single service named "NI_PUB". -->
<!-- the EMA defaults the OmmNiProviderConfig::adminControlDirectory() to ApiControlEnum.-->
<!-- the applications may just use the hardcoded "NI_PUB" service to publish all the items.-->
<!-- if desired, a custom directory may be configured, named and used instead of the -->
<!-- hardcoded one. Please see examples in the DirectoryGroup.-->
<!-- the directory may also be specified using OmmNiProviderConfig::addAdminMsg(). -->
<!-- if desired the OmmNiProviderConfig::adminControlDirectory() to UserControlEnum -->
<!-- which allows applications to specify and control the directory. -->
<Directory value="Directory_1"/>
<XmlTraceToStdout value="0"/>
</NiProvider>
<NiProvider>
<Name value="Provider_2"/>
<Channel value="Channel_6"/>
<Directory value="Directory_2"/>
<XmlTraceToStdout value="0"/>
</NiProvider>
<NiProvider>
<Name value="Provider_3"/>
<Channel value="Channel_6"/>
<Directory value="Directory_3"/>
</NiProvider>
<NiProvider>
<Name value="Provider_4"/>
<Channel value="Channel_7"/>
<Directory value="Directory_1"/>
<XmlTraceToStdout value="0"/>
</NiProvider>
<!-- Performance tools niprovider -->
<NiProvider>
<Name value="Perf_NIProvider_1"/>
<Channel value="Perf_NIP_Channel_1"/>
<Directory value="Perf_Directory_1"/>
<XmlTraceToStdout value="0"/>
<ItemCountHint value="100000"/>
<MaxDispatchCountApiThread value="500"/>
<MaxDispatchCountUserThread value="500"/>
</NiProvider>
</NiProviderList>
</NiProviderGroup>
<!-- IProviderGroup provides set of detailed configurations to be used by named providers -->
<!-- Application specifies which configuration to use by setting OmmIProviderConfig::providerName() -->
<IProviderGroup>
<!-- DefaultIProvider parameter defines which provider configuration is used by OmmProvider -->
<!-- if application does not specify it through OmmIProviderConfig::providerName() -->
<!-- first provider on the IProviderList is a default provider if this parameter is not specified -->
<DefaultIProvider value="Provider_1"/>
<IProviderList>
<IProvider>
<!-- Name is mandatory -->
<Name value="Provider_1"/>
<!-- Server is optional: defaulted to "RSSL_SOCKET + 14002" -->
<Server value="Server_1"/>
<!-- Directory is optional: defaulted to AdminControl::UserControlEnum -->
<!-- source directory configuration to use if OmmIProviderConfig::adminModel() -->
<!-- was set to ApiControlEnum -->
<!-- this configuration also decides which dictionaries will be loaded at startup -->
<!-- this configuration may be overwritten by OmmIProviderConfig::addAdminMsg() -->
<Directory value="Directory_2"/>
<ItemCountHint value="10000"/>
<ServiceCountHint value="10000" />
<DispatchTimeoutApiThread value="500" />
<MaxDispatchCountApiThread value="500" />
<MaxDispatchCountUserThread value="500" />
<PipePort value="9009" />
<RefreshFirstRequired value="1" />
</IProvider>
<IProvider>
<!-- Name is mandatory -->
<Name value="Provider_3"/>
<!-- Server is optional: now it specifies RSSL_WEBSOCKET connection options -->
<Server value="Server_2"/>
<!-- Directory is optional: defaulted to AdminControl::UserControlEnum -->
<!-- source directory configuration to use if OmmIProviderConfig::adminModel() -->
<!-- was set to ApiControlEnum -->
<!-- this configuration also decides which dictionaries will be loaded at startup -->
<!-- this configuration may be overwritten by OmmIProviderConfig::addAdminMsg() -->
<Directory value="Directory_2"/>
<ItemCountHint value="10000"/>
<ServiceCountHint value="10000" />
<DispatchTimeoutApiThread value="500" />
<MaxDispatchCountApiThread value="500" />
<MaxDispatchCountUserThread value="500" />
<PipePort value="9009" />
<RefreshFirstRequired value="1" />
<SendJsonConvError value="1" />
</IProvider>
<IProvider>
<!-- Name is mandatory -->
<Name value="EncryptedProvider"/>
<!-- Server is optional: defaulted to "RSSL_SOCKET + 14002" -->
<Server value="EncryptedServer"/>
<!-- Directory is optional: defaulted to AdminControl::UserControlEnum -->
<!-- source directory configuration to use if OmmIProviderConfig::adminModel() -->
<!-- was set to ApiControlEnum -->
<!-- this configuration also decides which dictionaries will be loaded at startup -->
<!-- this configuration may be overwritten by OmmIProviderConfig::addAdminMsg() -->
<Directory value="Directory_2"/>
<ItemCountHint value="10000"/>
<ServiceCountHint value="10000" />
<DispatchTimeoutApiThread value="500" />
<MaxDispatchCountApiThread value="500" />
<MaxDispatchCountUserThread value="500" />
<PipePort value="9009" />
<RefreshFirstRequired value="1" />
</IProvider>
<!-- Performance tools provider -->
<IProvider>
<Name value="Perf_Provider_1"/>
<Server value="Perf_Server_1"/>
<Directory value="Directory_2"/>
<ItemCountHint value="100000"/>
<ServiceCountHint value="10000"/>
<DispatchTimeoutApiThread value="5000" />
<MaxDispatchCountApiThread value="10"/>
<MaxDispatchCountUserThread value="6500"/>
<RefreshFirstRequired value="1"/>
<XmlTraceToStdout value="0"/>
</IProvider>
</IProviderList>
</IProviderGroup>
<ChannelGroup>
<ChannelList>
<Channel>
<Name value="Channel_1"/>
<!-- ChannelType possible values are: -->
<!-- ChannelType::RSSL_SOCKET - TCP IP connection type -->
<!-- ChannelType::RSSL_HTTP - Http tunnel connection type -->
<!-- ChannelType::RSSL_ENCRYPTED - Https tunnel connection type -->
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<!-- CompressionType is optional: defaulted to None -->
<!-- possible values: None, ZLib, LZ4 -->
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- ConnectionPingTimeout is optional: defaulted to 30000 -->
<ConnectionPingTimeout value="30000"/>
<!-- TcpNodelay is optional: defaulted to 1 -->
<!-- possible values: 1 (tcp_nodelay option set), 0 (tcp_nodelay not set) -->
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Channel_2"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Channel_3"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_4"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- EMA discovers a host and a port from RDP service discovery for the specified location
when both of them are not set and the session management is enable. -->
<Location value="us-east-1"/>
<EnableSessionManagement value="1"/>
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_5"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- EMA discovers a host and a port from RDP service discovery for the specified location
when both of them are not set and the session management is enable. -->
<Location value="us-east-1"/>
<EnableSessionManagement value="1"/>
<EncryptedProtocolType value="EncryptedProtocolType::RSSL_WEBSOCKET"/>
<WsMaxMsgSize value="61440"/>
<WsProtocols value="tr_json2"/>
</Channel>
<Channel>
<Name value="Channel_6"/>
<ChannelType value="ChannelType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="15000"/>
<WsMaxMsgSize value="61440"/>
<WsProtocols value="rssl.json.v2, rssl.rwf, tr_json2"/>
</Channel>
<Channel>
<Name value="Channel_7"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14003"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_8"/>
<ChannelType value="ChannelType::RSSL_HTTP"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="14003"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_9"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<Host value="localhost"/>
<Port value="14003"/>
<!-- ObjectName is optional: defaulted to "" -->
<ObjectName value=""/>
</Channel>
<Channel>
<Name value="Channel_RRTViewer_SE"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Channel_RRTViewer_DE"/>
<ChannelType value="ChannelType::RSSL_ENCRYPTED"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- EMA discovers a host and a port from RDP service discovery for the specified location
when both of them are not set and the session management is enable. -->
<Location value="us-east-1"/>
<EnableSessionManagement value="1"/>
<ObjectName value=""/>
</Channel>
<!--Performance tools channels -->
<Channel>
<Name value="Perf_Channel_1"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<NumInputBuffers value="2048"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
</Channel>
<Channel>
<Name value="Perf_Channel_WSJSON_1"/>
<ChannelType value="ChannelType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="50000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<DirectWrite value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
<WsMaxMsgSize value="18432"/>
<WsProtocols value="rssl.json.v2"/>
</Channel>
<Channel>
<Name value="Perf_Channel_WSRWF_1"/>
<ChannelType value="ChannelType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<DirectWrite value="1"/>
<Host value="localhost"/>
<Port value="14002"/>
<WsProtocols value="rssl.rwf"/>
</Channel>
<Channel>
<Name value="Perf_NIP_Channel_1"/>
<ChannelType value="ChannelType::RSSL_SOCKET"/>
<GuaranteedOutputBuffers value="100000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<DirectWrite value="1"/>
<Host value="localhost"/>
<Port value="14003"/>
<InterfaceName value=""/>
<HighWaterMark value="6144"/>
<NumInputBuffers value="10000"/>
<SysRecvBufSize value="65535"/>
<SysSendBufSize value="65535"/>
</Channel>
</ChannelList>
</ChannelGroup>
<ServerGroup>
<ServerList>
<Server>
<Name value="Server_1"/>
<ServerType value="ServerType::RSSL_SOCKET"/>
<!-- CompressionType is optional: defaulted to None -->
<!-- possible values: None, ZLib, LZ4 -->
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- ConnectionPingTimeout is optional: defaulted to 30000 -->
<ConnectionPingTimeout value="30000"/>
<!-- TcpNodelay is optional: defaulted to 1 -->
<!-- possible values: 1 (tcp_nodelay option set), 0 (tcp_nodelay not set) -->
<TcpNodelay value="1"/>
<Port value="14002"/>
</Server>
<Server>
<Name value="Server_2"/>
<!-- For WS connection server could use also RSSL_SOCKET type -->
<ServerType value="ServerType::RSSL_WEBSOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="1"/>
<Port value="15000"/>
<!-- There are optional and used for applying WS connection -->
<MaxFragmentSize value="6144"/>
<WsProtocols value="rssl.json.v2, rssl.rwf, tr_json2"/>
</Server>
<Server>
<Name value="EncryptedServer"/>
<ServerType value="ServerType::RSSL_ENCRYPTED"/>
<!-- CompressionType is optional: defaulted to None -->
<!-- possible values: None, ZLib, LZ4 -->
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<!-- ConnectionPingTimeout is optional: defaulted to 30000 -->
<ConnectionPingTimeout value="30000"/>
<!-- TcpNodelay is optional: defaulted to 1 -->
<!-- possible values: 1 (tcp_nodelay option set), 0 (tcp_nodelay not set) -->
<TcpNodelay value="1"/>
<Port value="14002"/>
</Server>
<!--Performance tools server -->
<Server>
<Name value="Perf_Server_1"/>
<ServerType value="ServerType::RSSL_SOCKET"/>
<CompressionType value="CompressionType::None"/>
<GuaranteedOutputBuffers value="5000"/>
<ConnectionPingTimeout value="30000"/>
<TcpNodelay value="0"/>
<Port value="14002"/>
<HighWaterMark value="0"/>
<InterfaceName value=""/>
<DirectWrite value="1" />
<MaxFragmentSize value="6144"/>
<NumInputBuffers value="10000"/>
<SysRecvBufSize value="65535"/>
<SysSendBufSize value="65535"/>
</Server>
</ServerList>
</ServerGroup>
<WarmStandbyServerInfoGroup>
<WarmStandbyServerInfoList>
<WarmStandbyServerInfo>
<Name value="Server_Info_1"/>
<Channel value="Channel_1"/>
<PerServiceNameSet value=""/>
</WarmStandbyServerInfo>
<WarmStandbyServerInfo>
<Name value="Server_Info_2"/>
<Channel value="Channel_7"/>
<PerServiceNameSet value=""/>
</WarmStandbyServerInfo>
</WarmStandbyServerInfoList>
</WarmStandbyServerInfoGroup>
<WarmStandbyGroup>
<WarmStandbyList>
<WarmStandbyChannel>
<Name value="WarmStandbyChannel_1"/>
<StartingActiveServer value="Server_Info_1"/>
<StandbyServerSet value="Server_Info_2"/>
<WarmStandbyMode value="WarmStandbyMode::LOGIN_BASED"/>
</WarmStandbyChannel>
</WarmStandbyList>
</WarmStandbyGroup>
<!-- source directory refresh configuration used by provider -->
<DirectoryGroup>
<!-- DefaultDirectory specifies Directory used as default if providers do not specify Directory name -->
<DefaultDirectory value="Directory_1"/>
<DirectoryList>
<!-- providers refer to the Directory by name -->
<!-- Directory is a set of Services (one or more) on which a provider will provide item data -->
<Directory>
<Name value="Directory_1"/>
<Service>
<Name value="TEST_NI_PUB"/>
<InfoFilter>
<!-- optional value; if not specified EMA will assign it -->
<ServiceId value="11"/>
<!-- optional value -->
<Vendor value="company name"/>
<!-- possible values: 0 - means consolidation service, 1 - means original provider -->
<IsSource value="0"/>
<!-- an array of market domains supported by this service -->
<!-- domains defined in the RDM Usage Guide may be refered by name -->
<!-- names of the RDM defined domains are listed in the EmaRdm.h file -->
<!-- e.g. MMT_MARKET_PRICE, MMT_MARKET_BY_ORDER -->
<!-- note that the capabilities may be specified with names and or numbers -->
<Capabilities>
<CapabilitiesEntry value="MMT_MARKET_PRICE"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<!-- list of dictionary names specified in the DictionaryGroup -->
<!-- EMA will populate the Service::InfoFilter::DictionariesProvided element -->
<!-- with the respective <>ItemName values -->
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<!-- list of dictionary names specified in the DictionaryGroup -->
<!-- EMA will populate the Service::InfoFilter::DictionariesUsed element -->
<!-- with the respective <>ItemName values -->
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<!-- list of QoS values supported by this service -->
<!-- possible values are listed in the OmmQos.h file of the EMA -->
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="Timeliness::InexactDelayed"/>
<Rate value="Rate::JustInTimeConflated"/>
</QoSEntry>
</QoS>
<!-- 0 means does not support, 1 - means supports QoS range -->
<SupportsQoSRange value="0"/>
<!-- name of item list -->
<ItemList value="#.itemlist"/>
<!-- 0 means does not accept, 1 - means accepts consumer status -->
<AcceptingConsumerStatus value="0"/>
<!-- 0 means does not support, 1 - means supports out of band snapshots -->
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<!-- StateFilter is optional -->
<!-- EMA will default the values as follows: -->
<!-- for interactive provider -->
<!-- - ServiceState is "up" and AcceptingRequests is "Yes" -->
<!-- for non interactive provider -->
<!-- - ServiceState is "up" and AcceptingRequests is "No" -->
<StateFilter>
<!-- 0 means service is down, 1 - means service is up (default; 1) -->
<ServiceState value="1"/>
<!-- 0 means service does not accept, 1 - means service accepts (default; 1) -->
<AcceptingRequests value="1"/>
<!-- optional; specifies status change to apply to all items provided by this service -->
<!-- possible values are listed in the OmmState.h file of the EMA -->
<Status>
<!-- possible values are: Open, Close, CloseRecover -->
<StreamState value="StreamState::Open"/>
<!-- possibe values are: NoChange, Ok, Suspect -->
<DataState value="DataState::Ok"/>
<!-- possible values are: None, DacsDown, etc -->
<StatusCode value="StatusCode::None"/>
<!-- a text field -->
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
<Service>
<Name value="NI_PUB"/>
<InfoFilter>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
<Status>
<StreamState value="StreamState::Open"/>
<DataState value="DataState::Ok"/>
<StatusCode value="StatusCode::None"/>
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Directory_2"/>
<Service>
<Name value="DIRECT_FEED"/>
<InfoFilter>
<ServiceId value="1"/>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
<CapabilitiesEntry value="MMT_MARKET_BY_PRICE"/>
<CapabilitiesEntry value="MMT_DICTIONARY"/>
<CapabilitiesEntry value="200"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="100"/>
<Rate value="100"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Directory_3"/>
<Service>
<Name value="TEST_NI_PUB"/>
<InfoFilter>
<ServiceId value="11"/>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="MMT_MARKET_PRICE"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="Timeliness::InexactDelayed"/>
<Rate value="Rate::JustInTimeConflated"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
<Status>
<StreamState value="StreamState::Open"/>
<DataState value="DataState::Ok"/>
<StatusCode value="StatusCode::None"/>
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
<Service>
<Name value="NI_PUB"/>
<InfoFilter>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
<Status>
<StreamState value="StreamState::Open"/>
<DataState value="DataState::Ok"/>
<StatusCode value="StatusCode::None"/>
<StatusText value=""/>
</Status>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Directory_4"/>
<Service>
<Name value="DIRECT_FEED"/>
<InfoFilter>
<ServiceId value="1"/>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="company name"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="6"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
<CapabilitiesEntry value="MMT_MARKET_BY_PRICE"/>
<CapabilitiesEntry value="MMT_DICTIONARY"/>
<CapabilitiesEntry value="200"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="100"/>
<Rate value="100"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
</StateFilter>
</Service>
</Directory>
<Directory>
<Name value="Perf_Directory_1"/>
<Service>
<Name value="NI_PUB"/>
<InfoFilter>
<ServiceId value="1"/>
<DictionariesProvided>
<DictionariesProvidedEntry value="Dictionary_3"/>
</DictionariesProvided>
<DictionariesUsed>
<DictionariesUsedEntry value="Dictionary_3"/>
</DictionariesUsed>
<Vendor value="RefinitivDevTestLab"/>
<IsSource value="0"/>
<Capabilities>
<CapabilitiesEntry value="MMT_DICTIONARY"/>
<CapabilitiesEntry value="MMT_MARKET_PRICE"/>
<CapabilitiesEntry value="MMT_MARKET_BY_ORDER"/>
<CapabilitiesEntry value="MMT_MARKET_BY_PRICE"/>
<CapabilitiesEntry value="200"/>
</Capabilities>
<QoS>
<QoSEntry>
<Timeliness value="Timeliness::RealTime"/>
<Rate value="Rate::TickByTick"/>
</QoSEntry>
<QoSEntry>
<Timeliness value="100"/>
<Rate value="100"/>
</QoSEntry>
</QoS>
<SupportsQoSRange value="0"/>
<ItemList value="#.itemlist"/>
<AcceptingConsumerStatus value="0"/>
<SupportsOutOfBandSnapshots value="0"/>
</InfoFilter>
<StateFilter>
<ServiceState value="1"/>
<AcceptingRequests value="1"/>
</StateFilter>
</Service>
</Directory>
</DirectoryList>
</DirectoryGroup>
<DictionaryGroup>
<DictionaryList>
<Dictionary>
<Name value="Dictionary_1"/>
<!-- dictionaryType is optional: defaulted to ChannelDictionary" -->
<!-- possible values: ChannelDictionary, FileDictionary -->
<!-- if dictionaryType is set to ChannelDictionary, file names are ignored -->
<DictionaryType value="DictionaryType::ChannelDictionary"/>
</Dictionary>
<Dictionary>
<Name value="Dictionary_2"/>
<DictionaryType value="DictionaryType::FileDictionary"/>
<!-- dictionary names are optional: defaulted to RDMFieldDictionary and enumtype.def -->
<RdmFieldDictionaryFileName value="./RDMFieldDictionary"/>
<EnumTypeDefFileName value="./enumtype.def"/>
</Dictionary>
<Dictionary>
<Name value="Dictionary_3"/>
<!-- providers always assume DictionaryType = DictionaryType::FileDictionary -->
<DictionaryType value="DictionaryType::FileDictionary"/>
<!-- dictionary file names are optional: defaulted to ./RDMFieldDictionary and ./enumtype.def -->
<RdmFieldDictionaryFileName value="./RDMFieldDictionary"/>
<EnumTypeDefFileName value="./enumtype.def"/>
<!-- <dictionary>ItemName represents the names shown in DictionariesProvided and DictionariesUsed
elements of the Directory InfoFilter -->
<!-- <dictionary>ItemName is optional; default values are "RWFFld" for the RdmFieldDictionary
and "RWFEnum" for the enumtype.def -->
<RdmFieldDictionaryItemName value="RWFFld"/>
<EnumTypeDefItemName value="RWFEnum"/>
</Dictionary>
</DictionaryList>
</DictionaryGroup>
</EmaConfig>