Overview
FIX Edge Java provides a RoutingRule
unit as an abstraction for internal message routing element. FEJ supports pure Java and Groovy implementations for routing rules.
Groovy routing rules are flexible mechanism that allows to implement custom logic for messages transformation and handling events.
The rules can be embedded in a rules.groovy file:
[ messageRule( // rule description "some Rule", //source filter - ignore for this rule null, // context filter - apply this rule for New Order - Single (D) messages { ctx -> ctx.getMessage().getTagValueAsString(35) == "D" } as RuleCondition, // action for rule - resend message to all session within same group // and stop message processing { ctx -> routingContext.getDestinationsByGroup(ctx.sourceParams.groups).each { adapter -> adapter.send(ctx.message) ctx.exit() } } as RuleAction), eventRule("Catching session events", FIXSessionStateEvent.class, { appEvent -> return true//do nothing but there can be additional logic }, { sessionStateEvent -> def sessionName = sessionStateEvent.getSessionId() logger.info("Session '{}' has been started.", sessionName) } ) // append system rejection rules for not processed messages getRejectionRule(routingContext) ]
The example represents two different types of rules - MessageRoutingRule and EventRoutingRule.
Groovy message routing rules syntax
messageRule
helps to build a rule for message processing. It requires a few components for its instantiation:
messageRule(String description, SourceCondition sourceCondition, RuleCondition condition, RuleAction action)
description - String with free text description of rule
source filter - check if this rule should be applied to messages from certain source. This filter was added as a separate with propose of optimization process. Such filter can by applied on static basis without addition affect in runtime. Source filter is
SourceCondition
implementation and can be null if you’d like to ignore it.context filter - dynamic filter, which can check in the same time appliance of this rule depends on message content and source attributes. Context filter is
RuleCondition
implementation and can be null if you’d like to ignore it.action - implementation of
RuleAction
which describes the main goal of this rule. It can be transformation, modification or just resending to required destination.
It is also possible to use "helper" method in case when one of several sections are not implemented
messageRule(description) .action(msgCtx -> {....}) .build()
RuleDescription
Free text description of rule.
SourceCondition
It returns True or False.
Possible values:
Parameter | Type |
---|---|
getId() | String |
getSource(); | Object |
getTargetCompId() | String |
getTargetLocationId() | String |
getTargetSubId() | String |
getSenderCompId() | String |
getSenderLocationId() | String |
getSenderSubId() | String |
RuleCondition
Returning value is True or False, according to this value code in action section is called. Rule condition is usually used as a filter for routing rule.
Example bellow demonstrate a filter by message type. Action section will be called only for Order (D) messages in the example.
{ ctx -> ctx.getMessage().getTagValueAsString(35) == "D" } as RuleCondition
The variable ctx here is used to access to the context of the message, it has the following methods
Methods | Description |
---|---|
FIXFieldList getMessage() | FIX message |
MessageEvent getMessageEvent() | |
EndpointParams getSourceParams() | Parameters of endpoint which received the message. |
void exit() | Specifies not to execute any rules after execution current one. |
boolean isExit() | |
StorageManager getContextManager() |
RuleAction
Defines the actions that will apply to the messages that correspondes to the SourceCondition and RuleCondition filters.
Example:
// action for rule - resend message to all session within same group // and stop message processing { ctx -> rc.getDestinationsByGroup(ctx.sourceParams.groups).each { adapter -> adapter.send(ctx.message) ctx.exit() } } as RuleAction),
ctx variable here is the same as for RuleCondition.
Groovy event routing rules syntax
eventRule
method helps to build a rule for event processing. It requires a few components for its instantiation:
eventRule(String description, Class<AppEvent> eventType, Predicate<AppEvent> ruleCondition, Consumer<AppEvent> ruleAction)
description - string with free test description of rule
- event type - type or subtype of event for which the rule is applied.
- rule condition - dynamic filter, which can check in the same time appliance of this rule depends on event content and source attributes. Context filter can be null if you’d like to ignore it.
rule action - describes the main goal of this rule.
EventType
Type of the events for which the rule is applied. Subtype or general type can be specified.
Available list of types and their methods
Event category | Class of event | Methods | Description |
---|---|---|---|
General | |||
BasicAppEvent | The basic class of all events, can be used for handling all the events system throws. | ||
Application | |||
ServerStateEvent | getSource(): STARTED | Notifies about the changes in state of the FIX server. | |
Session | |||
FIXSessionStateEvent | getSessionState(): CONNECTING, WAITING_FOR_LOGON, CONNECTED, WAITING_FOR_LOGOFF, DISCONNECTED, LOGON_RECEIVED, DEAD, DISCONNECTED_ABNORMALLY, RECONNECTING, WAITING_FOR_FORCED_LOGOFF, WAITING_FOR_FORCED_DISCONNECT getSessionId(): String | Notifies about the changes in state of the FIX sessions. | |
NewSessionEvent | SessionParameters getSessionParameters() reject(String reason) reject(String reason, boolean quiet) | The event is intended for accepting or rejecting new incoming session. The session will be rejected if reject method is called or accepted if not. note: if reject method is called, the next rule for the event will not be processed. | |
Scheduler | |||
SchedulerEvent | getId(): String | Event that is created by scheduler when the trigger executes. | |
SnF | |||
SnFEvent | getSource(): MESSAGE_WAS_QUEUED, MESSAGE_WAS_SKIPPED | ||
Rule events | |||
RuleErrorEvent | getException(): Exception getMessage(): FIXFieldList getRuleDescription(): String | Notifies that there is an exception in some of the rule processed. | |
UnprocessedMessageEvent | getMessage(): FIXFieldList | Notifies that there are no acceptable rules defined for the specified message. |
note: If BasicAppEvent is specified in eventRule method as a event type parameter, all the events above will be trigger the rule.
Examples
import com.epam.fej.server.fix.event.ServerStateEvent import com.epam.fej.server.fix.event.SessionStateEvent import com.epam.fej.scheduling.event.SchedulerEvent [ eventRule("Catching session events", SessionStateEvent.class, { appEvent -> return true//do nothing but there can be additional logic }, { sessionStateEvent -> def sessionName = sessionStateEvent.getSessionId() logger.info("I'm rule for session events, I was called because session '{}' has been started.", sessionName) } ), eventRule("Catching server events", ServerStateEvent.class, { appEvent -> return true//do nothing but there can be additional logic }, { serverStateEvent -> String state = String.valueOf(serverStateEvent.getSource()) logger.info("I'm rule for server events, I was called because server has {}.", state) } ), eventRule("Catching scheduler events", SchedulerEvent.class, { appEvent -> return true//do nothing but there can be additional logic }, { schedulerEvent -> logger.info("I'm rule for schedule events, id - {}.", schedulerEvent.getId()) } ), eventRule("Custom accepting of FIX sessions", NewSessionEvent.class, null, { newSessionEvent -> boolean accepted = true def sessionParameters = newSessionEvent.getSessionParameters() if (sessionParameters.getIncomingUserName() != "User1" || sessionParameters.getIncomingPassword() != "Password1") { newSessionEvent.reject("Wrong username or/and password") accepted = false } logger.info("Session {} is {}", sessionParameters.getSessionID(), accepted ? "accepted" : "declined") } ) ]
Example of scheduler settings - an event SchedulerEvent will be published every 10 seconds.
<schedule id="every10Seconds"> <task name="event" timeZone="Europe/Samara"> <event cron="*/10 * * ? * *"/> </task> </schedule>
Groovy routing rules "helpers" methods
There is a static class with methods which name "helpers", they help end-user make logic shorter by encapsulating the details inside the methods.
Name | Definition | Description |
---|---|---|
generateUniqueId | String generateUniqueId() | returns UUID that is generated using a cryptographically strong pseudo random number generator. Example: def id = generateUniqueId() |
stringValue | String stringValue(FIXFieldList msg, int tag) | returns string representation of value by provided tag Example: def destination = stringValue(msg, Header.DeliverToCompID) |
messageRule | RoutingRule messageRule(String description, SourceCondition sourceCondition, RuleCondition condition, RuleAction action) | short version for creating MessageRoutingRule |
messageRule | RoutingRuleBuilder messageRule(String description) | rule builder for creating MessageRoutingRule messageRule(description) |
eventRule | EventRoutingRuleBuilder eventRule(String description) | rule builder for creating EventRoutingRule eventRule(description) |
eventRule | RoutingRule eventRule(String description, Class<AppEvent> eventType, Predicate<AppEvent> ruleCondition, Consumer<AppEvent> ruleAction) | short version for creating EventRoutingRule |
removeRepGroup | void removeRepGroup(FIXFieldList msg, int leadingTag, int groupTags[]) | removes the list of tags that corresponds to the repeating group. Example: removeRepGroup(msg, 453, [452, 448, 447]) |
send | void send(RoutingContext rc, RuleContext ruleContext, String targetCompId) | sends a message to the session by provided targetCompId Example: send(routingContext, msgCtx, destination) |
send | void send(RoutingContext rc, RuleContext ruleContext, String targetCompId, String qualifier) | sends a message to the session by provided targetCompId and sessionQualifier Example: send(routingContext, ctx, destination, qualifier) |
Import of the classes
It is not necessary to import classes directly in the groovy.rules file. The classes are described in the fej-routing.xml. The values bellow are predefined and can be extended by custom ones not to specify imports in rules.
Injected properties
This properties available for use in groovy rule.