Rule language for decentralized business processes

Working Draft,

This version:
https://mellonscholarlycommunication.github.io/spec-rulelanguage
Editors:
(IDLab - Ghent University)
(meemoo - Flemish Institute for Archiving)
(IDLab - Ghent University)
(IDLab - Ghent University)

Abstract

This document specifies the definition and application of a rule language to capture machine-readable business processes.

1. Set of documents

This document is one of the specifications produced by the ResearcherPod and ErfgoedPod project:

  1. Overview

  2. Orchestrator

  3. Data Pod

  4. Rule language (this document)

  5. Artefact Lifecycle Event Log

  6. Notifications

  7. Collector

2. Introduction

Introduction here.

3. Rulebook language

A Rulebook is set of machine-readable business rules that instruct the Orchestrator what Actions to take in response to a Trigger such as incoming LDN notifications.

To demonstrate the capabilities of the policies and possible use-cases it should cover, we introduce a pseudo rule language which acts as a guide to find reference implementations. Our pseudolanguage combines features of Drools and SPARQL. Examples are given how some of the features of this language can be implemented in a concrete implementation.

Each rule in a rulebook has the structure of rulebook, rule, when, then clauses:

rulebook Description?

# This is a comment

[Prefix]*

rule Description?

[Prefix]*

when

[Condition] *

then

[Action] *

A rulebook can have one or more rule-s. Each rule has one when clause that contains zero or more conditions that need to match for a graph. Each rule has one then clause that contains zero or more actions, new generated triples, when an input graph matches the conditions. The rulebook section and each rule can define prefix abbreviations for triple patterns. All lines starting with an hash (#) are interpreted as comments.

3.1. Simple example

An example of a simple rule:

rule "Add to the EventLog"

ex:   <http://example.org/>
as:   <https://www.w3.org/ns/activitystreams#>
rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
pol:  <https://www.example.org/ns/policy#>
fno:  <https://w3id.org/function/ontology#>

when

  ?s a as:Announce . OR
    ?s a as:Create .

then

  ?s pol:policy [
      a fno:Execution ;
      fno:executes ex:appendToLog
  ] .
  ?s pol:policy [
      a fno:Execution ;
      fno:executes ex:removeBlindCopies
  ] .

Given an LDN Notification:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "" ,
  "type": "Create" ,
  "object": "http://miel.data.pod/publications/mellon.pdf",
  "target": "http://ruben.data.pod/inbox",
  "bcc": [
   "http://patrick.data.pod/inbox",
   "http://jeroen.data.pod/inbox"
   ]
}

the rules will result in an output:

@prefix ex:   <http://example.org/> .
@prefix as:   <https://www.w3.org/ns/activitystreams#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix pol:  <https://www.example.org/ns/policy#> .
@prefix fno:  <https://www.example.org/ns/policy#> .

<http://this.document> pol:policy [
      a fno:Execution ;
      fno:executes ex:appendToLog
] .
<http://this.document> pol:policy [
      a fno:Execution ;
      fno:executes ex:removeBlindCopies
] .

These resulrs could start up an Orchestrator process that adds the Create event to the EventLog and removes the bcc blind copies.

3.2. Conditions

Conditions in the when clause are interpreted as boolean statements. When the condition is in the format of a triple, it means the existence of the triple in the input data. This behavior matches SPARQL WHERE clause statements:

when
    ?s foaf:name "Herbert"  .      # a property foad:name equals "Herbert" shoud exist
    ?s ?p  42  .                   # a property with value 42 should exist
    ?s/as:object nrr:reviews ?o  . # a nested ?s/as:object/nrr:reviews should exist

Functions in our pseudolanguage mimic the SPARQL FILTER statements:

(?s ?p ?o) -> SomeFunction with (?s,?p,?o)

Some examples:

