Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Overview

The ability to create Groovy DSL rules is available since FIXEdge Java 1.10.3 release.

Routing rules are the main elements in the FIXEdge Java configuration file. They contain instructions for:

  • Routing of incoming and outgoing FIX messages.
  • Filtering of incoming and outgoing FIX messages.
  • Transformation of incoming and outgoing FIX messages.

More than one rule can be applied to a message. It is also possible to route one message to multiple destinations or to the same destination multiple times. All rules are applied to each FIX message independently in the order set in the configuration file.

Event rules are a special kind of business rule that handle events launched during execution. The following FIXEdge Java events can be processed:

  • FixSessionStateEvent
  • NewSessionEvent
  • RuleErrorEvent
  • ScheduleEndpointEvent
  • SchedulerEvent
  • SnfEvent
  • UnprocessedMessageEvent
  • Custom

Rule element

There are two types of rules: messageRules and eventRules, and they should be grouped accordingly.

General Groovy DSL rule template:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule(description) {...}
        messageRule(description) {...}
    }
    eventRules {
        eventRule(description) {...}
        eventRule(description) {...}
    }
    routing {
        from "sourceId" to "destinationId"
    }
}

Or/And conditions

Logical And/Or blocks can be used inside conditional blocks (messageRule: source, condition; eventRule: condition).

And

And condition means that instructions will be executed sequentially. If one is false, then the others are not executed and the entire expression returns 'false'. If all are true, then the entire expression returns 'true' also.

Syntax:

rules.groovy
and {
instruction1
instruction2
}

Or

Or condition means that instructions will be sequentially. If one is true, then the others are not executed and the entire expression returns 'true'. If all are false, then the entire expression returns 'false' also.

Syntax:

rules.groovy
or {
instruction1
instruction2
}

Default

If no logical block is specified inside the conditional block then the instructions will be connected via And by default.

Routing block

Routing block is intended to route a message between two endpoints.

Syntax:

rules.groovy
routing {
from <source ids> to <destination ids>
...
from <source ids> to <destination ids>
}


<source ids> list represents the list of source session IDs.

<destination ids> list represents the list of destination session IDs.

Example:

FIXEdge Java must send all messages from 'session2' and 'session4' sessions to 'session3', 'session2, and 'session4' sessions. And then send all messages from the 'session3' session to the 'session4' session.

rules.groovy
import com.epam.fej.routing.RoutingContext
 
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    routing {
        from "session2", "session4" to "session3", "session2", "session4"
        from "session3" to "session4"
    }
}

Message rule

messageRule block is intended to build a rule for message processing.

Syntax:

rules.groovy
messageRule(description){
    source {
        //instructions, optional
    }
    condition {
        //instructions, optional   
    }
    action {
        //instructions
    }
}

Each messageRule block contains 4 sections:

SectionDescription
DescriptionMandatory section. This section provides a string with a free text - description of the business rule.
Source

Optional section. This section defines instructions for primary message filtering. The source section defines a source from which the FIX message can come. If the message source coincides with the source defined in the Source section then the rule will be applied to the message. If the Source section is not specified then the rule will be applied to FIX messages from all sources.

This filter can be applied on a static basis without additional effect at runtime.

The Source section is the SourceCondition implementation

Condition

Optional section. This section contains a set of pre-defined criteria. The application checks FIX messages on specified criteria and if it is met the instructions will be executed. If the Condition section is not specified then all messages will be maintained in accordance with the Action section.

The Condition section is the RuleCondition implementation.

Action

Mandatory section. This section defines the instructions that must be performed when the BL rule is being applied to a message. The Action section must contain at least one instruction.

The Action section is the RuleAction implementation.

Source section 

Endpoint parameters 

The source from which the FIX message can come for processing may be defined by endpoint parameters:

  • id <regex>
  • targetCompId <regex>
  • targetSubId <regex>
  • targetLocationId <regex>
  • senderCompId <regex>
  • senderSubId <regex>
  • senderLocationId <regex>

<regex> means that the regular expression or the full name of the parameter can be specified.

Example:

The rule will be applied to the messages, whose sources meet the following criteria: session ID must start with session' and the targetCompId is 'TargetCompID1' or the senderCompId contains 'Sender'.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Filter source by endpoint parameters") {
            source{
                id "session*"
                or {
                    targetCompId "TargetCompID1"
                    senderCompId ".*Sender.*"
                }
            }
        }
    }
}

Session

The source from which the FIX message can come for processing may be defined by the session parameters. Works similarly to the previous one, but is used for visual separation and grouping (e.g. per session).

Example:

The rule will be applied to the messages, whose sources meet the following criteria: session senderCompId contains 'Sender' and either session id is 'session1' and targetCompId is 'TargetCompID1' or session id is 'session2' and targetCompId  'TargetCompID2'.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Filter source by endpoint parameters") {
            source{
                senderCompId ".*Sender.*"
                or{
                    session {
                        id "session1"
                        targetCompId "TargetCompID1"
                    }
                    session {
                        id "session2"
                        targetCompId "TargetCompID2"
                    }
                }
                 
            }
        }
    }
}

