/
History implementation in DSL

History implementation in DSL

Overview

FIXEdge Java provides Solutions for handling and storing data on the business layer—Histories. Information can be handled in memory or through database queries, depending on the defined type.  These types are available in the current version:

·        Information can be stored in the memory storage with the help of InMemoryHistory.

·        Information can be stored in the JDBC database via JDBCHistory.

Histories can be used in existing message/event rules builders using routingContext (see History implementation) or in routing rules through the suggested Groovy DSL design.

The DSL Layer's many history types are configured and handled according to the instructions in this manual.

Configuration structure

The configuration of the histories must be done through the histories block in rulesDSL depending on the type.

It’s possible to work with histories at different levels of DSL rules: condition, action, custom blocks.

InMemoryHistory

 

In order to configure InMemoryHistory, it’s required to declare a block memoryHistory in the histories section and describe the list of required parameters:

·        name <history name> - type: String. Must be unique .

·        keyTags <key tags: simple or compose> - type: Integer or List of integers. Tag(s) number(s) in received on BL message (FIXFieldList), which creates a key (simple or compose).

·        valueTags <value tags: simple or compose> type: Integer or List of integers. Tag(s) number(s) in received on BL message (FIXFieldList), that will be stored by prepared key.

Structure template

Main structure

1

2

3

4

5

6

7

8

9

10

11

12

13

14

import com.epam.fej.routing.RoutingContext

 

import static dsl.CommonRulesDsl.rulesDSL

 

rulesDSL(routingContext as RoutingContext) {

    histories {

        memoryHistory {

            name <history name>

            keyTags <key tags: simple or compose>

            valueTags <value tags: simple or compose>

 

        }

    }

}

 

Sample

Main structure

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import com.epam.fej.routing.RoutingContext

 

import static dsl.CommonRulesDsl.rulesDSL

 

rulesDSL(routingContext as RoutingContext) {

    histories {

        memoryHistory {

            name "SenderTargetCompId History"

            keyTags 34

            valueTags 49, 56

 

        }

        memoryHistory {

            name "ClOrdID History"

            keyTags 34, 35

            valueTags 11

        }    

    }

}

JDBCHistory

For configuring JDBCHistory, its required to declare a block db(<dataSource>) in the histories and describe the list of parameters:

·   DataSource - type: String. Must be unique. Group identifier, that contains parameters for connecting to the database. Its set through the conf/history.properties

o   <dataSource>.url=<connectionUrl> - required. 

o   <dataSource>.username=<username> -  required. 

o   <dataSource>.password=<password> -  required. 

o   <dataSource>.driverClassName=<driverClassName> - required. 

o   <dataSource>.databaseName=<databaseName> - optional.  The name of the catalogue must be specified (the same specified in the URL). Required to be used in case when two databases contain procedures with the same name. 

o   <dataSource>.schemaName=<schemaName> - optional. The name of the schema must be specified. For example, when using it with a MsSQL datasource and a specified catalog name, its required to specify the schema so that the procedure is recognized (dbo is the default).

o   <dataSource>.maximumPoolSize=<maximumPoolSize> - optional, default - 10, type:       Integer. This property controls the maximum size that the pool is allowed to reach, including both idle and in-use connections.

o  <dataSource>.idleTimeout=<idleTimeout> - optional, default - 3000, type: Integer. The maximum duration that a connection may remain idle in the pool is managed by this attribute.

·   Procedures - structure block, that describes the list of stored procedures or custom requests, that can be applied to declared dataSource.

Includes:

o procedure(<procedure name>) - block that describes procedure's configuration:

§  <procedure name> - required, type: String, name of stored procedure. Used as the        identifier of the procedure/request being accessed if no <id> was specified. In this case, the uniqueness of the names for all databases is important. (Otherwise, the <id> is additionally specified). It is also used to generate a stored procedure call request in the "CALL <procedure name> (<InParams template>);" format if a custom template has not been previously specified. 

§ <id> - optional, type: String, is used when it is necessary to set the uniqueness of the    procedure configuration. For example, for two different databases, there are procedures with the same name. To distinguish them when calling, own id is assigned to each structure. It must be unique in comparison with the names/ids of other procedures , regardless of the database being accessed. 

§ inParams - optional, block, that describes and after - prepare expected incoming   params. The order in which the parameters are described is important:

·        fixParam (<tag num>) - get from FIXFieldList (incoming message) value by <tag num> as String. 

·     fixParam (<tag num>, <default value>) - get from FIXFieldList (incoming message) value by <tag num> as String. If the value does not exist, then substitute the specified default <default value>