when
    # a resource has a class that is an as:Announce or as:Accept
    (?s a ?class) -> ?class IN (as:Announce , as:Accept) .

    # a propety needs to have a case-insensitive name "yahoo"
    (?s ?p ?o) -> regex(?o, "yahoo",i) .

    # the as:object needs to have an IRI value
    (?s as:object ?o) -> isIRI(?o) .

    # the as:objects needs to have an IRI value or is a blankNode
    (?s as:object ?o) -> isIRI(?o) OR isBlank(?o) .

    # the isLocalEventResouce should return a true value for the as:object value
    (?s as:object ?o) -> isLocalEventResouce(?o)

    # the predicate and object should return a true value from myLocalFunction
    (?s ?p ?o) -> myLocalFunction(?p, ?o) .

    # combine with booleans
    (?s as:object ?o) -> isIRI(?o) OR isBlank(?o) .
        OR ?s my:justATest true .

3.3. Actions

Actions are a list of zero or more statements that mimic the triples that are generated by the SPARQL CONSTRUCT statement:

then

    ?this pol:policy [
      a fno:Execution ;
      fno:executes ex:sendMessage ;
      ex:to "http://my.institute.org/inbox" ;
      ex:from :Me ;
      ex:message "Hello world"
    ] .

    ?this pol:policy [
      a fno:Execution ;
      fno:executes ex:appendToLog
    ] .

    (?this ?_ ?_) -> SomeFunctionThatGeneratesTriplesFor(?this) .

3.4. Result

The result of a rule execution is the generation of zero or more triples. These generated triples create a graph independent from the input graph of the rule engine. Rules can’t influence each other. This mimics the style of rule processing in SHACL.

An example:

rule "First rule"

when
   ?s ?p ?o .

then
   ?s my:match "first rule" .

#---    
rule "Second rule" when ?s ?p ?o . then ?s my:match "second rule" . #---
rule "Third rule" when ?s ?p ?o . then ?s my:match "third rule" .

When these three rules are excuted against any input graph, it will result in two graphs: the input graph and the result graph which contains:

my:input_id my:match "third rule" .
my:input_id my:match "first rule" .
my:input_id my:match "second rule" .

Note: the order in which the rules are executed is not specified.

4. Examples

4.1. Receving Linked Data Notifications

We demonstrate here how a rule can be created that acts on incoming Linked Data Notifications.

This rule will request to add an AS2 Offer to the EventLog:

rule "Add offer to the EventLog"

ex:   <http://example.org/>
as:   <https://www.w3.org/ns/activitystreams#>
rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
pol:  <https://www.example.org/ns/policy#>
fno:  <https://w3id.org/function/ontology#>

when

  ?s a as:Offer .

then
  ?s pol:policy [
    a fno:Execution ;
    fno:executes ex:appendToLog
  ] .

Given the following JSON-LD input:

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "http://purl.org/coar/notify"
  ],
  "actor": {
    "id": "https://orcid.org/0000-0002-1825-0097",
    "ldp:inbox": "https://josiahcarberry.com/ldn/inbox",
    "name": "Josiah Carberry",
    "type": [
      "Person"
    ]
  },
  "id": "urn:uuid:0370c0fb-bb78-4a9b-87f5-bed307a509dd",
  "object": {
    "id": "https://origin-system.org/resources/0021",
    "ietf:cite-as": "https://doi.org/10.4598/12123487",
    "type": [
      "Document"
    ]
  },
  "origin": {
    "id": "https://origin-system.org",
    "ldp:inbox": "https://origin-system.org/inbox/",
    "type": [
      "Service"
    ]
  },
  "target": {
    "id": "https://target-system.org",
    "ldp:inbox": "https://target-system.org/inbox/",
    "type": [
      "Service"
    ]
  },
  "type": [
    "Offer"
  ]
}

The rulebook above will result in a new graph with these triples:

@prefix ex:   <http://example.org/> .
@prefix as:   <https://www.w3.org/ns/activitystreams#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix pol:  <https://www.example.org/ns/policy#> .
@prefix fno:  <https://www.example.org/ns/policy#> .

<urn:uuid:0370c0fb-bb78-4a9b-87f5-bed307a509dd> pol:policy [
        a fno:Execution ;
        fno:executes ex:appendToLog
] .