Groups

The source from which the FIX message can come may be defined by the resource group. Logical conditions can be used inside.

Instruction

Description

contains <groups list>

The source is all groups from the proposed list.

<groups list> - string list with the group names.

Example:

groups {
	contains "A", "B", "C"
}

contains <filter action> from <groups list>

The source is the group(s) from the list which satisfies the <filter action>.

<filter action> may be set to one of the following values:  any | all | none.

<groups list> - string list with the group names.

Example:

groups {
	contains any from "A", "B", "C"
}

size <num>

The source is the group(s) with the specified size.

<num> - integer, the size of the group.

Example:

groups { 
	size 5 
}

size_more <num>

The source is the group(s) whose size is more than the specified value.

<num> - integer, the minimum size of the group.

Example:

groups {
	size_more 5 
}

size_less <num>

The source is the group(s) whose size is less than the specified value. 

<num> - integer, the maximum size of the group.

Example:

groups {
	size_less 5 
}

Example:

The rule will be applied to the messages, whose sources meet the following criteria: the source contains all 'A', 'B', and 'C' groups and the group size is 5, or the group list contains one of the 'B', D' groups and the group size is more than 3 and less than 6.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Filter source by groups") {
            source {
                or {
                    groups {
                        contains "A", "B", "C"
                        size 5             
                    }
                    groups {
                        contains any from "B", "D"
                        size_less 6
                        size_more 3
                    }
                }              
            }
        }
    }
}

Available destinations

The source from which the FIX message can come may be defined by the destination endpoints contained in specified Groups.

Instruction

Description

size <num>

The source is the group(s) for which the number of available destinations equals <num>.

<num> - integer, the number of available destinations for the group.

Example:

available_destinations {
	size 4 
}
size_more <num>

The source is the group(s) for which the number of available destinations is more than <num>.

<num> - integer, the minimum number of available destinations for the group.

Example:

available_destinations {
	size_more 2
}
size_less <num>

The source is the group(s) for which the number of available destinations is less than <num>.

<num> - integer, the maximum number of available destinations for the group.

Example:

available_destinations { 
	size_less 8 
}

quantity <num> by_groups <groups list>

The source is the group(s) from the list for which the number of available destinations equals <num>.

<groups list> - string list with the group names. At least one group from the list must belong to the endpoint.

Example:

available_destinations { 
	quantity 4 by_groups "A", "B", "C"
}

quantity <comparator> than <num> by_groups <groups list>

The source is the group(s) from the list for which the number of available destinations satisfies the <comparator>.

<comparator> - may be set to one of the following values: more | less.

<groups list> - string list with the group names. At least one group from the list must belong to the endpoint.

Example:

available_destinations { 
	quantity more than 4 by_groups "A", "B", "C" 
}

Example:

The rule will be applied to the messages, whose sources meet the following criteria: the number of available destination endpoints by the group is 4, or the number of available resources received by the provided groups 'A', 'B', and 'C' is less than 8.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Filter source by number of available destinations ") {
            source {
                or {
                  available_destinations {
                        size 4
                    }
                    available_destinations {
                         quantity less than 4 by_groups "A", "B","C"
                    }
                }              
            }
        }
    }
}

Custom

If there is a need to write customized source conditions, FIXEdge Java provides the ability to use the Custom block to describe the required behavior. For example, for the customized endpoint this block can be combined with all the previous ones, and several of them can be used.

If any external classes are used, they must be imported.

Syntax:

rules.groovy
source {custom {source → <some actions that will return a boolean value in the end> }}

Example: 

The rule will be applied to the messages, whose source meets the following criteria: the session id is 'session1' or the group size equals 5, and the number of available destinations received through the groups of this resource is greater than or equal to 4.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Filter source by number of available destinations, endpoint id and groups size, using custom implementation") {
            source {
                or {
                    id "session1"
                    groups { size 5 }
                }
                custom { source ->
                            Set<String> groups =  source.getGroups()
                            routingContext.getAvailableDestinationsByGroup(groups).size() >= 4
                }              
            }
        }
    }
}

Condition section 

The message received from the selected Source can be dynamically filtered by:

  • field content (single or group conditions)
  • header content
  • message type
  • current date and time
  • existence of the field(s)
  • non-existence of the field(s)
  • existence of the destination(s)
  • non-existence of the destination(s)
  • message(s) match
  • message(s) mismatch
  • custom condition

Field content 

It is possible to filter messages from the selected Source both by a single field value and a group of values for the same field.

Single construct

For a single construct, it is enough to specify the field number and one condition against which the field should be checked.

Syntax:

rules.groovy
field <tagNum> <condition>

where <tagNum> is an integer, field number and <condition> is a condition for checking the value of the field.

The list of available conditions:

Condition

Description

greater <num>

The value of the field is greater than <num>.

