Skip to content

Commit

Permalink
Reporting docs (finos#636)
Browse files Browse the repository at this point in the history
* Initial

* WIP

* Created new docs

* Updated description

* Converted to Demo model

* Update rosetta-java-documentation.md

* Fixed typo

---------

Co-authored-by: Hugo Hills <39260692+hugohills-regnosys@users.noreply.github.com>
  • Loading branch information
SimonCockx and hugohills-regnosys authored Sep 7, 2023
1 parent eafdcf2 commit ea556a9
Show file tree
Hide file tree
Showing 4 changed files with 412 additions and 65 deletions.
158 changes: 158 additions & 0 deletions documentation/rosetta-java-documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
---
title: "Rosetta Java Documentation"
date: 2023-09-01T12:57:00+02:00
description: "This document describes the interface and usage of classes that are generated from a Rosetta model using the Java code generator."
draft: false
weight: 2
---

# Rosetta Java Documentation

## Types and enums

Coming soon.

## Functions

Coming soon.

## Validation

Coming soon.

## Reports and rules

Both reports and rules are represented in the same way as a [function](#functions). They implement the `ReportFunction<IN, OUT>` interface, which extends from `RosettaFunction`, and additionally exposes an `evaluate` method that takes in a single parameter of type `IN` (the input of a report, e.g., a `ReportableEvent`) and has a result of type `OUT` (the report output, e.g., a `CFTCPart43TransactionReport`).

### Example: European Emission Report

As a simple example, consider the following report definition:
``` Haskell
report EuropeanParliament EmissionPerformanceStandardsEU in real-time
from VehicleOwnership
when IsEuroStandardsCoverage
with type EuropeanParliamentReport

// Definition for regulatory references:
body Authority EuropeanParliament
corpus Regulation "Regulation (EU) 2019/631" EmissionPerformanceStandardsEU
```
This report takes an input of type `VehicleOwnership`, and returns an instance of type `EuropeanParliamentReport`, defined as follows:
``` Haskell
type VehicleOwnership:
drivingLicence DrivingLicence (1..1)
vehicle Vehicle (1..1)

type EuropeanParliamentReport:
vehicleRegistrationID string (1..1)
[ruleReference VehicleRegistrationID]
vehicleClassificationType VehicleClassificationEnum (1..1)
[ruleReference VehicleClassificationType]

type Vehicle:
registrationID string (1..1)
vehicleClassification VehicleClassificationEnum (1..1)

enum VehicleClassificationEnum:
M1_Passengers
M2_Passengers
M3_Passengers
N1I_Commercial
...

type Person:
name string (1..1)

type DrivingLicence:
owner Person (1..1)
countryofIssuance string (1..1)
dateofIssuance date (1..1)
dateOfRenewal date (0..1)
vehicleEntitlement VehicleClassificationEnum (0..*)
```

The report is supported by the following rules.

``` Haskell
eligibility rule IsEuroStandardsCoverage from VehicleOwnership:
filter
vehicle -> vehicleClassification = VehicleClassificationEnum -> M1_Passengers
or vehicle -> vehicleClassification = VehicleClassificationEnum -> M2_Passengers
or vehicle -> vehicleClassification = VehicleClassificationEnum -> M3_Passengers
or vehicle -> vehicleClassification = VehicleClassificationEnum -> N1I_Commercial
or ...

reporting rule VehicleRegistrationID from VehicleOwnership:
extract vehicle -> registrationID
as "Vehicle Registration ID"

reporting rule VehicleClassificationType from VehicleOwnership: <"Classification type of the vehicle">
extract vehicle -> vehicleClassification
as "Vehicle Classification Type"
```

#### Generated Java Code

In Java, the report is represented by the following class:
``` Java
@ImplementedBy(EuropeanParliamentEmissionPerformanceStandardsEUReportFunction.EuropeanParliamentEmissionPerformanceStandardsEUReportFunctionDefault.class)
public abstract class EuropeanParliamentEmissionPerformanceStandardsEUReportFunction implements ReportFunction<VehicleOwnership, EuropeanParliamentReport> {
@Override
public EuropeanParliamentReport evaluate(VehicleOwnership input) {
EuropeanParliamentReport.EuropeanParliamentReportBuilder outputBuilder = doEvaluate(input);

... // build the output and perform validation

return output;
}

protected abstract EuropeanParliamentReport.EuropeanParliamentReportBuilder doEvaluate(VehicleOwnership input);

public static class EuropeanParliamentEmissionPerformanceStandardsEUReportFunctionDefault extends EuropeanParliamentEmissionPerformanceStandardsEUReportFunction {
@Override
protected EuropeanParliamentReport.EuropeanParliamentReportBuilder doEvaluate(VehicleOwnership input) { ... }
}
}
```
Note that we rely on the Guice dependency injection framework to separate specification (`EuropeanParliamentEmissionPerformanceStandardsEUReportFunction`) from implementation (`EuropeanParliamentEmissionPerformanceStandardsEUReportFunctionDefault`). The default implementation will delegate to the `VehicleRegistrationID` and `VehicleClassificationType` reporting rules, as specified in the Rosetta model.

{{< notice info "Note" >}}
The implementation of a report or a specific reporting rule can be customized by binding their Java class to a custom implementation in your Guice module.
{{< /notice >}}

#### Running a report

To run the report, we first need to inject a report function instance using any conventional method delivered by Guice. An example:
``` Java
@Inject
private EuropeanParliamentEmissionPerformanceStandardsEUReportFunction reportFunction;

@Test
private void testReportFunction() {
VehicleOwnership input = ... // create or read a vehicle ownership instance
EuropeanParliamentReport reportOutput = reportFunction.evaluate(input);

assertEquals(input.getVehicle().getRegistrationID(), reportOutput.getVehicleRegistrationID());
}
```

### Running a report that relies on rules annotated with `[legacy-syntax]`

Some reporting rules you might encounter in a Rosetta model are marked with the `[legacy-syntax]` annotation. They are written in a deprecated syntax, and they need an additional Guice binding in order to work - otherwise you will see an exception during injection. Consequently, a report definition that relies in some way on a reporting rule annotated with `[legacy-syntax]` needs this binding as well.

To run such a report, add the following binding to your Guice module.
``` Java
bind(RosettaActionFactory.class).to(RosettaActionFactoryImpl.class);
```
You might need to add a dependency to the proprietary `rosetta-reports` artifact in order to import the `RosettaActionFactoryImpl` class.
``` xml
<dependency>
<groupId>com.regnosys</groupId>
<artifactId>rosetta-reports</artifactId>
<version>7.6.3</version>
</dependency>
```

{{< notice info "Note" >}}
Support for `[legacy-syntax]` will be dropped in the near future, and the `rosetta-reports` repository will be archived.
{{< /notice >}}
82 changes: 17 additions & 65 deletions documentation/rosetta-modelling-component.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Rosetta Modelling Components"
date: 2022-02-09T00:38:25+09:00
description: "This documentation details the purpose and features of each type of model component and highlights their relationships. Examples drawn from the Demonstration Model, a sandbox model of the 'vehicle' domain, will be used to illustrate each of those features."
date: 2023-09-01T12:57:00+02:00
description: "This document details the purpose and features of each type of model component and highlights their relationships. Examples drawn from the Demonstration Model, a sandbox model of the 'vehicle' domain, are used to illustrate each of those features."
draft: false
weight: 2
---
Expand Down Expand Up @@ -1360,10 +1360,6 @@ func GetDrivingLicenceNames: <"Get driver's names from given list of licences.">
then extract firstName + " " + surname
```

{{< notice info "Note" >}}
The `assign-output` keyword also exists as an alternative to `set` and can be used with the same syntax. However, the `assign-output` keyword does not consistently treat single-cardinality (overrides the value) and list (appends the value) objects. It is therefore being phased out in favour of `set` and `add` that clearly separate those two cases.
{{< /notice >}}

**The Rosetta DSL supports a number of fully defined function cases**, where the output is being built up to a valid state:

- Object qualification
Expand Down Expand Up @@ -1398,7 +1394,7 @@ func Qualify_InterestRate_IRSwap_FixedFloat_PlainVanilla:

#### Calculation Function

A calculation function defines a calculation output that is often, though not exclusively, of type `number`. It must end with a `set` (or `assign-output`) instruction that fully defines the calculation result.
A calculation function defines a calculation output that is often, though not exclusively, of type `number`. It must end with a `set` instruction that fully defines the calculation result.

Calculation functions are associated to the `calculation` [annotation](#annotation).

Expand All @@ -1417,7 +1413,7 @@ func FixedAmount:
alias fixedRateAmount: fixedRate -> rate
alias dayCountFraction: DayCountFraction(interestRatePayout, interestRatePayout -> dayCountFraction, date)

assign-output fixedAmount:
set fixedAmount:
calculationAmount * fixedRateAmount * dayCountFraction
```

Expand All @@ -1435,7 +1431,7 @@ Short-hand functions are functions that provide a compact syntax for operations
func PaymentDate:
inputs: economicTerms EconomicTerms (1..1)
output: result date (0..1)
assign-output result: economicTerms -> payout -> interestRatePayout only-element -> paymentDate -> adjustedDate
set result: economicTerms -> payout -> interestRatePayout only-element -> paymentDate -> adjustedDate
```

which could be invoked as part of multiple other functions that use the `EconomicTerms` object by simply writing:
Expand Down Expand Up @@ -1471,8 +1467,8 @@ func Max:
b number (1..1)
output:
r number (1..1)
assign-output r:
if (a>=b) then a
set r:
if a >= b then a
else b
func WhichIsBigger:
Expand All @@ -1481,7 +1477,7 @@ func WhichIsBigger:
b number (1..1)
output:
r string (1..1)
assign-output r:
set r:
if Max(a,b)=a then "A" else "B"
```

Expand Down Expand Up @@ -1901,7 +1897,7 @@ The next section describes how to define reporting rules as model components.

The Rosetta DSL applies a functional approach to the process of regulatory reporting. A regulatory rule is a functional model component (*f*) that processes an input (*x*) through a set of logical instructions and returns an output (*y*), such that *y = f( x )*. A function can sometimes also be referred to as a *projection*. Using this terminology, the reported data (*y*) are considered projections of the business data (*x*).

For field rules, the output consists of the data to be reported. For eligibility rules, this output is a boolean that returns True when the input is eligible for reporting.
For field rules, the output consists of the data to be reported. For eligibility rules, this output is a boolean that returns `True` when the input is eligible for reporting.

To provide transparency and auditability to the reporting process, the Rosetta DSL supports the development of reporting rules in both human-readable and machine-executable form.

Expand All @@ -1927,45 +1923,17 @@ The `<ruleType>` can be either `reporting` or `eligibility` (in which case it mu

The functional expression of reporting rules uses the same [logical expression](#expression-component) components that are already available to define other modelling components, such as data validation or functions.

Functional expressions are composable, so a rule can also call another rule. When multiple rules may need to be applied for a single field or eligibility criteria, those rules can be specified in brackets separated by a comma, as illustrated below. Each of `Euro1Standard`, ..., `Euro6Standard` are themselves reporting rules.
Functional expressions are composable, so a rule can also call another rule, as illustrated below. Each of `Euro1Standard`, ..., `Euro6Standard` are themselves reporting rules.

``` Haskell
reporting rule EuroEmissionStandard from ReportableEvent:
[regulatoryReference EuropeanCommission StandardEmissionsEuro6 article "1"
[regulatoryReference EuropeanCommission StandardEmissionsEuro6 article "1"
provision "Regulation (EC) No 715/2007 is amended as follows:..."]
(
Euro1Standard as "Emission Standards",
Euro2Standard as "Emission Standards",
Euro3Standard as "Emission Standards",
Euro4Standard as "Emission Standards",
Euro5Standard as "Emission Standards",
Euro6Standard as "Emission Standards"
)
```

In addition to those existing functional features, the Rosetta DSL provides specific reporting instruction components:

- extract
- filter
- repeat

Those components are documented in the next sections.

##### Extract Instruction

An extraction instruction defines a value to be either reported or used as input into another rule or instruction. The extraction keywords comprise:

- `extract`
- `then`
- `as`

The extraction syntax is:

``` Haskell
extract <Expression1>
then extract <Expression2>
<...>
(optional: as <"Label">)
if Euro1Standard exists
then Euro1Standard
else if Euro2Standard exists
then Euro2Standard
as "Emission Standards"
```

The expressions may use any type of [expression component](#expression-component) available in the Rosetta DSL, from simple path expressions or constants to more complex conditional statements, as illustrated below:
Expand Down Expand Up @@ -2006,23 +1974,7 @@ reporting rule FirstRegistrationDate from VehicleOwnership: <"Date of first regi
as "First Registration Date"
```

##### Filtering Rules

A filter instruction takes a list of input objects and return a subset of them. The output type of the rule is always the same as the input, and of multiple cardinality. The syntax is:

``` Haskell
filter <FunctionalExpression>
```

The `filter` keyword takes each input value and uses it as input to a provided test expression. The result type of the test expression must be boolean and its input type must be the input type of the filter rule. If the expression returns true for a given input, that value is included in the output.

The functional expression can be either a direct boolean expression or the output of another rule whose output is a boolean, in which case the syntax is:

``` Haskell
filter <RuleName>
```

Filter expressions can be combined with extraction expressions. The example below extracts the date of first registration for a list of passenger-type vehicles only:
The example below extracts the date of first registration for a list of passenger-type vehicles only:

``` Haskell
extract vehicle
Expand Down
Loading

0 comments on commit ea556a9

Please sign in to comment.