A rulebook interpeter, such as the Orchestrator, could use the new generated graph to write a copy of the notification in some way to the Artefact Lifecycle Event Log. The pol:AppendToLog is interpreted in this way as some agreed procedure call that needs to be executed on the JSON-LD input.

4.2. Other Triggers

AS2 Notifications can not only be generated by external actors but also internal local processes. For instance, at periodic intervals the Orchestrator can monitor an (external) resource. When the state of a resource changes, then it can trigger the creation of a AS2 notification. The rulebook can act on these notifications and decide what to do with this information.

How these internal trigger notifications get generated is outside the scope of this specification. We assume that the activation of a trigger results in the generation of an AS2 notification.

4.2.1. Observing resource state changes

This trigger is generated when a monitored (external) resource has a state change.

In the example below a new resource http://my.instutution.org/people/124/publications/a03218h was created by http://my.instutution.org/people/124. The Orchestrator is triggered — by itself or an external trusted source — of this fact using the AS2 notification:

{
  "@context": [
      "https://www.w3.org/ns/activitystreams",
      "https://www.example.org/ns/policy"
  ] ,
  "type": [ "Create" , "pol:StateTrigger" ] ,
  "actor": "http://my.instutution.org/people/124" ,
  "object": "http://my.instutution.org/people/124/publications/a03218h" ,
  "summary": "A new publication was created by person 1234"
}

A rulebook to send emails when these types of StateTrigger occur can be defined as follows:

rule "Add State Trigger definitions"

ex:   <http://example.org/>
as:   <https://www.w3.org/ns/activitystreams#>
rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
pol:  <https://www.example.org/ns/policy#>
fno:  <https://w3id.org/function/ontology#>

when

  ?s a pol:StateTrigger . AND
    ?s a as:Create .

then
  ?s pol:policy [
      a fno:Execution ;
      fno:executes ex:sendEmail ;
      ex:from "my@myself.and.i" ;
      ex:to "you@yourself.edu" ;
      ex:subject "A new resource was created!"
  ] .

The execution of the rulebook will result in a new graph with these triples:

@prefix ex:   <http://example.org/> .
@prefix as:   <https://www.w3.org/ns/activitystreams#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix pol:  <https://www.example.org/ns/policy#> .
@prefix fno:  <https://www.example.org/ns/policy#> .

_:b0 pol:policy [
    a fno:Execution ;
    fno:executes ex:sendEmail ;
    ex:from "my@myself.and.i" ;
    ex:to "you@yourself.edu" ;
    ex:subject "A new resource was created!"
] .

Some SendEmail process could use this input with the AS2 notification above to send an email to you@yourself.edu about the new resource.

We assume there are some reasonable security measures in place, such as digital signatures, to limit the applications that are allowed to send these type of trigger events to the rulebook engine.

4.2.2. Scheduled trigger

A scheduled trigger is defined as a recurrent activity at a scheduled interval. In the example below we assume that cron based process is capable to generate an AS2 notification at a specific time. We assume that every Friday at 17:00 CEST the Weekend trigger is activated.

{
  "@context": [
      "https://www.w3.org/ns/activitystreams",
      "https://www.example.org/ns/policy"
  ] ,
  "summary": "Time Trigger",
  "name": "Weekend",
  "type": [ "Announce" , "pol:DateTimeTrigger" ],
  "startTime": "2021-07-09T17:00:00-01:00"
}

A policy rule could be that on weekends a notification is send out to your friends:

rule "Add State Trigger definitions"

ex:   <http://example.org/>
as:   <https://www.w3.org/ns/activitystreams#>
rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
pol:  <https://www.example.org/ns/policy#>
fno:  <https://w3id.org/function/ontology#>

when

  ?s a pol:DateTimeTrigger . AND ?s a as:Announce .
  ?s as:name "Weekend" .

then
  ?s pol:policy [
    a fno:Execution ;
    fno:executes ex:sendActivity ;
    ex:body [
      a as:Activity ;
      as:actor [
        a as:Person ;
        as:name "Sally";
      ] ;
      as:object [
        a as:Note ;
        as:name "Let’s go to the pub"
      ] ;
      as:to <http://pod.me/my#friends>
    ]
  ] .