<num> - integer or double.

Example:

condition { 
	field 34 greater 2
}

greater_or_equal <num>

The value of the field is greater or equal to <num>.

<num> - integer or double.

Example:

condition {
	field 34 greater_or_equal 2
}

less <num>

The value of the field is less than <num>.

<num> - integer or double.

Example:

condition { 
	field 34 less 2
}

less_or_equal <num>

The value of the field is less or equal to <num>.

<num> - integer or double.

Example:

condition {
	field 34 less_or_equal 2
} 

value <value>

The value of the field equals to the <value>.

<value> - integer or double or string (regex).

Example:

condition {
	field 58 value "TestText"
}

length <num>

The length of the field is equal to the <num>.

<num> - integer.

Example:

condition {
	field 58 length 5 
}

length <comparator>than <num>

The length of the field is compared to <num>.

<num> - integer.

<comparator> - 'greater' or 'greater_or_equal' or 'less or less_or_equal'.

Example:

condition {
	field 58 length greater than 5
}

contains <string list>

The tag value contains all elements from the <string list>.

<string list> - string, list of values.

Example:

condition { 
	field 58 contains "Test", "Text"
}

from <string list> contains <action>

The tag value contains <action> elements from the <string list>.

<string list> - string, list of values.

<action> - 'all' or 'any' or 'none'.

Example:

condition { 
	field 58 from "Test", "Text" contains none 
}

begins_with <prefix>

The tag value begins with <prefix>.

<prefix> - string.

Example:

condition {
	field 58 begins_with "T"
}

Example:

The received messages are passed to the Condition section. The filtering condition is the following: field 35 equals "D", the value of the 38 field is less than 5 and greater than 2, and 58 field begins with the "Test" and has a length greater than 2.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check message type") {
            field 35 value "D"
            field 38 less 5
            field 38 greater 2
            or{
                field 58 begins_with "Test"
                field 58 length greater than 2
            }
             
        }
    }
}
Group construct

For a group construct, the field number and a list of conditions to be applied to it must be specified.

Syntax:

rules.groovy
field ( <num> ) {
	<condition 1>
	<condition 2>
	. . .
	<condition n>
}

The list of available conditions:

Condition

Description

value <comparator> than <num>

The value of the field is compared to <num>.

<num> - integer or double.

<comparator> - 'greater' or 'greater_or_equal' or 'less' or 'less_or_equal'.

Example:

condition {
	field (34) {
		greater 2
		less 10
	}
}

value <value>

The value of the field equals to the <value>.

<value> - integer or double or string (regex).

Example:

condition {
	field (58){
		or{
			value "Test.*"
			value 5
			value 1.3
		}
	}
} 

length <num>

The length of the field equals to the <num>.

<num> - integer.

Example:

condition {
	field (58) {
		length 5
	}
}

length <comparator> than <num>

The length of the field is compared to <num>.

<num> - integer.

<comparator> - 'greater' or 'greater_or_equal' or 'less' or 'less_or_equal'.

Example:

condition {
	field (58) {
		length greater than 5
		length less than 25
	}
}

contains <string list>

The value of the field contains all elements from the <string list>.

<string list> - string, list of values.

Example:

condition {
	field (58){
		contains "Test", "Text"
	}
}

contains <action> from <string list> 

The tag value contains <action> elements from the <string list>.

<string list> - string, list of values.

<action> - 'all' or 'any' or 'none'.

Example:

condition {
	field (58){
		contains any from "Test", "Text"
	}
}

begins_with <prefix>

The value of the field begins with <prefix>.

<prefix> - string.

Example:

condition {
	field (58) {
		begins_with "T"
	}
}

Header content

It is possible to filter messages from the selected Source by header content. Logical conditions And/Or can be applied.

Syntax:

rules.groovy
header {
	<header condition 1>
	. . .
	<header condition n>
}
Header Condition

Description

field (<name>) {<field condition>}

The value of the header is checked against <name>. More details about the <field condition> is below. The same as field content with group construct.

<name> - string, name of the header property.

<field condition> - condition to check header content by name.

Example:

condition {
	header {
		field("FieldName") { value "SampleValue" }
	}
}
exist <names>

The condition returns 'true' if all fields with given <names> exist.

<names> - string, the list of header names.

Example:

condition { 
	header {exist "FieldName1", "FieldName2"}
}
exist <action> from <names>

The <action> header properties from the <names> list exist.

<names> - string, list of header names.

<action> - 'all' or 'any' or 'none'.

Example:

condition { 
	header {exist any from "FieldName1", "FieldName2"}
}
not_exist <names>

The condition returns 'true' if all fields from the <names> list do not exist.

<names> - string, the list of header names.

Example:

condition { 
	header { not_exist "FieldName1", "FieldName2"}
}

Message type

It is possible to filter messages from the selected Source by message type.

Syntax: 

rules.groovy
condition {
	msgType <list of msg types>
}

Example:

The received messages are passed to the Condition section. The filtering condition is the following: the message type must be equal to one of the values in the provided list: "D", 8, "AE".

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check message type") {
            condition {
                msgType "D", 8, "AE"           
            }
        }
    }
}

Field is today

It is possible to filter messages from the selected Source by checking whether the value of the date/time field is the current date. The condition returns 'false' if the field value has an incorrect format or is not the current day.

Syntax:

rules.groovy
condition { 
	is_today <tagNum>
}



The is_today condition must be used with the fields with a time format of value, for example, 52 or 60.

Example:

The received messages are passed to the Condition section. The filtering condition is the following: the value of the 52 filed is today's date.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check message type") {
            condition {
                msgType "D", 8, "AE"           
            }
        }
    }
}

Field(s) exist

It is possible to filter messages from the selected Source by checking that the field(s) exists in these messages.

Condition

Description

exist <action> from <tagNums>

The <action> tag numbers from the <tagNums> list exist in the message.

<tagNums> - the list of tag numbers.

<action> - all or any or none.

Example:

condition { 
	exist any from 35, 49, 56
}
exist <tagNums>

The condition returns 'true' if all fields with tag numbers from the <tagNums> list exist.

<tagNums> - the list of tag numbers.

Example:

condition {
	exist 35, 49, 56
}

Field(s) not exist

It is possible to filter messages from the selected Source by checking that the field(s) does not exist in these messages. The condition returns 'true' if all fields with tag numbers from the <tagNums> list do not exist.

Syntax:

rules.groovy
not_exist <tagNums>

where <tagNums> is the list of tag numbers.

Example: 

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check if tags not exist") {
            condition {
              not_exist 35, 49, 56   
            }
        }
    }
}

Destination(s) exist by ID

It is possible to filter messages from the selected Source by checking that the destination(s) with the specified IDs exists. The condition returns 'true' if all destinations with the specified <ids> exist.

Syntax:

rules.groovy
exist <ids>

where <ids> is the list of destination IDs, string.

Example: 

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check if destinations by ids exist") {
            condition {
              exist "destination1", "destination2"    
            }
        }
    }
}

Destination(s) not exist by ID

It is possible to filter messages from the selected Source by checking that the destination(s) with the specified IDs does not exist. The condition returns 'true' if all destinations with the specified <ids> do not exist.

Syntax:

rules.groovy
not_exist <ids>

where <ids> is the list of destination IDs, string.

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check if destinations by ids not exist") {
            condition {
              not_exist "destination1", "destination2"    
            }
        }
    }
}

Message match

It is possible to filter messages from the selected Source by checking that the received message matches a pattern. The condition returns 'true' if the message matches the <regex>.

Syntax:

rules.groovy
condition {
	message_match <regex>
}

Example:

The received messages are passed to the Condition section. The filtering condition is the following: the message matches the regular expression ".*38=0.15\u000158=SampleValue\u000110=.*" Where the \u0001 is a tags separator.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check message type") {
            condition {
                message_match ".*38=0.15\u000158=SampleValue\u000110=.*"           
            }
        }
    }
}

Message mismatch

It is possible to filter messages from the selected Source by checking that the received message does not match a pattern. The condition returns 'true' if the message does not match the <regex>.

Syntax:

rules.groovy
condition {
	message_mismatch <regex>
}

Example: 

The received messages are passed to the Condition section. The filtering condition is the following: the message does not match the regular expression ".*38=0.15\u000158=SampleValue\u000110=.*" Where the \u0001 is a tags separator.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check message type") {
            condition {
                message_mismatch ".*38=0.15\u000158=SampleValue\u000110=.*"        
            }
        }
    }
}

Custom

It is possible to filter messages from the selected Source using a customized condition. The Custom block can be used to describe the required behaviour.

If any external classes are used, they must be imported.

Syntax:

rules.groovy
condition { 
	custom { 
		ctx → <some actions that will return a boolean value in the end>
	} 
}

Example:

The received messages are passed to the Condition section. The filtering condition is the following: the value of the 35 tag must equal 'D'.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Condition to check message type") {
            condition {
                custom { ctx -> ctx.getMessage().getTagValueAsString(35) == "D" }
            }
        }
    }
}

Action section

The message that was successfully checked against the specified Condition is passed to the Action section.

The main goal of the rule is described in the Action section. It can be transformation, modification, or just resending to the selected destination.

Send to destination(s) by ID

It is possible to send the message that was successfully checked against the specified Condition to the specified endpoint(s) using the Destination ID. If errors occur, they will be logged at the ERROR level.

Syntax:

rules.groovy
sendTo <destination ids>

where <destination ids> is the list of endpoint destination IDs.

Example: 

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Send message to several endpoints") {
            action {
                sendTo "session1", "endpoint1"
            }
        }
    }
}

Send by repeating groups to destination ID

It is possible to send a message containing a repeating group that was successfully checked against the specified Condition to the specified endpoint using the Destination ID.

Syntax:

rules.groovy
action {
	send by repeating_groups <repeating group> to <destination id>
}

where <repeating_groups> is repeating group tag, and the <destination id> is endpoint destination ID.

Example: 

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Send message by repeating groups to endpoint") {
            action {
                send by repeating_groups 552 to "endpoint1"
            }
        }
    }
}

Send by groups

It is possible to send the message that was successfully checked against the specified Condition to the destination(s) found by the <groups> list.

Syntax:

rules.groovy
action {
	send by groups <groups>
}

where <groups> is a list of groups.

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Send message by groups") {
            action {
                send by groups "A", "B"
            }
        }
    }
}

Send by TargetIDs

It is possible to send the message that was successfully checked against the specified Condition to the destination(s) found by TargetIDs.

Syntax:

rules.groovy
action {
	send by targetIds <ids>
}

where <ids> is a list of target IDs.

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Send message by target ids") {
            action {
                send by targetIds "targetId1", "targetId2"
            }
        }
    }
}

Reject message

It is possible to reject the message that was successfully checked against the specified Condition with the specified reason.

Syntax:

rules.groovy
action {
	rejectMessage <user reason>
}

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Send reject message") {
            action {
                rejectMessage "User reason"
            }
        }
    }
}

Modify fields

It is possible to modify the fields and send the message that was successfully checked against the specified Condition.

Syntax:

rules.groovy
action {
	fields {
		<action 1>
		<action n>
	}
}

where the <action n> is the modification that must be applied to change the message.

The list of available actions:

Action

Description

set <fieldNum> value <value>

The field with the <fieldNum> number will be set to the <value>. If the <fieldNum> field doesn't exist in the message, it will be added.

<fieldNum> - the tag number.

<value> - the new value for the <fieldNum> field.

Example:

action {
	fields { 
		set 58 value "New value" 
	}
}
remove <fieldNum>

The <fieldNum> field will be deleted.

<fieldNum> - the tag number.

Example:

action { 
	fields { 
		remove 58 
	} 
}
move <fieldNum1> to <fieldNum2>

The value of the <fieldNum1> field will be moved to the <fieldNum2> field. The source <fieldNum1> field will be deleted.

<fieldNum1> - the source field.

<fieldNum2> - the destination field.

Example:

action { 
	fields { 
		move 38 to 58 
	} 
}
modify <fieldNum> value <value>

The value of the <fieldNum> field will be updated. The new field won't be added if the <fieldNum> field doesn't exist. 

<fieldNum> - the tag number.

<value> - value for adding. The following types are valid: string, int, long, boolean or byte.

Example:

action { 
	fields { 
		modify 58 value "New value" 
	} 
}
modify <fieldNum> double_value <value>, <precision>

The double value of the existing <fieldNum> field will be updated. The new field won't be added if the <fieldNum> field doesn't exist.

<fieldNum> - the tag number.

<value> - the value for adding. 

<precision> - num precision.

Example:

action { 
	fields { 
		modify 44 double_value 3.45, 2 
	} 
}
exchange <fieldNum1> with <fieldNum2>

The values of the <fieldNum1> field and <fieldNum2> field will be exchanged.

<fieldNum1> - the source field.

<fieldNum2> - the destination field.

Example:

action { 
	fields { 
		exchange 49 with 56 
	} 
}
copy <fieldNum1> to <fieldNum2>

The value of the <fieldNum1> field will be copied to the <fieldNum2> field. The source field will be not deleted. The new destination field will be added if it doesn't exist.

<fieldNum1> - source field.

<fieldNum2> - destination field.

Example:

action { 
	fields { 
		copy 38 to 58 
	} 
}

Example:

Received message: 

 8=FIX.4.4 | 9=146 | 35=D | 49=FIXCLIENT1 | 56=FIXEDGE | 34=4 | 52=20220510-08:44:56.384 | 11=MyNew11Tag | 55=BTC/USD | 60=20220420-12:35:40.970 | 38=1 | 40=2 | 44=2.25 | 10=XXX | 

Result message: 

8=FIX.4.4 | 9=146 | 35=D | 49=FIXCLIENT1 | 56=FIXEDGE | 34=4 | 52=20220510-08:44:56.384 | 55=BTC/USD | 60=20220420-12:35:40.970 | 38=1 | 40=2 | 44=3.45 | 58=Sample message with type D |  10=XXX |

The message of 'D' message type was received from the 'session2', changed and routed to 'session1'.

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Change received message and route from session2 to session1") {
            source {
                id "session2"
            }
            condition {
                msgType "D"
            }
            action {
                fields {
                    set 58 value "Sample message with type D"
                    remove 11
                    modify 54 value 3
                    modify 44 double_value 3.45, 2
                }
                sendTo "session1"
            }
        }
    }
}

Modify header

It is possible to modify the message header and send the message that was successfully checked against the specified Condition.

Syntax:

rules.groovy
action {
	header {
		<action 1>
		<action n>
	}
}

