Server Developer Training - Day two
This day covers:
Notify
The Genesis platform includes a notification module called GENESIS_NOTIFY by default. The package for this is genesis-notify
. It does not run automatically.
As you have already cloned the Server Developer Training starting repository from here, you have everything you need to run it.
The manual steps to use the genesis-notify
package are not difficult:
-
Add a reference to your server/jvm/alpha-dictionary-cache build.gradle.kts file, such as this.
-
Add a reference to your server/jvm/alpha-deploy build.gradle.kts file, like this.
-
Finally, include a variable indicating the
genesis-notify
version, as demonstrated here.
Now you need to reload the gradle project, and run build and deploy tasks to verify that the new process works as expected.
If everything works, you will see a new process called GENESIS_NOTIFY in the mon tab.
if you build using the genesisInstall
command with the --compactProcesses
option, the GENESIS_NOTIFY process will be running under GENESIS_COMPACT_PROCESS.
Set up GENESIS_NOTIFY
First, we need to create the gateway. To do that, create a new file called genesis-notify.kts under your server/jvm/alpha-site-specific/src/main/resources/scripts/ and add the following information, including the details of the the SMTP server you are using.
notify {
gateways {
email(id = "email") {
smtpHost =
smtpPort =
smtpUser =
smtpPw =
smtpProtocol =
systemDefaultUserName =
systemDefaultEmail =
}
}
}
Insert NOTIFY_ROUTE
Create a file NOTIFY_ROUTE.csv as shown below, then insert it in the table NOTIFY_ROUTE using the command SendIt
.
NOTIFY_ROUTE_ID,TOPIC_MATCH,GATEWAY_ID
TRAINING_NOTIFY_01,NOTIFY_EMAIL,email
You need to add the details using new item
statements in the system definition. Open the alpha-system-definition.kts file and use the code below, adding the details of your SMTP server connection:
...
systemDefinition {
global {
...
item(name = "SYSTEM_DEFAULT_USER_NAME", value = "" )
item(name = "SYSTEM_DEFAULT_EMAIL", value = "" )
item(name = "EMAIL_SMTP_HOST", value = "" )
item(name = "EMAIL_SMTP_PORT", value = "" )
item(name = "EMAIL_SMTP_USER", value = "" )
item(name = "EMAIL_SMTP_PW", value = "" )
item(name = "EMAIL_SMTP_PROTOCOL", value = "SMTP")
}
...
}
Once this is in place, you can use systemDefinition["{NAME_OF_THE_ITEM}"].get()
to get access to its value.
Insert EMAIL_DIST_NOTIFY_ROUTE_EXT
Finally, create the EMAIL_DIST_NOTIFY_ROUTE_EXT.csv
as shown below. This creates the distribution email that will be used when the topic NOTIFY_EMAIL
is used. Run the command SendIt
to insert the details in the table EMAIL_DIST_NOTIFY_ROUTE_EXT.
NOTIFY_ROUTE_ID,EMAIL_TO,EMAIL_CC,EMAIL_BCC
TRAINING_NOTIFY_01,email@host.com,email@host.com,,
All fields are mandatory, so if you are not CCing or BCCing anyone, you need to leave these fields blank, so the platform understands that they are null. This is what we did with the EMAIL_BCC
field in the previous example.
Switch on data dumps
Data dumps need to be switched on for EVALUATOR so we can see some additional data in the logs.
Run the LogLevel command to do this:
LogLevel -p ALPHA_EVALUATOR -DATADUMP_ON -l DEBUG
And then to see the logs run:
cd $L
tail -f ALPHA_EVALUATOR.log
$L is an alias to the logs folder (~/run/runtime/logs) provided by the Genesis platform. Feel free to use your favourite command to view logs, such as tail, less etc.
Dynamic rules
In system terms, Evaluators enable you to connect Event Handlers to two different kinds of event: dynamic and static (cron rules):
- Cron Rules are scheduling rules; these are defined as quartz cron expressions.
- Dynamic Rules, also known as Dynamic Events, are defined as groovy expression, which respond to changes to database table entries.
In both cases, you define the rule in a table in the database:
- CRON_RULES for static rules
- and DYNAMIC_RULES for dynamic rules
Assuming we have already set up the Evaluator, our extended application should be able to create reports daily.
Now you are going to use the Evaluator again to set up dynamic rules. In this case, you want to send an email automatically if a specified limit has been breached.
Preparation
First, check that you have the Evaluator running. If it is not, check the procedure at the beginning of the exercise on setting up a cron rule.
You need to create three csv files for this. The first is the file with your rule in the correct format, similar to the static cron rule in the previous exercise. Call the file DYNAMIC_RULE.csv.
ID,NAME,DESCRIPTION,RULE_TABLE,RULE_STATUS,RULE_EXPRESSION,USER_NAME,PROCESS_NAME,MESSAGE_TYPE,RESULT_EXPRESSION
99,MY_RULE,It’s a rule,POSITION,ENABLED,(QUANTITY > 500),JaneDee,ALPHA_EVENT_HANDLER,EVENT_POSITION_CANCEL,((QUANTITY = 0) && (POSITION_ID = POSITION_ID))
The second csv file relates the dynamic with with a specific topic and route in the notify. Create a file called DYNAMIC_NOTIFY_RULE.csv with the following content:
DYNAMIC_NOTIFY_RULE_ID,DYNAMIC_RULE_ID,MESSAGE,TOPIC
1,99,Testing,NOTIFY_EMAIL
The third csv file enables you to test the rule. Create a file called POSITION.csv with the following data:
POSITION_ID,INSTRUMENT_ID,COUNTERPARTY_ID,QUANTITY,NOTIONAL
,2,2,600,1100000
Now you are ready to begin setting up your dynamic rule.
Exercise 2.1 Trigger the event to test the rule
15 mins
So, let's see if that has worked.
Insert the file POSITION.csv into the database. This is the file that you prepared earlier; it contains a value that breaches a limit, so it should trigger our event.
You can see that when the limit is breached, you receive an email automatically.
Go to https://www.wpoven.com/tools/free-smtp-server-for-testing and access the inbox dev-training@freesmtpserver.com
Advanced views
Views enable you join related tables to create a single holistic view. In short, Views are the genesis equivalent of SQL select queries. Views are defined in the file application-name-view-dictionary.kts. If your application is called rubicon, then the file name will be rubicon-view-dictionary.kts.
Unlike tables, views do not have any data of their own, they are read-only, but present a view based on one or more tables. We saw basic concepts and common usages of views in the Developer Training. Now we are exploring advanced concepts for views, such as INNER vc OUTER joins, Parameterised joins, and Dynamic joins.
INNER and OUTER joins
Available join types are INNER and OUTER. If you do not specify the type, it defaults to OUTER.
INNER
joins require all joins to match exactly; if one single join fails to match, the row will be discarded.
joining(INSTRUMENT, JoinType.INNER) {
on(TRADE { INSTRUMENT_ID } to INSTRUMENT { INSTRUMENT_ID })
OUTER
joins provide null references for failed joins and will still allow the row to be built.
Dictionary-joined tables
When tables are joined in the dictionary, for example, when you create a subtable in the tables definition, you are able to join to those tables in views directly, without having to specify the fields on which to join. This does not currently work with aliased tables.
Joining on fields:
joining(TRADE_TO_SIDE) {
on(TRADE { TRADE_ID } to TRADE_TO_SIDE { TRADE_ID })
Joining using join:
joining(TRADE.JOIN_TRADE_TO_SIDE)
Parameterised joins
Some join operations require external parameters that are not available in the context of the table-join definition, but will be available when the view repository is accessed (e.g. client enriched definitions), so an option exists to create parameterised joins.
These are typically used in Request Server queries:
view("INSTRUMENT_PARAMETERS", INSTRUMENT) {
joins {
joining(ALT_INSTRUMENT_ID, JoinType.INNER) {
on(INSTRUMENT.ID to ALT_INSTRUMENT_ID.INSTRUMENT_ID)
.and(ALT_INSTRUMENT_ID.ALTERNATE_TYPE.asParameter())
}
}
fields {
ALT_INSTRUMENT_ID {
ALTERNATE_CODE withAlias "INSTRUMENT_CODE"
}
INSTRUMENT {
NAME withPrefix INSTRUMENT
}
}
}
So for the above, if we had a Request Server using the view, it would make ALTERNATE_TYPE
available as a field input parameter.
Exercise 2.2 Changing TRADE_VIEW JOINs
15 mins
Change the TRADE_VIEW JOINs types to INNER. Make sure the syntax uses curly brackets to link fields, and that the JOINs statements are simplified with Dictionary-joined.