5. Implementation Hints

5.1. SPARQL

Example 2 - Add to the EventLog

PREFIX ex: <http://example.org/>
PREFIX as: <https://www.w3.org/ns/activitystreams#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX pol: <https://www.example.org/ns/policy#>
PREFIX fno: <https://w3id.org/function/ontology#>

CONSTRUCT {
  ?this pol:policy [
      a fno:Execution ;
      fno:executes ex:appendToLog
  ] .
  ?this pol:policy [
      a fno:Execution ;
      fno:executes ex:removeBlindCopies
  ] .
}
WHERE {
  ?this a ?type .
  FILTER ( ?type IN (as:Announce , as:Create) )
}

Example 5 - Conditions

PREFIX ex: <http://example.org/>
PREFIX as: <https://www.w3.org/ns/activitystreams#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX pol: <https://www.example.org/ns/policy#>
PREFIX fno: <https://w3id.org/function/ontology#>
CONSTRUCT {
  ...
}
WHERE {
  ?this foaf:name "Herbert"  .
  ?this ?p  42  .
  ?this/as:object nrr:reviews ?o .
}

Example 7 - Function Examples

PREFIX ex: <http://example.org/>
PREFIX as: <https://www.w3.org/ns/activitystreams#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX pol: <https://www.example.org/ns/policy#>
PREFIX fno: <https://w3id.org/function/ontology#>
CONSTRUCT {
  ...
}
WHERE {
  ?this a ?class .
  ?this foo:name ?foo_val .
  ?this as:object ?object_val .

  FILTER ( ?class IN (as:Announce , as:Accept)  )
  FILTER ( regex(?foo_val, "yahoo", i) )
  FILTER ( isIRI(?object_val) || isBlank(?object_val) )
}

5.2. Notation3

Example 2 - Add to the EventLog

PREFIX ex: <http://example.org/>
PREFIX as: <https://www.w3.org/ns/activitystreams#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX pol: <https://www.example.org/ns/policy#>
PREFIX fno: <https://w3id.org/function/ontology#>
PREFIX list: <http://www.w3.org/2000/10/swap/list#>

{
  ?s a ?class .
  ?class list:in (as:Announce as:Create) .
}
=>
{
  ?s pol:policy [
      a fno:Execution ;
      fno:executes ex:appendToLog
  ] .
  ?s pol:policy [
      a fno:Execution ;
      fno:executes ex:removeBlindCopies
  ] .
} .

Example 5 - Conditions

PREFIX ex: <http://example.org/>
PREFIX as: <https://www.w3.org/ns/activitystreams#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX pol: <https://www.example.org/ns/policy#>
PREFIX fno: <https://w3id.org/function/ontology#>

{
  ?this foaf:name "Herbert"  .
  ?this ?p  42  .
  ?this!as:object nrr:reviews ?o .
}
=> {
  ...
} .

Example 7 - Function Examples

PREFIX ex: <http://example.org/>
PREFIX as: <https://www.w3.org/ns/activitystreams#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX pol: <https://www.example.org/ns/policy#>
PREFIX fno: <https://w3id.org/function/ontology#>
PREFIX list: <http://www.w3.org/2000/10/swap/list#>
PREFIX string: <http://www.w3.org/2000/10/swap/string#>
PREFIX math: < http://www.w3.org/2000/10/swap/math#>

{
   ?this a ?class .
   ?class list:in (as:Announce  as:Accept) .

   ?this foo:name ?foo_val .
   ?foo_val string:matches "yahoo" .

   ( 1 2 3 4 5) math:product ?product .
}
=>
{
   ...
} .

More Notation3 examples are available at https://github.com/MellonScholarlyCommunication/spec-rulelanguage/tree/master/examples/n3.

6. Acknowledgement

We thank Herbert Van de Sompel, DANS + Ghent University, hvdsomp@gmail.com for the valuable input during this project.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

References

Normative References

[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119