where <action n> is the modification that must be applied to change the message header.

The list of available actions: 

Action

Description

set <fieldName> value <value>

The <fieldName> header field will be set to the <value> . If the <fieldNum> field doesn't exist in the message, it will be added.

<fieldName> - header field name.

<value> - the new value for the <fieldNum> header field.

Example: 

action { 
	header { 
	set 58 value "New value" 
	} 
}

Example: 

The ManageableQueue.STORE_AND_FORWARD_ENABLED header property will be set to the Boolean.FALSE value.

rules.groovy
import com.epam.fej.routing.RoutingContext
import com.epam.fej.routing.manageablequeue.ManageableQueue
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Set header property") {
            source {
                id "session2"
            }
            condition {
                msgType "D"
            }
            action {
                header {
                    set ManageableQueue.STORE_AND_FORWARD_ENABLED value Boolean.FALSE
                }
                sendTo "session1"
            }
        }
    }
}

If condition

It is possible to separate the execution of some events depending on the conditions described in the corresponding block. It consists of the ifCondition main part, which separates this block from other actions, and 3 subparts: when, then, and otherwise. 

Syntax:

rules.groovy
action {
	ifCondition {
		when {
			<condition 1>
			<condition n>
		}
		then {
			<action 1>
			<action n>
		}
		otherwise {
			<action 1>
			<action n>
		}
	}
}

Separation by the ifConditionis required.

Each of the when, then and otherwise sub-parts can be skipped or duplicated. If there are several identical sub-parts in one block, their instructions will be executed as a single condition/action.

The when sub-part describes the condition. <condition n> is any instruction from the message rule Condition section.

The then sub-part describes actions that will be performed if the result of executing when sub-part is 'true'. <action n> is any instruction from the message rule Action section.

The otherwise sub-part describes actions that will be performed if the result of executing when sub-part is 'false'. <action n> is any instruction from message rule Action block.

whenthenotherwise

behavior

<condition n><action 1><action 2>

If the <condition n> is 'true' then apply <action 1> will be executed.

If <condition n> is 'false' then <action 2> will be executed.

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. If condition with all blocks") {
            action {
                ifCondition {
                    when {
                        or {
                            msgType "D"
                            exist 11, 58
                        }
                    }
                    then {
                        modify 58 value "Update user text"
                        sendTo "session1"
                    }
                    otherwise {
                        sendTo "session2"
                    }
                }
            }
        }
    }
}
<condition n><action 1>null

If <condition n> is 'true' then <action 1> will be executed.

If <condition n> is 'false' then nothing will be executed.

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. If condition with all blocks") {
            action {
                ifCondition {
                    when {
                        or {
                            msgType "D"
                            exist 11, 58
                        }
                    }
                    then {
                        modify 58 value "Update user text"
                        sendTo "session1"
                    }
                }
            }
        }
    }
}
<condition n>null<action 2>

If <condition n> is 'true' then nothing will be executed.

If <condition n> is 'false' then <action 2> will be executed.

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. If condition with all blocks") {
            action {
                ifCondition {
                    when {
                        or {
                            msgType "D"
                            exist 11, 58
                        }
                    }
                    otherwise {
                        sendTo "session2"
                    }
                }
            }
        }
    }
}
null<action 1><action 2>If when block is missing, it means that there is no 'true' condition, so otherwise block will always be executed, if present. If the otherwise block is absent too, then nothing will be executed.

Route by field value

Depending on the <value> specified in the <field num> field, the routeByField action redirects the message to the <destination n> destination. The Otherwise block provides the ability to set the default behaviour if none of the specified conditions is met.

Syntax:

rules.groovy
routeByField(<field num>) {
	value <value 1> to <destination 1>
	value <value 2> to <destination 2>
	value <value n> to <destination n>
	otherwise <default behavior>
}

where:

<field num> is an integer, the number of the tag whose value will be compared.

<value n> is a number or string, value, that the <field num> will be compared to.

<destination n> is a target endpoint to which the message will be redirected if the value of the <field num> field equals <value n>.

<default behavior> is a string or lambda block defining the default action that will be performed if none of the specified cases works. String - by default, used to send messages to the specified destination. Lambda - to specify fully custom behaviour.

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Route by field") {
            source {
                id "session2"
            }
            condition {
                msgType "D"
            }
            action {
                routeByField(11) {
                    value "OR2" to "session1"
                    value "OR1" to "session3"
                    otherwise {ctx -> logger.info("Can't match appropriate value")}
                }
            }
        }
    }
}

Custom

If there is a need to write customized action, FIXEdge Java provides the ability to use the Custom block to describe the required behaviour. For example, for the customized endpoint this block can be combined with all the previous ones, and several of them can be used.

If any external classes are used, they must be imported.

Syntax: 

