Rule Engine Fun in Jahia
Jahia uses a business rule engine to ‘act’ upon changes within the content repository and is integrated at the JCR event listening level. From within the context of Jahia it’s usually known as the ‘Jahia Rule Engine’. In case you want to search the internet for more information, Jahia uses Drools as the underlaying technology for its rule engine. Although it can be useful to find the knowledge on their website, it’s not required to read the Drools website to use the Jahia’s rule engine.
How the rule engine is integrated
The rule engine is integrated in Jahia in such a way that it acts at the JCR level. For you (the developer) that means you need to think in such a way that you take action when the JCR gets modified. This modification usually happens when a node is created, deleted, moved or when properties of a node are modified, created or deleted. Each rule within Jahia is defined with consequences that must be performed when a condition is met.
The elements of a rule
A rule has the following structure:
rule "name" attributes when LHS then RHS end
It's really that simple. Most punctuation is not needed, even the double quotes for "name" are optional, even newline characters are not required. Attributes are simple (always optional) hints as to how the rule should behave. LHS is the conditional parts of the rule, which follows a certain syntax which is explained below. RHS is basically a command sequence block that allows dialect specific semantic code to be executed - this is also called a consequence.
It is important to note that whitespace is not important, except in the case of domain specific languages, where lines are processed one by one and spaces may be significant to the domain language. (from http://docs.jboss.org/drools/release/5.3.0.Final/drools-expert-docs/html/ch05.html#d0e2818)
Rule Conditions
Rule conditions are evaluated when a change in the JCR occurs. All rules in Jahia will be processed by the rule engine and when a condition matches, the consequence (RHS) will be executed. Fortunately for us, Drools is fairly clever in how it executes rules and the total time it takes to evaluate the rules is usually very small.
Obviously it’s possible to create rules that depend on multiple conditions as this is often required within a CMS. For example, if the node is a post and it’s from a admin user, don’t test for SPAM.
To get a good overview on the sort of conditions that may be defined you can have a look at the rules.dsl file located in: tomcats/webapps/ROOT/WEB-INF/etc/repository/rules.dsl . Alternatively you can also look at them online in case you didn’t install Jahia yet.
This is a simple text file with the following content:
[condition][]A file content has been modified=property : ChangedPropertyFact ( name == "jcr:data", contentnode : node ) and AddedNodeFact ( name == "jcr:content" ) from contentnode and node : AddedNodeFact () from contentnode.parent [condition][]A new node "{name}" is created=node : AddedNodeFact ( name == "{name}") [condition][]A new node is created=node : AddedNodeFact ( ) [condition][]A node is deleted=node : DeletedNodeFact ( ) [condition][]A node is moved=node : MovedNodeFact ( ) [condition][]A node is published=node : PublishedNodeFact ( ) [condition][]A node is copied=node : CopiedNodeFact ( ) [condition][]A node is a top copy=node : CopiedNodeFact ( top == true ) … … [condition][]- it has the extension type {type}=types contains "{type}" [condition][]- it has the type {type}=types contains “{type}" … …
Conditions are written in a human readeable language to make it easy for the integrator to select build rules, so you don’t have to have a deep knowledge to actually test for a condition. The hyphen (-) in a condition means that it’s inserted into the last preceding output text, in front of a closing parenthesis and after an additional comma (‘,'). This feature enables you to accumulate constraints, one by one, into a preceding Pattern Conditional Element. We will come to that later.
Rule Consequences
When a rule matches the conditions, it will be executed. Each rule can have multiple consequences and each consequence can do whatever you have programmed it to do. In the rules.dsl file, as mentioned above, all consequences are written down in human-readable language to make it easy for integrators to build their own rules.
Examples:
For me the best way to learn something is by creating a couple of examples and do some real world testing.
Example 1
Task: When a node is created we set some property to some value.
The rule rule tests for the condition ‘A new node is created’ with the accumulate constraint ‘the node has the type jnt:user’. Directly you can see why the rule engine choose to use english language (or any language if you choose..) rather then if/then/else constructs found in programming languages. The rule itself is very natural and thus makes it easy to understand.
The rule’s condition does what it says, when a node is created and has the type jnt:user, do something…
The consequence for this rule is also very simple:
- We log the start of the rule’s execution.
- We set the property j:organisation to the value Hello world from Blog Examples!
- We log the end of the rule’s execution.
# Example 1, set a property when a node is created rule "Example 1, set a property when a node is created" when A new node is created - the node has the type jnt:user then Log "Start: Adding a property for this user " + node.getName() Set the property j:organization of the node with the value "Hello world from Blog Examples!” Log "End: Adding a property for this user " + node.getName() end
Example 2
Task: Send an email when a new user was created within Jahia
It speaks for itself that for the consequence we are not limited to just modifying a JCR node, we can do any other task we choose. Here is an example to send a mail to the root user based on a specific template.
Note 1:, Make sure you configure Jahia’s mail service, see here how to properly set it up
Note 2: Make sure you configure the ‘root’ user with a valid mail address
# Example 2, Mail ourselve when a user was created rule "Example 2, Mail ourselve when a user was created" when A new node is created - the node has the type jnt:user then Log "Start: Sending mail to admin " + node.getName() Notify "root" user with mail template "/modules/blog-drools/templates/mail/newUser.vm" from "jahiasystem@rvt.dds.nl" Log "End: End sending mail to admin " + node.getName() end
Conclusion
The rule system in Jahia allows you to take action when the JCR gets modified. This is very nice, because you can from your own module act upon changes created by other modules in such a way that you don’t need a tight coupling that would lead to interdependencies.
You can find the complete source code for the module described in this blog post.
This blogpost has been written by R. van Twisk