1. Set of documents
This document is one of the specifications produced by the ResearcherPod and ErfgoedPod project:
-
Rule language (this document)
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:
# 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:
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.
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.