rules.groovy
action {
	custom {
		ctx → <some actions> 
	}
}

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    messageRules {
        messageRule("Action. Set header property") {
            source {
                id "session2"
            }
            condition {
                msgType "D"
            }
            action {    
                custom {
                    ctx ->
                        routingContext.getDestinationById("session1").send(ctx.messageEvent)
                        logger.info("run custom action")
                        ctx.exit()
                }
            }
        }
    }
}

Context exit

It is possible to perform the RuleContext exit and not follow the rules below.

Syntax:

rules.groovy
action { 
	context exit 
}

Event rule

eventRule block is intended to build a rule for event processing.

Syntax:

rules.groovy
eventRule(description){
    eventType(<ClassName>.class)
    condition {
        //instructions, optional
    }
    action {
        //instructions
    }
}

Each eventRule block contains 4 sections:

SectionDescription
descriptionMandatory section. This section provides a string with a free text - description of the event rule.
eventType

Optional section. This section defines the type or subtype of the event for which the rule must be applied. This section can be skipped if you use customized types of events.

condition

Optional section. This section contains a set of pre-defined criteria. The application checks events on event content and source attributes and if the condition is met the instructions will be executed. If the condition section is not specified then all events will be maintained in accordance with the Action section.

Action

Mandatory section. This section defines the instructions that must be performed when the event rule is being applied. The Action section must contain at least one instruction.

Description section

The description section contains the line of text used to describe the event rule.

eventType section

The eventType section defines the type or subtype of the event for which the rule must be applied. It is possible to specify custom classes built on the AppEvent interface or use the default ones.

Syntax:

rules.groovy
eventRules {
	eventRule ("Description"){
		eventType (FIXSessionStateEvent.class)
	}
}

If any classes are used, they must be imported.

The eventType section can be skipped if the customized default type of events is specified.

The eventType section consists of the list of the default classes, they and their analogue among the default custom types are listed in the table below.

eventType section can be used with customized default rules too. The class passed as a parameter must be an instance or an inheritor of the class that underlies this block.

Class

Import path

Analogous to the default custom type

FIXSessionStateEvent.class

com.epam.fej.server.fix.event.FIXSessionStateEvent

FixSessionStateEventRule(name)

NewSessionEvent.class

com.epam.fej.server.fix.event.NewSessionEvent

NewSessionEventRule(name)

RuleErrorEvent.class

com.epam.fej.routing.event.RuleErrorEvent

ErrorEventRule(name)

ScheduleEndpointEvent.class

com.epam.fej.event.ScheduleEndpointEvent

ScheduleEndpointEventRule(name)

SchedulerEvent.class

com.epam.fej.scheduling.event.SchedulerEvent

SchedulerEventRule(name)

SnFEvent.class

com.epam.fej.routing.endpoint.snf.events.SnFEvent

SnFEventRule(name)

UnprocessedMessageEvent.class

com.epam.fej.routing.event.UnprocessedMessageEvent

UnprocessedMessageEventRule(name)

Examples: 

The default event rule structure with default event type.

rules.groovy
import com.epam.fej.routing.RoutingContext
import com.epam.fej.server.fix.event.FIXSessionStateEvent
import com.epam.fixengine.SessionState
 
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    eventRules {
        eventRule("FIX Session Disconnect. Default rule structure") {
            eventType(FIXSessionStateEvent.class)
            condition {
                custom {
                    event ->
                        def state = event.sessionState as SessionState
                        return SessionState.isDisconnected(state) && event.sessionId == "session2"
                }
            }
            action {
                custom {
                    event ->
                        logger.info("[FIX Session Disconnect] Session is disconnected: " + event.sessionId)
 
                }
            }
        }
    }
}

The customized event rule structure with the default event type:

rules.groovy
import com.epam.fej.routing.RoutingContext
 
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    eventRules {
        FixSessionStateEventRule("FIX Session Connect") {
            condition {
                session "session1"
                sessionState connected
            }
            action {
                log "[FIX Session Connect] Session is connected: session1"
            }
        }
    }
}

The rule with the custom event type:

rules.groovy
import com.epam.fej.routing.RoutingContext
import com.path.to.custom.event.type.CustomEventType
 
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    eventRules {
        eventRule("Custom event type") {
            eventType(CustomEventType.class)
            condition {
                custom {
                    event -> event.condition()
                }
            }
            action {
                log "Custom event type"
            }
        }
    }
}

Condition section

The occurred event can be filtered by the event content and source attributes. This section consists of a number of instructions that can be grouped by logical operators.

FixSessionStateEventRule

It is possible to filter occurred FixSessionStateEvents by session state and session ID.

Syntax:

rules.groovy
eventRules {
	FixSessionStateEventRule("FIX Session Connect") {
		condition {
			<condition instruction 1>
			<condition instruction n>
		}
	}
}

where the <condition instruction n> is an instruction for this event type.

Instruction

Description

session <regex>

The session ID will be checked against regular expression. 

<regex> - the regular expression.

Example:

condition {
	session "session1"
}
sessionState <state>

The current state of the session will be compared to the specified <state>.

<state> - provided session state, 'connected' or 'disconnected' or 'disposed' or 'not_disconnected'.

