Using RIF to Interchange F-Logic Rules and Drools

F-Logic and Drools

The Negotiating eBusiness Contracts Across Rule Platforms Use Case illustrates the usage of RIF to supply a vendor-neutral representation of rules, so that rule-system developers can do their work without concern about a vendor-specific format and in particular without concern about the compatibility with the technology of its business partners.

Below are two rules from the use case:

  • Rule R1: If an item is perishable and it is delivered more than 10 days after the scheduled delivery date then the item will be rejected.
  • Rule R2: If an item is perishable and it is delivered more than 7 days after the scheduled delivery date but less than 14 days after the scheduled delivery date then a discount of 18.7% will be applied to this delivery.

Contents

[hide]

Rules are working on top of vocabularies

First we need to understand the vocabulary on which these rules act i.e. what is an item, scheduled delivery etc. Therefore first I have to develop the rules vocabulary.

Different developers may choose different vocabulary languages do do that. Some of them may choose RDFS, some others may choose OWL or UML. By consequence:

  • RIF needs to deal with different vocabularies.
  • RIF needs an uniform mechanism to address vocabulary elements. The usage of URI's may be such a mechanism.
  • Vocabulary and rules are separate layers

In this document I will use RDFS to represent an excerpt from the entire use case vocabulary.

We assume that:

  • Jane's e-commerce system uses Drools therefore the rules vocabulary is represented using Java beans and
  • John uses an OWL vocabulary and its rules are represented in F-Logic.

Below is an excerpt from the John's OWL vocabulary:

<rdf:RDF 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" 
   xmlns:owl="http://www.w3.org/2002/07/owl#" 
   xmlns="http://www.example.org/JohnSystem/vocabulary">
    <owl:Class rdf:ID="Item"/>
    <owl:DatatypeProperty rdf:ID="perishable">
        <rdfs:domain rdf:resource="#Item"/>
        <rdfs:range rdf:resource="xs:boolean"/>

    </owl:DatatypeProperty>
    <owl:DatatypeProperty rdf:ID="actualDeliveryDate">
        <rdfs:domain rdf:resource="#Item"/>
        <rdfs:range rdf:resource="xs:date"/>
    </owl:DatatypeProperty>
    <owl:DatatypeProperty rdf:ID="scheduledDeliveryDate">

        <rdfs:domain rdf:resource="#Item"/>
        <rdfs:range rdf:resource="xs:date"/>
    </owl:DatatypeProperty>
    <owl:DatatypeProperty rdf:ID="status">
        <rdfs:domain rdf:resource="#Item"/>
        <rdfs:range rdf:resource="Status"/>

    </owl:DatatypeProperty>
    <owl:DatatypeProperty rdf:ID="discount">
        <rdfs:domain rdf:resource="#Item"/>
        <rdfs:range rdf:resource="xs:double"/>
    </owl:DatatypeProperty>
    <owl:Class rdf:ID="Delivery"/>

    <owl:Class rdf:ID="Status">
        <owl:oneOf rdf:parseType="Collection">
            <rdf:List>
                <rdf:first rdf:datatype="xs:string">rejected</rdf:first>
                <rdf:rest>

                    <rdf:first rdf:datatype="xs:string">accepted</rdf:first>
                </rdf:rest>
            </rdf:List>
        </owl:oneOf>
    </owl:Class>

</rdf:RDF>

Encoding of Rules

John Rules (F-Logic)

//If an item is perishable and it is delivered more than 10 days 
//after the scheduled delivery date then the item will be rejected

RULE R1 I:item[status -> "rejected"] <- I:item[isPerishable -> true] AND
                              I[actualDeliveryDate -> A] AND 
                              I[scheduledDeliveryDate -> S] AND 
                              R is (A - S) AND R > 10.

//If an item is perishable and it is delivered more than 7 days after the scheduled delivery date 
//but less than 14 days after the scheduled delivery date 
//then a discount of 18.7% will be applied to this delivery.

RULE R2 I:item[discount -> 18.7] <- D:delivery[hasItems->>Items] AND 
                                    I:item[isPerishable -> true] AND 
                                    I[actualDeliveryDate -> A] AND 
                                    I[scheduledDeliveryDate-> S] AND 
                                    member(I, Items) AND 
                                    R is (A - S) AND 
                                    R > 7.

Jane's Rules (Drools)

package com.sample
 
import com.sample.Item;

rule "R1"
 when
  i : Item(isPerishable==true, actualDeliveryDate : actualDeliveryDate, 
           scheduledDeliveryDate : scheduledDeliveryDate 
      )
  eval( actualDeliveryDate.getDay() - scheduledDeliveryDate.getDay() > 10)
 then
  i.isRejected(true);
  modify(i);
end


rule "R2"
 when
   d:Delivery(hasItems: hasItems)
   i : Item(actualDeliveryDate : actualDeliveryDate, 
            scheduledDeliveryDate : scheduledDeliveryDate 
       )
   eval( (actualDeliveryDate.getDay() - scheduledDeliveryDate.getDay() > 7) && hasItems.contains(i))
 then
   i.setDiscount(18.7);
   modify(i);
end

We assume that the function getDay() is defined in a DeliveryDate Java bean where all processing of time and dates is performed. This function is supposed to return an integer.

Interchanging of Rules

Importing Jane's Rules in the John's rule system

Translating from Drools into RIF

Since Jane's Rules are based on Java Beans all corresponding beans must be created from John's vocabulary. Therefore an interchange of vocabularies have to be performed.


We use the Presentation syntax provided by the RIF-BLD proposal. The reader may notice that Jane's Rules are Drools therefore production rules and RIF-BLD provides derivation rules therefore this translation has some limitations. Fortunately in the use case the rules are quite simpler: for example, the action part of Jane's rule R1 is a simple assign action as in OMG PRR (beta 1 specification, 4 November 2007). Therefore in the future this translation must be modified according with the RIF-PRD specification.

Below is the translation of Jane's Drools Rules rules into RIF. This translation is one from probably many other solutions:

rule "R1"
 when
  i : Item(isPerishable==true, actualDeliveryDate : actualDeliveryDate, 
           scheduledDeliveryDate : scheduledDeliveryDate 
      )
  eval( actualDeliveryDate.getDay() - scheduledDeliveryDate.getDay() > 10)
 then
  i.isRejected(true);
  modify(i);
end

// Translation to RIF
Rule ("http://jane.com/R1"
      ?i#Item[(isRejected->"true"^^xs:boolean) :-
                   And(?i#Item[(isPerishable->"true"^^xs:boolean) 
                               (actualDeliveryDate->?actualDeliveryDate ) 
                               (scheduledDeliveryDate ->?scheduledDeliveryDate)]
                               op:numeric-greater-than(
                                  op:numeric-subtract(
                                    user-defined:getDay(?actualDeliveryDate),
                                    user-defined:getDay(?scheduledDeliveryDate)
                                  ),
                                  "10"^^xs:int
                               )
                       )
     )

While the usual Drools column (i.e i : Item(isPerishable==true,...)) is straightforward to be translated into RIF-BLD frames the Drools eval() is more complex to be implemented since actually the RIF Data Types and Built-Ins do not provide information about potential user-defined functions. Here we suppose the user-defined function user-defined:getDay() performing the same functionality as in Jane's Java Bean DeliveryDate.

The Java constant true is mapped into "true"^^xs:boolean. Also the Java int 10 is mapped into the literal "10"^^xs:int.

Therefore RIF have to solve the extensibility issue of user-defined functions.