Rule Engine
Rule Engine Overview
The N2SVCD distribution includes a generic rule-matching library that can be used to select one or more matching rules from a configuration item, based on input values from the appropriate N2SVCD LogicApp service.
Additionally, it offers a mechanism for specifying and using arbitrary “variables” within the context of a service’s application.
Integration
Rule engine functionality can be included by any LogicApp script as a standard require
, e.g.:
local rule_engine = require ("n2.rule_engine")
In the above example, the LogicApp definition should include the N2SVCD Lua library location, i.e.:
../lua/lib/?.lua
Rulesets are Lua arrays with each element specifying a single rule, e.g.:
array = {
{ param1 = "1", param2 = "2" },
{ param1 = "3", param2 = "4" }
}
Alternately, rulesets with only a single rule may be specified in shorthand, e.g.:
shorthand = { param1 = "5", param2 = "6" }
These may be defined natively or passed in from N2SVCD LogicApp globals
configuration, e.g.:
<global name="SOME_ARRAY" type="array">
<thing id="thing1" value="1"/>
<thing id="thing2" value="2"/>
<thing id="thing3" value="3"/>
</global>
<global name="SOME_SHORTHAND" id="thing4" value="4"/>
… will be loaded in the LogicApp as:
SOMEARRAY = {
{ id = "thing1", value = "1" },
{ id = "thing2", value = "2" },
{ id = "thing3", value = "3" }
}
SOME_SHORTHAND = { id = "thing4", value = "4" }
Both formats will be accepted by the rule engine for any rule functions, including variable definition.
Rule Engine Functions
All rule engine functions are pure Lua and synchronous.
Contexts
Rule functions expect two contexts to be provided as Lua tables, the input context and the service context.
Both are completely free-form, but are separated as services will usually treat the input context as read-only (i.e. the message as received from the network) while using the service context for temporary transaction storage.
The context to search may be specified in selector rule parameters or values by using input.
or service.
as
prefixes. If no prefix is specified, input.
is assumed.
Note that variables are stored in the service context when initialised by the rule engine.
Rule Selection
Selector Rules Overview
The primary purpose of the rule engine is to provide a generic framework to allow selection of a value or values based on arbitrary input data from a list of Selector Rules.
Rules are traversed in order and matched based on selectors to raw or derived fields in the input data for the LogicApp service or from configured variables.
Selector Rules Configuration
Rule definition is generally for an application-specific purpose, and relies on protocol-specific input data.
Each rule
object for IDP selection can support the following attributes:
Attribute | Type | Can Invert? | Description |
---|---|---|---|
literal |
String | No | [Conditional] The literal value to return when the rule is selected. One of literal , source , or from_var must be present for each rule. |
source |
String | No | [Conditional] A field from the protocol- or service-specific context to return as the value when the rule is selected. Multiple fields may be separated by a comma, and will be concatenated (if populated). One of literal , source , or from_var must be present for each rule. |
from_var |
String | No | [Conditional] A variable name to return the value of when the rule is selected. Multiple tag names may be separated by a comma, and will be concatenated (if populated). One of literal , source , or from_var must be present for each rule. |
r_index |
Integer | No | For source and from_var source selection, r_index can be used to specify the starting index for value retrieval. Positive values count from the start of the string (zero-indexed), and negative values count from the end. Used in conjunction with r_len to provide any substring of the selected value, including prefix or suffix.(Default: 0 , copy from the start of the string) |
r_len |
Positive Integer | No | For source and from_var source selection, r_len can be used to specify the returned length of the selected value. Used in conjunction with r_index to provide any substring of the selected value of the selected value, including prefix or suffix.(Default: the selected value’s remaining length after r_index has been applied) |
var |
String | No | [Conditional] Selector for a variable name to match the value for. If var is present, value must also be present. |
var_prefix |
String | No | [Conditional] Selector for a variable name to match the value prefix for. If var_prefix is present, value must also be present. |
var_x |
String | No | [Conditional] As for var , but with x representing a unique pairing, e.g. var_12 or var_abc . A matching value_x must also be present with the appropriate suffix. |
var_prefix_x |
String | No | [Conditional] As for var_x , but for matching against the value prefix. A matching value_x must also be present with the appropriate suffix. |
value |
(various) | Yes | [Conditional] The string or integer value to match against during rule selection. Required when either var or var_prefix is present. |
value_x |
(various) | Yes | [Conditional] As for value , but with x representing a unique pairing, e.g. value_12 or value_abc . A matching var_x or var_prefix_x must also be present with the appropriate suffix. |
(other available fields) | (various) | Yes | Any number of service- or protocol-specific fields. |
Values of source
fields or the field names for the other available fields must be specified in full dot-notation form,
e.g. input.initialdp_args.serviceKey
. Either input
or service
may be prefixed in order to select the appropriate
context to match on. If neither input
nor service
is specified, input
is used as the default context.
Note that it is not required that Selector Rules are in elements called rule
. The element name is ignored when parsing
rulesets.
Each rule must provide a value, either as a literal
or copied from a context or variable field. All selectors in a rule must
match in order for the rule to be selected. If no selectors are present (e.g. only a literal
is configured), the rule
will always match, acting as a catch-all.
Returning a Substring
The r_index
and r_len
fields can be specified in order to return only a substring of the found value.
The field r_index
is zero-indexed, with the following semantics:
n = 0
: The returned value starts at the beginning of the string.n > 0
: The returned value starts after skippingn
characters from the beginning of the string.n < 0
: The returned value startsn
characters from the end of the string.
The r_len
value indicates how many characters at most should be returned, regardless of the index position.
Examples using the source value abcde
:
r_index |
r_len |
Result |
---|---|---|
(not specified) | (not specified) | abcde |
0 |
(not specified) | abcde |
3 |
(not specified) | de |
-3 |
(not specified) | cde |
(not specified) | 1 |
a |
0 |
1 |
a |
3 |
1 |
d |
-3 |
1 |
c |
Selector Inversion
Some fields in selector rules may have their match be made inverted. To do this, add the character !
to the start of
the match value.
If the string to be matched starts with an exclamation mark, add an additional !
, i.e. !!
for a normal match
and !!!
for an inverted match.
Some examples of using and not using inversion:
- rule specifies
abc
(match onlyabc
):- against actual value
abc
: match - against actual value
abd
: no match - against actual value
!abc
: no match - against actual value
!abd
: no match
- against actual value
- rule specifies
!abc
(match anything that is notabc
):- against actual value
abc
: no match - against actual value
abd
: match - against actual value
!abc
: match - against actual value
!abd
: match
- against actual value
- rule specifies
!!abc
(match only!abc
):- against actual value
abc
: no match - against actual value
abd
: no match - against actual value
!abc
: match - against actual value
!abd
: no match
- against actual value
- rule specifies
!!!abc
(match anything that is not!abc
):- against actual value
abc
: match - against actual value
abd
: match - against actual value
!abc
: no match - against actual value
!abd
: match
- against actual value
Rule Functions
Get Source, Get Rule, Get All
The three core functions for rule selection are rule_engine.get_source
, rule_engine.get_rule
, and rule_engine.get_all
.
These functions all search the provided ruleset for matching according to the supplied input and service contexts.
These functions all take the following parameters:
Attribute | Type | Description |
---|---|---|
input_context |
Table | Required The received input context object from the underlying service. |
service_context |
Table | Required The service’s context object. |
ruleset |
Table | Required The array of rules to analyse. Each rule should be a hash of possible keys and values that are used to match against the given arguments. For selection of sub-hashes, use dot notation. |
ignore_keys |
Table | An optional array of additional keys to ignore when matching rules. |
These functions return
get_source
: the contents of the first matched rule’s source value, ornil
if no match was made.get_rule
: the complete rule of the first matched rule, ornil
if no match was made.get_all
: a (possibly empty) array of all matched rules.
A Lua error
will be thrown if a processing failure occurs.
Validate Rule Variables
The function rule_engine.validate_rule_variables
determines if the provided rule has internally-consistent variable definitions.
It does not check whether variable definitions are valid or populated within the service context.
This function takes the following parameters:
Attribute | Type | Description |
---|---|---|
rule |
Table | Required The configured rule to validate. |
This function does not return anything.
A Lua error
will be thrown if a processing failure occurs or if the rule’s variable definitions are not internally-consistent.
Validate And Prepare Boolean Keys
The function rule_engine.validate_and_prepare_boolean_keys
validates that any provided boolean keys in a rule are
valid. Any keys not present are set to their default value.
This function takes the following parameters:
Attribute | Type | Description |
---|---|---|
rule |
Table | Required The configured rule to validate. |
keys |
Table | Required A table of keys to check in the format { <key name> = <key default value, either true or false>, ... } |
This function does not return anything. The rule will be updated in-place.
A Lua error
will be thrown if a processing failure occurs or if the rule’s variable definitions are not internally-consistent.
Rule Contains Source
The function rule_engine.rule_contains_source
checks if a configured rule contains a key from the available core
value source types.
This function takes the following parameters:
Attribute | Type | Description |
---|---|---|
rule |
Table | Required The configured rule to validate. |
allowed |
Table | An optional array of additional allowed source keys. |
This function returns true
if the rule contains an allowed source key, otherwise false
.
Variable Management
Variable Overview
The rule engine can be used to store values in “variables” within the service context for later use. Variables are referred to by a freeform name, and can hold string or integer values, either read from received messages from the network or configured as literals.
Variables may be referred to by other rule engine configuration as required to influence rule selection behaviour.
Once populated, variables are available within the provided service context under the sub-object vars
. These can be read
directly as required. They can also be written to, but that is not a usual use case.
The rules engine sets variable values via the use of Rule Selection to apply the appropriate rule for each variable. Each variable may be given a maximum of one value from its list of rules; as soon as a match is found, the remaining rules for that variable are not used.
Variables are configured as a LogicApp service global named VARIABLES
.
A simple variable configuration of a LogicApp instance receiving input for mobile calls from the
N2SCP Logic Hand-Off Application
might be:
<application name="Logic" module="LogicApp">
...
<config>
<services>
<service module="LhoScpApp::LhoScpLuaService" ...>
...
<globals>
<global name="VARIABLES" type="array">
<variable name="msc" mandatory="1">
<rules type="array">
<rule source="initialdp_arg.mscAddress_digits" />
</rules>
</variable>
<variable name="vlr" mandatory="0">
<rules type="array">
<rule source="initialdp_arg.locationInformation.vlrNumber_digits" />
</rules>
</variable>
<variable name="network" edr="NET" mutable="1">
<rules type="array">
<rule input.ssp_inap="!camel" literal="home"/>
<rule var_prefix="vlr" value="1500" literal="home"/>
<rule var_prefix="vlr" value="1" literal="national_roaming" />
<rule service.forwarding="true" var_prefix="msc" value="1500" literal="home"/>
<rule service.forwarding="true" var_prefix="msc" value="1" literal="national_roaming" />
<rule literal="roaming" />
</rules>
</variable>
<variable name="location" mandatory="1" mutable="1">
<rules type="array">
<rule input.ssp_inap="cs1" service.forwarding="false" source="locationNumber_digits" />
<rule service.forwarding="false" from_var="vlr" />
<rule service.forwarding="true" from_var="msc" />
</rules>
</variable>
</global>
...
This variable configuration sets the following:
- The variables
msc
andvlr
set with a value as per the received field from the network. The variablemsc
must be able to be set or an error will be raised. - A variable
network
that will have the literal values ofhome
ornational_roaming
with an appropriate VLR or MSC prefix or will otherwise be marked asroaming
. This variable will be added to the EDR table under the keyNET
. - The variable
location
to set the call location string. The value for these field is dependent on the type of the call.
Variables are assigned their values in the order configured. Later variable rules may therefore refer to previous variable values if
required as shown with the network
variable definition above.
Variable names and their values may also be written to EDRs automatically by LogicApp services as part of
variable function execution. Only variables with a defined edr
parameter will be written.
All variables defined must have a name
parameter applied, and must contain at least one rule
. Note that no catch-all rule
is required for variables; if no rule applies no value will be given to the variable (and it will not be created).
Variable Configuration
All variable configuration is part of the LogicApp service’s VARIABLES
global. Each variable may have the following attributes:
Attribute | Type | Description |
---|---|---|
name |
String | Required The name of the variable. Must be unique. |
mandatory |
Boolean | Whether the variable is required to be populated or not. If no suitable value can be found for a variable marked as mandatory , an error will be raised. Default = 0 , variable is not mandatory. |
mutable |
Boolean | Whether or not a variable value selection may be updated on a subsequent variable population attempt. Default = 0 , don’t allow update. |
edr |
String | An EDR key to write the variable’s value to. Will be converted to uppercase automatically. If not specified, the variable will not be written to the EDR. |
A variable must then contain a rules
child parameter with its type
explicitly set to array
. Within the rules
parameter,
Selector Rules can be specified in order to set the variable’s value.
Variable Functions
Set Variable Values
The function rule_engine.set_variable_values
is used to populate the service context variables from received input. It will also
validate the global VARIABLES
configuration if not already done.
This function takes the following parameters:
Attribute | Type | Description |
---|---|---|
input_context |
Table | Required The received input context object from the underlying service. |
service_context |
Table | Required The service’s context object. |
edr |
Table | Required The service’s current EDR keys and values. |
This function does not return anything. Variable values and EDR fields are updated directly within the service context or EDR table.
A Lua error
will be thrown if a processing failure occurs.