·   param - general block that describes incoming param structure

o tag - optional, type: int, define tag number, that should take and save from incoming FIXFieldList

o defaultValue - optional, type: any serializable object. This value will be substituted if the specified tag is not found.

o dataType - optional, type: String, default: String. Possible values (case insensitive):  INT, LONG, FLOAT, DOUBLE, BIGDECIMAL,BYTE, BYTES, BOOL, STRING, TIMESTAMP, LOCALMKTTIME, TENOR, TIMEONLY. Unknown type - get from FIXFieldList as bytes. 

o saveFullMessage - optional, type: boolean. Declare to save full incoming message as byte array (db blob type)

§  outParams - optional, block, that describes out parameters/result set

·     param - expect name of OUT param for stored procedure and its java.sql.Types 

·     rowMapper - type: RowMapper. Custom implementation of method to map each row of data in the ResultSet. 

·     dbHistory - structure block, that describes the configuration of the view on selected table. Describes by:

o   name - required, type: String, must be unique over ALL declared histories. This parameter is used as an identifier for accessing the described structure.

o   updateOnSave - optional, type: boolean, default: false. Determines whether to update database records with the same key or ignore them.

o   table - required, structure block, that describes selected table (in whole or in part):

§ name - required, type: String. Declared table name

§ keys - required, structure block, that describes the list of key columns in the table. Consist of one or a list of described column structures:

·     column - structure block, that describes the table column:

o  tag - optional, type: int, define tag number, that should take and save from incoming FIXFieldList

o  defaultValue - optional, type: any serializable object. This value will be substituted if the specified tag is not found.

o  dataType - optional, type: String, default: String. Possible values (case insensitive):  INT, LONG, FLOAT, DOUBLE, BIGDECIMAL,BYTE, BYTES, BOOL, STRING, TIMESTAMP, LOCALMKTTIME, TENOR, TIMEONLY. Unknown type - get from FIXFieldList as bytes. 

o  saveFullMessage - optional, type: boolean. Declare to save full incoming message as byte array (db blob type). It is not recommended to use the type as a key.

o  customFormatter - optiona, type: Functional callback. Allows the user to define the format for saving a value to a column using a callback. Accepts FIXFieldList as input, returns HistoryObject (HistoryKey/HistoryValue) as output: HistoryObject apply(FIXFieldList list);

§   values - required, structure block, that describes the value columns in the table. Consist of one or a list of described column structures (see keys column description)

 

Structure template

Main structure

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

import com.epam.fej.routing.RoutingContext

 

import static dsl.CommonRulesDsl.rulesDSL

 

rulesDSL(routingContext as RoutingContext) {

    histories {

        db(<dataSource>){

            procedures {

                procedure (<procedure name>)

                procedure (<procedure name>){

                    id <identifier>

                    inParams {

                        param {

                            tag <tag num>

                            dataType <data type>

                            defaultValue <default value>

                            saveFullMessage <true/false>

                        }

                    }

                    outParams {

                        param <procedure param name>, <java.sql.Types.<var>>

                        rowMapper { <RowMapper implementation> }

                    }

                }

            }

            dbHistory {

                name <history name>

                table {

                    name <table name>

                    keys {

                        column {

                            name <column name>

                            tag <tag num>

                            dataType <data type>

                            defaultValue <default value>

                            saveFullMessage <true/false>

                            customFormatter <custom formatter, callback>

                        }

                    }

                    values {

                        column {

                            name <column name>

                            tag <tag num>

                            dataType <data type>

                            defaultValue <default value>

                            saveFullMessage <true/false>

                            customFormatter <custom formatter, callback>

                        }

                        column {

                            name <column name>

                            tag <tag num>

                            dataType <data type>

                            defaultValue <default value>

                            saveFullMessage <true/false>

                            customFormatter <custom formatter, callback>

                        }

                         

                    }

                }

            }

            dbHistory {

                name <history name>

                table {

                    name <table name>

                    updateOnSave <true/false>

                    keys {

                        column {

                            name <column name>

                            tag <tag num>

                            dataType <data type>

                            defaultValue <default value>

                            saveFullMessage <true/false>

                            customFormatter <custom formatter, callback>

                        }

                        column {

                            name <column name>

                            tag <tag num>

                            dataType <data type>

                            defaultValue <default value>

                            saveFullMessage <true/false>

                            customFormatter <custom formatter, callback>

                        }

                    }

                    values {

                        column {

                            name <column name>

                            tag <tag num>

                            dataType <data type>

                            defaultValue <default value>

                            saveFullMessage <true/false>

                            customFormatter <custom formatter, callback>

                        }

                    }

                }

            }

        }

    }

}