Example:

condition {
	sessionState connected
}
 

Example: 

rules.groovy
import com.epam.fej.routing.RoutingContext
 
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    eventRules {
        FixSessionStateEventRule("FIX Session Connect") {
            condition {
                session "session1"
                sessionState connected
            }
            action {
                log "[FIX Session Connect] Session is connected: session1"
            }
        }
    }
}

NewSessionEventRule

It is possible to filter occurred NewSessionEvents by session event state.

Syntax:

rules.groovy
eventRules {
	NewSessionEventRule("New session event") {
		condition {
			<condition instruction 1>
			<condition instruction n>
		}
	}
}

where the <condition instruction n> is an instruction for this event type.

Instruction

Description

session <state>

The current state of the session event will be compared to the specified <state>.

<state> - the session event state, 'rejected' or 'quietRejected'.

ErrorEventRule

It is possible to filter occurred RuleErrorEvents.

Syntax:

rules.groovy
eventRules {
	ErrorEventRule("Error event rule") {
		condition {
			<condition instruction 1>
			<condition instruction n>
		}
	}
}

where <condition instruction n> is an instruction for this event type.

Instruction

Description

session <condition>

The session will be checked against specified <condition>.

<condition> - 'mitigated'.

ScheduleEndpointEventRule

It is possible to filter occurred ScheduleEndpointEvents by endpoint condition and endpoint ID.

Syntax:

rules.groovy
eventRules {
	ScheduleEndpointEventRule("Schedule endpoint event") {
		condition {
			<condition instruction 1>
			<condition instruction n>
		}
	}
}

where <condition instruction n> is an instruction for this event type.

Instruction

Description

endpoint <condition>

The endpoint condition will be checked against specified <condition>.

<condition> - 'startedOnLoad' or 'resetSequence' (if sequence was reset on schedule)

ids <ids list>

Check if any of given endpoint IDs present. 

<ids> - string, the list of endpoint IDs.

SchedulerEventRule

It is possible to filter occurred SchedulerEvents.

Syntax:

rules.groovy
eventRules {
	SchedulerEventRule("Sheduler event") {
		condition {
			<condition instruction 1>
			<condition instruction n>
		}
	}
}

where <condition instruction n> is an instruction for this event type.

Instruction

Description

ids <ids list>

Check if any of given IDs present.

<ids> - string, the list of IDs.

SnFEventRule

It is possible to filter occurred SnfEvents.

Syntax:

rules.groovy
eventRules {
	SnFEventRule("SnF event") {
		condition {
			<condition instruction 1>
			<condition instruction n>
		}
	}
}

where <condition instruction n> is an instruction for this event type.

UnprocessedMessageEventRule

It is possible to filter occurred UnprocessedMessageEvents.

Syntax:

rules.groovy
eventRules {
	UnprocessedMessageEventRule("Unprocessed message event") {
		condition {
			<condition instruction 1>
			<condition instruction n>
		}
	}
}

where <condition instruction n> is an instruction for this event type.

Custom

Custom filtering is available for all event types. It allows to write customized conditions, taking into account the features of the received AppEvent and Source.

Syntax:

rules.groovy
eventRule("FIX Session Disconnect. Default rule structure") {
	eventType(FIXSessionStateEvent.class)
		condition {
			custom {
				event -> <condition instruction>
			}
		}
}

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import com.epam.fej.server.fix.event.FIXSessionStateEvent
import com.epam.fixengine.SessionState
 
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    eventRules {
        eventRule("FIX Session Disconnect. Default rule structure") {
            eventType(FIXSessionStateEvent.class)
            condition {
                custom {
                    event ->
                        def state = event.sessionState as SessionState
                        return SessionState.isDisconnected(state) && event.sessionId == "session2"
                }
            }
        }
    }
 
}

Action section

Custom

If there is a need to write customized action, FIXEdge Java provides the ability to use the Custom block to describe the required behaviour. For example, for the customized endpoint this block can be combined with all the previous ones, and several of them can be used.

If any external classes are used, they must be imported.

Syntax:

rules.groovy
action {
	custom {
		appEvent→ <some actions> 
	}
}

Example:

rules.groovy
import com.epam.fej.routing.RoutingContext
import com.epam.fej.server.fix.event.FIXSessionStateEvent
import com.epam.fixengine.SessionState
 
import static dsl.CommonRulesDsl.rulesDSL
 
rulesDSL(routingContext as RoutingContext) {
    eventRules {
        eventRule("FIX Session Disconnect. Default rule structure") {
            eventType(FIXSessionStateEvent.class)
            condition {
                custom {
                    event ->
                        def state = event.sessionState as SessionState
                        return SessionState.isDisconnected(state) && event.sessionId == "session2"
                }
            }
            action {
                custom {
                    event ->
                        logger.info("[FIX Session Disconnect] Session is disconnected: " + event.sessionId)
 
                }
            }
        }
    }
}
  • No labels