Skip to content

aasaru/paasuke-rule-engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pääsuke rule engine.

This is the code base that Pääsuke, part of the Estonian state portal (https://eesti.ee/volitused) uses to calculate what is available for the user (which roles can add and what the user can do with the mandates (authorisations) the user already has

ph-namespace-adapter

This application has a rule engine that performs the following checks:

  1. AddableRoles: (before user can start adding roles it) decides the list of roles user is allowed to add
  2. VerifyMandateOperations: when the user adds a mandate, it checks that the user has the right to add this role
  3. VerifyMandateLinks: when the user is looking at the mandates, then the rule engine checks, which actions (delete and addSubDelegate) for each mandate are allowed for the user

Structure

Model module

Contains Pojos and utility classes used by the drools module. It is in a separate module because drools maven plugin does not work well together with lombok annotations on the classes. So the classes used are in this separate module and drools module can use compiled classes from here.

Drools module

Contains drools rules and queries. Uses the kie-maven-plugin to generate neccessary classes for rules. Depends on the model module. The main purpose is offer the ee.eesti.paasuke.namespaceadapterapp.query.Queries class to other modules.

Web module

Uses the drools module and offers rest services for performing drools queries.

Installing and Running

Prerequisites

You will need:

  • Java 11+ (19 is fine)

Compile and Run

NB! Maven has a plugin that generates classes based on Drools rules

./mvnw clean compile spring-boot:run

OpenAPI (Swagger) documentation

Is available here

If Swagger is empty, then most likely you haven't generated classes (using ./mvnw compile)

Understanding what the rules (in *.drl files) are doing

If you have little or no knowledge about Drools rule engine, then first just try reading the rule names (first line starting with "rule ...")

For example, if rule name is: "User can add the role if user has a role in addableBy list" then the rule is just trying to find all the rules that satisfy these criteria and make them addable.

Follow these guidelines when writing new rules into *.drl files

  1. Rule name must describe what the rule is doing
  2. Rule file name must start with what action it affects (or if it is creating a query then start with "queries")
  3. If you want to log in the *.drl rule then use on of:
    • AddableRoles.log,
    • VerifyMandateLinks.log
    • or VerifyMandateOperations.log()
    • NB! what class you're using for logging has to match the *.drl file name
  4. Having separate classes for logging allows later to configure different levels for different loggers
    • For example, one could switch on logging for verifying mandate links but switch off logging for others.
    • In order to get the logs created by rules in *.drl in logback configuration, set the level to DEBUG and set higher (WARN) if you don't want logs:
  <logger name="ee.eesti.paasuke.namespaceadapterapp.logging.AddableRolesLogger" level="debug"/>
  <logger name="ee.eesti.paasuke.namespaceadapterapp.logging.VerifyMandateOperations" level="debug"/>
  <logger name="ee.eesti.paasuke.namespaceadapterapp.logging.VerifyMandateLinks" level="debug"/>
  1. If you need to make one rule depend on another, then (for performance reasons) do not modify() or update() the object if possible. Instead, add a new object to the working memory.

    For example, let's look at a use case where rule A sets a value to: MandateTriplet -> Mandate -> VerifiedLink -> delete

    There is rule B that depends on this fact. This is why we should inform Drools that we have changed the MandateTriplet, but looking up this object would have a significant performance impact

    Instead, the rule A (besides modifying the VerifiedLinks -> delete property), adds an additional fact: verifiedAddSubDelegateLinks.add( newFactObject)

    And rule B checks the presence of this fact object.

Tips for development

The *.drl rules are compiled into Java code (don't try to read that generated code, it is not very intuitive)

If you modify any of the Drools rules (*.drl files) then how to get new code:

  1. Use the Maven plugin of your IDE to run kogito -> kogito:generateModel
  2. Use maven: ./mvnw -DskipTests=true clean compile

And then use your IDE to run a test that covers that specific scenario.

Learn more

  • Look at the tests!
  • Switch on .log().all() in tests

Writing tests

Model classes for tests (classes with suffix "Pojo")

When you want to construct custom payloads or map responses, then use model classes (class name ends with "Pojo") from the tests directory (src/test/java/ee/eesti/paasuke/namespaceadapterapp/testmodel) The reason is that application's own model classes have business logic inside, making them unsuitable for regular POJOs that are just needed to carry data.

Namespace-adapter configuration properties

Parameter Mandatory Description, example
namespace.store.url yes Where to pull the list of role definitions
namespace.store.queryTimeoutMillis no Response timeout for namespace store requests (defaults to 5000ms)
namespace.store.cacheTimeToLiveSeconds no How long the roles query is cached for (defaults to 10 seconds)

Releases

No releases published

Packages

No packages published