Sample

conf/rules.groovy

DB configuration        

                                                                                       Collapse source

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

import com.epam.fej.routing.RoutingContext

 

import static dsl.CommonRulesDsl.rulesDSL

import static java.sql.Types.INTEGER

 

class Product {

    String name

    BigDecimal price

     

    public Product(String name, BigDecimal price) {

        this.name = name

        this.price = price

    }

}

rulesDSL(routingContext as RoutingContext) {

    histories {

        db("datasource1"){

            procedures {

                procedure ("insert_default_value")

                procedure ("insert_ClOrdId"){

                    id "saveClOrdId"

                    inParams {

                        tag 11

                        defaultValue "default Order id"

                    }

                }

                procedure ("select_by_price"){

                    id "selectProducts"

                    inParams {

                        tag 58

                        defaultValue "default value"

                    }

                    outParams {

                        param "counter", Types.INTEGER

                        rowMapper {

             rs, num -> return new Product(rs.getString("productName"), rc.getBigDecimal("price"))}

                        }

                }

            }

            dbHistory {

                name "SenderTargetHistory"

                table {

                    name "SenderTargetCompId"

                    keys {

                        column {

                            name "SeqNum"

                            tag 34

                            dataType "Int"

                        }

                    }

                    values {

                        column {

                            name "SenderCompId"

                            tag 49

                        }

                        column {

                            name "TargetCompId"

                            tag 56

                        }

                         

                    }

                }

            }

            dbHistory {

                name "ClOrdIdHistory"

                table {

                    name "ClOrdID_table"

                    updateOnSave true

                    keys {

                        column {

                            name "SeqNum"

                            tag 34

                            dataType "Int"

                        }

                        column {

                            name "MsgType"

                            tag 35

                        }

                    }

                    values {

                        column {

                            name "ClOrdID"

                            tag 11

                            defaultValue "None"

                        }

                    }

                }

            }

        }

    }

}

 

 

conf/history.properties

history.properties

datasource1.url=jdbc:mysql://localhost:3306/custom_db

datasource1.username=user

datasource1.password=

datasource1.driverClassName=com.mysql.cj.jdbc.Driver

datasource1.maximumPoolSize=3

 

datasource2.url=jdbc:h2:~/test;DB_CLOSE_DELAY=0

datasource2.username=user

datasource2.password=

datasource2.driverClassName=org.h2.Driver

datasource2.maximumPoolSize=3

datasource2.idleTimeout=3000

In the FIXEdge Java from the package, the following SQL databases are supported:

§  MySql

§  PostgreSQL

§  H2

§  HSQL


DSL Instructions

MessageRule

Condition section

To work with a History in a Condition section, its required to declare the corresponding block and pass the name of the history in which check is needed as a parameter.

Comparably to other conditional blocks, additional and/or blocks can be used inside so that  to facilitate communication between tasks. By extension, and.

Template

messageRule {

condition {

Name

Description

Template

Example

Key exists

Prepare a key based on a given structure and an incoming message. Check whether the corresponding one exists in the history.

key exists

condition { key exists }

Prepare a key based on a given value list. Check whether the corresponding one does not exist in the history.

keyParams <key values> value exists

condition { keyParams "Sender",

 "Target" value exists }

Key not exists

Prepare a key based on a given structure and an incoming message. Check whether the corresponding one not exists in the saved in the history.

key not_exists

condition { key not_exists }

Prepare a key based on a given value list. Check whether the corresponding one does not exist in the history.

keyParams <key values> value not_exists

condition { keyParams "Sender",

 "Target" value not_exists }

Value by key is empty

Checks if there is such a key, prepared on a given value list, and nothing is stored by it (value equal to null).

keyParams <key values> value empty

condition { keyParams  "Sender",

 "Target" value empty }

Checks if there is such a key, on a given structure and an incoming message, and nothing is stored by it (value equal to null).

key empty

condition { key empty}

Value by key is not empty

Checks if there is a key,  prepared on a given structure and an incoming message, and the value stored by the key is not empty (not equal to null)

keyParams <key values> value not_empty

condition { keyParams "Sender",

 "Target" value not_empty }

Checks if there is such a key, prepared on a given value list, and nothing is stored by it (value equal to null).

key not_empty

condition { key not_empty }

Value exists

Prepare a key based on a given structure and an incoming message. Check whether the corresponding one exists in the WHOLE history.

value exists

<