This document is an introductory guide that presents the Natural Rule Language (NRL) to those who have never used it or heard of it before. The Natural Rule Language is an open specification hosted on SourceForge, at http://nrl.sourceforge.net. Its principal purpose is to enable the expression of constraints over models in a restricted language that is reasonably close to English.
The web site contains some related documents, most importantly the language specification and also a guide to advanced NRL concepts. It also contains a collection of example rule sets that can provide further insight into the language.
This document is under copyright ©2006 by its authors:
NRL rules are written against a model. This model can have a number of sources: UML, XML Schema or even Java source code. In this user guide we will work exclusively with a UML model.
It is important to understand the meaning of a model if one wants to write rules against it. So let us first look at an example model and establish its purpose:
This UML diagram is a simple, quite generic model of a settlement transaction. Broadly speaking, a settlement is financial jargon for parties involved in a contract paying each other money. The Transaction class has a date when the transaction was executed and a type: this will be PAYMENT for us, but could be set to something else for other types of transactions.
A number of parties are involved in a transaction. The transaction also contained a number of settlements, which signify money passing from one party to another. A quick note on reading UML diagrams may be useful here: the class Transaction has a property called parties - we know this because the role label on the opposite side of the association between Transaction and Party.
Let's now look at some sample NRL rules expressed over this model. This NRL files is complete and correct and could be used in practice:
Model
"userguide.uml2"
Context:
Transaction
Validation Rule "t1"
If the type is equal to 'PURCHASE' then exactly two parties are present
Context: Settlement
Validation Rule "s2"
discount is greater than or equal to
0 and discount is less than or equal to 1
Context: Settlement
Validation Rule "d1"
transaction.date is before
settlementDate.date
Context: Settlement
Validation Rule "c1"
The
settlementCurrency.ccyCode is equal to
'GBP'
Context: Settlement
Validation Rule "s1"
netAmount is equal to
(grossAmount - tax) * (1 - discount)
Context: Transaction
Validation Rule "t2"
In each of the parties the role is
one of 'BUYER', 'RECEIVER'
Context: Address
Validation Rule "a1"
At most two of the
addressComponents have their type equal
to AddressComponentType.StreetAddressLine and exactly one of the
addressComponents has its type equal to
AddressComponentType.StreetAddressPostcode
Context: Transaction
Validation Rule "zero-sum"
If the type is equal to 'SWAP' then the sum of
settlements.grossAmount is equal to
0
If you want to get straight into understanding how to write NRL rules, you can skip this section. We take a quick look at the history of the NRL here and explain why it looks the way it looks.
The NRL was first conceived in a hotel room in New York as an alternative to the CLiX language for specifying constraints over XML documents. It has evolved since then, being used on a project as a replacement for OCL and even as a language for driving a rule engine. The purpose remains the same: to capture "business constraints" over models in a reasonably formal way, while at the same time retaining some readability.
The NRL is a controlled subset of English. This means that whilst business rules usually read just like plain English, NRL prescribes a fixed structure that must be followed. The English language is powerful and expressive, but it is also ambiguous and much richer than is necessary for the task of specifying constraints over business data. Look at the following examples - the first is valid NRL because it obeys the NRL grammar. The second, though it means the same in English, is invalid because it uses symbols like the period at the end of the sentence not available in the NRL, and also uses sentence structures that do not exist in the NRL.
Exactly two parties are present (Valid NRL)
Two parties must be specified. (Invalid)
In order to use the NRL properly you have to ensure
that you:
Provided you do this, there are significant benefits. Most importantly, the NRL is machine translatable. It can be unambiguously parsed and then transformed:
Using NRL helps keep business rules readable and visible to stakeholders, rather than hiding their business constraints in hard-coded program code. It also eliminates the error-prone manual translations normally required to proceed from business analysis to system implementation. In short, the NRL can provide a fragment of a model-driven architecture where constraint validation is automated.
You will have seen from the introductory examples that the NRL lets you write rules against a model. These rules hold relative to some context. The simplest types of rules we can write, then, are those that check the attribute values of the context:
Context: Settlement
Validation Rule "s2"
The discount is greater than or equal to
0
You can compare attributes to other attributes, to numbers of to literal strings. Literal strings are surrounded by single quotes, for example 'PAYER'. All manners of equality and inequality are supported - in both textual and symbolic form:
NRL Text | NRL Text with "is" | Symbol | Comments |
---|---|---|---|
equal to | is equal to | = | |
not equal to | is not equal to | <> | |
greater than | is greater than | > | |
greater than or equal to | is greater than or equal to | >= | |
less than | is less than | < | |
less than or equal to | is less than or equal to | <= | |
before | is before | < | * Convenience notation for dates |
after | is after | > | * Convenience notation for dates |
one of 'STR', 'STR', ... | is one of 'STR', 'STR', ... | Compared value is in a list of strings |
The textual form of the statements usually come with an optional "is". This is useful in compound NRL rules that we will later, for example "one of the parties has a role equal to 'PAYER'", where "is equal to" would leave us with a sentence that does not sound like English.
The symbolic form can be used instead of the text form if preferred - it is particularly useful when performing arithmetic. The following two rules are equivalent:
Context: Settlement
Validation Rule "s2-1"
The discount is greater than or equal to
0
Context: Settlement
Validation Rule "s2-2"
discount >= 0
Simple symbolic arithmetic is supported, as demonstrated in the rule from the example section:
Context: Settlement
Validation Rule "s1"
netAmount is equal to
(grossAmount - tax) * (1 - discount)
The symbols provided are:
In addition, the NRL supports string concatenation using the + symbol. The following rule will never fail:
Context: Party
Validation Rule "p1"
'PAYER' = 'PAY' + 'ER'
The information we want to check is not necessarily always available as an attribute directly in the rule context. In that case, we can make use of the associations in the model to get to our information:
Context: Settlement
Validation Rule "d1"
transaction.date is before
settlementDate.date
Look at this rule closely. Its context is Settlement. We want to check that the transaction date is before the settlement date. Unfortunately, the transaction date is contained in Transaction and the settlement date in an AdjustableDate, not directly as attributes of Settlement. We thus have to navigate to obtain the values. Model navigation:
One other form of navigation is allowed - static attributes or enumeration values can be reference directly, by giving the class or enumeration name followed by the attribute name, as in this rule fragment taken from the introduction that refers to the enumeration AddressComponentType:
Context: Address
Validation Rule "a1"
At most two of the
addressComponents have their
type equal
to AddressComponentType.StreetAddressLine
NRL sentences can be connected using and, or, implies and only if. The NRL also supports sentences of the if-then-otherwise or if-then-else form. We have seen examples of most of these constructs in the introduction:
Context:
Transaction
Validation Rule "t1"
If the type is equal to 'PURCHASE' then exactly two parties are present
Context: Settlement
Validation Rule "s2"
discount is greater than or equal to
0 and discount is less than or equal to 1
In case of any doubt, here is a fuller definition of what is available, and what it means:
NRL Text | Comments |
---|---|
condition and condition | Both conditions must be true |
condition or condition | Either condition (or both) must be true |
condition implies condition | If the first condition is true, the second must be
true. Otherwise, we don't care and the rule holds (e.g. "If I was faster than the speed of light, two would be equal to four) |
condition only if condition | The first condition must be true only if the second is
true. It must be false only if the second is false. |
If condition then condition | Logically, same as condition implies condition |
If condition then condition otherwise condition | Classic if-then-else |
If condition then condition else condition | Classic if-then-else |
It happens that we want to make sure that an element is present or absent under certain conditions, or that a number of elements are present or absent. A rule from the example section demonstrates how this is done:
Context:
Transaction
Validation Rule "t1"
If the type is equal to 'PURCHASE' then exactly two parties are present
The interesting part of the sentence here is "exactly two parties are present". Using this type of NRL rule we can:
In general, these rules are expressed using the keywords "is present" or "are present", together with an optional number that can be used with a collection to specify how many entries must be present. Here are some more examples:
Context:
Transaction
Validation Rule "t1-2"
If the type is equal to 'BROKERPURCHASE' then at least two parties are present and at most three
parties are present
Context: Settlement
Validation Rule "s1"
If a grossAmount is present then a netAmount is present
Checking for absence is also supported, in one of two ways:
Context:
Transaction
Context: Settlement
Validation Rule "s2-1"
If a grossAmount is not present then a netAmount is not present
Context: Settlement
Validation Rule "s2-2"
If no grossAmount is present then no netAmount is present
This table summarises the types of sentences that can be written:
NRL Text | Comments |
---|---|
one element is present | |
two elements are present | |
three elements are present | |
four elements are present | |
5 elements are present | Any integer number can be used. The previous four textual versions are useful for readability. |
no element is present | For attributes with a singular name |
no elements are present | For attributes with a plural name |
element is not present | For attributes with a singular name |
elements are not present | For attributes with a plural name |
Where a sentence uses a number, it can additionally be prefixed with a lower-bound, upper bound, or be required to be exact:
NRL Text | Comments |
---|---|
two elements are present | Same as "exactly two" |
exactly two elements are present | |
at least two elements are present | |
at most two elements are present |
The NRL does not just allow you to check that a collection is empty or non-empty, but also that its members obey certain properties. We can check that some members obey properties or that all members obey them. Here is an example from the introduction:
Context: Address
Validation Rule "a1"
At most two of the
addressComponents have their
type equal
to AddressComponentType.StreetAddressLine and exactly one of the
addressComponents has its type equal to
AddressComponentType.StreetAddressPostcode
The same upper-bound and lower-bound syntax applies as when checking for presence or absence. It is thus not repeated here. Here is how to check that some members of a collection obey certain conditions:
NRL Text | Comments |
---|---|
one element has properties | "properties" must be a simple NRL sentence such as equality comparison |
two elements have properties | "at least two", "at most two" or other numbers can be used, including "no" |
When we want to check more complex conditions, we need some extra syntax. For example, maybe we want to check that for a given transaction, one of the settlements has a gross amount of zero and a net amount of zero. This is not a simple comparison anymore - it is two comparison combined by an "and". In order to delineate the scope, we need to use parentheses for anything other than simple comparisons:
Context: Transaction
Validation Rule "tr-complex"
Exactly one of the
settlements has (a
grossAmount equal
to 0 and a
netAmount equal to 0 )
The reasons for why these parentheses are necessary are a bit complex and to do with grammar ambiguity, but in short: if they were not there, we would not know whether the statement after the "and" was related to the settlements or the overall transaction. Here is a summary table for checking complex properties:
NRL Text | Comments |
---|---|
one element has (complex properties) | |
two elements have (complex properties) | Other numbers can still be used |
These constructs let us check that some members of a collection have certain properties. We can also check that all members have certain properties. This is done by using the words "each", "in each", "all" or "every", as preferred or suitable for a sentence:
Context: Transaction
Validation Rule "t2"
In each of the parties the role is
one of 'BUYER', 'RECEIVER'
Similar to the previous cases, if we want to check more complex properties we have to ensure that we use parentheses:
Context:
Transaction
Validation Rule "t2"
In each of the parties (the role is
one of 'BUYER', 'RECEIVER' and
a name is present)
Here is the summary table:
NRL Text | Complex Properties | Comments |
---|---|---|
each element has properties | each element has (complex properties) | For singular collection names |
each of the elements has properties | each of the elements has (complex properties) | |
in each of the elements properties | in each of the elements (complex properties) | Eliminates the has/have - see example |
all of the elements have properties | all of the elements have (complex properties) | Alternative |
every element has properties | every element has (complex properties) | Alternative |
There are two more things the NRL can do with collections: count the number of entries, and sum up integer values. The former we do with the "number of" keyword, the latter with "sum of":
Context:
Transaction
Validation Rule "swap"
If the type is equal to 'SWAP' then the number of
settlements is equal to 2
Context:
Transaction
Validation Rule "zero-sum"
If the type is equal to 'SWAP' then the sum of
settlements.grossAmount is equal to
0
Note that the first rule can also be written using "two settlements are present". In general, we need to use the "number of" form is we want to compare the number of entries to something other than a literal number, for example another attribute. In the second rule, we're adding up the gross amounts of all settlements and require them to be zero - negative to one party, positive to another.
The NRL "number of" constructs also supports a concept of uniqueness. Imagine that you want to count all parties with unique roles. Maybe our transaction has multiple parties of type 'PAYER', and some other parties, and we want to ensure that the number of unique parties by role is equal to 3. We can do this as follows:
Context:
Transaction
Validation Rule "swap"
If the type is equal to 'COMPLEXPAYMENT' then the number of parties (unique by role )
is equal to 3
Here is the summary of these constructs:
NRL Text | Comments |
---|---|
number of elements | "elements" must refer to an attribute or association
role with a multiplicity of more than one. |
number of elements (unique by attribute) | Groups the collection elements by the attribute and then counts them. |
sum of collection.attribute | The attribute must be numerical |
This guide has covered the basics of the Natural Rule Language. If you understand this, you will be able to cover off most of the day to day constraints that need to be attached to a model.
In order to write more complex rules, visit the NRL Home Page. There is an user guide for advanced users, and very interested rule writers may want to look at the specification, which covers the language in pain-staking detail and provides a full grammar.
©2006 The Authors.