Creating rules and listeners

February 2, 2022

As Jahia uses a Java Content repository, it uses the standard JCRObservationManager. This manager observes events on the content repository and passes them to several event listeners implementing the abstract DefaultEventListener class. In the JCRStoreService, Jahia configures several default event listeners which are necessary to make Jahia work. These event listeners are then registered in the JCRObservationManager.

One of these event listeners is the JBoss Rules Listener, which allows integrators to use rules to process events. These rules can be deployed in modules and Jahia also includes default rules.

rules-and-listeners.png

Content events can be observed through the JCRObservationManager. However, system events (such as the login event) are not routed through the JCRObservationManager, but instead are sent and received through the system framework.

Rules

Each module in Jahia can define its own rules, extend the rule domain specific language, and add its own set of global objects.

Adding rules in a module

Just define a rules.drl file in the resources/META-INF folder of the module. Here is an example from the tasks module:

package org.jahia.modules.tasks.rules

//list any import classes here.
import org.jahia.services.content.rules.*
import org.slf4j.Logger

expander rules.dsl

//declare any global variables here
global User user
global Service service
global Logger logger
global Tasks tasks

rule "A welcome task for the new user"
   when
       A new node is created
                - the node has the type jnt:user
   then
       Log "Creating welcome task for new user: " + node.getName()
       Create task "Welcome to Jahia!" with description "We are glad to have you in our platform." for user node.getName()
end

rule "A notification about new group member"
   when
       A new node is created
                - the node has the type jnt:member
       The node has a parent
   then
       Log "Notifying members of the group '" + parent.getParent().getName() + "' about new member '" + node.getName()
       Create task "New member in the group" with description "A new member was added to the group." for members of group parent.getParent().getName()
end

rule "A task has been created"
    when
        A new node is created
        - the node has the type jnt:task
        The node has a property assignee
    then
        Set the property state of the node with the value "active"
        Assign permissions "rw-" on the node to the user property.getNode().getName()
end

This module adds some new rule consequences that are not part of the default DSL:

Create task "Welcome to Jahia!" with description "We are glad to have you in our platform." for user node.getName()

And it also defines a global object of type Tasks named tasks:

global Tasks tasks

Extending the domain specific language for rules

You only have to add a rules.dsl file in the WEB-INF/resources folder of your module. An example from the tasks module:

[consequence][]Create task "{title}" with description "{description}" for user {forUser}=tasks.createTask({forUser}, "{title}", "{description}", drools);
[consequence][]Create task "{title}" with description "{description}" for members of group {group}=tasks.createTaskForGroupMembers({group}, "{title}", "{description}", drools);

The extension made in a module will be available for all other modules. If your modules rely on a DSL from another module, you must add this module as a dependency of yours.

Here is an example of using tasks in your own module (say, Jahia RSS Feeds module). In the pom.xml we have:

<Jahia-Depends>tasks</Jahia-Depends>

And the META-INF/rules.drl file content is:

###############################################################################
package org.jahia.modules.rss.rules

#list any import classes here.
import org.slf4j.Logger
import org.jahia.services.content.rules.*
import org.jahia.modules.tasks.rules.*

expander rules.dsl

#declare any global variables here
global User user
global Service service
global Logger logger
global Tasks tasks
###############################################################################

rule "Notification about new RSS feed"
   when
       A new node is created
                - the node has the type jnt:rss
        The node has a property url
   then
       Log "Notifying root about new RSS feed " + property.getStringValue()
       Create task "New RSS feed alert" with description "Read the newly added RSS feed, retrieved from '" + property.getStringValue() + "'" for user "root"
end

Note that the rule file must import the org.jahia.modules.tasks.rules.* package and have a definition for tasks global object, for example:

...

import org.jahia.modules.tasks.rules.*

...
global Tasks tasks
...

Adding your own global objects to your rule context for execution

You can find an example of how to register global objects using OSGi here: https://github.com/Jahia/OSGi-modules-samples/tree/master/rules-samples/src/main/java/org/foo/modules/rules

System events

To listen to events sent through the system framework, you need to implement an OSGi event handler. See the example available here: https://github.com/Jahia/OSGi-modules-samples/blob/master/system-events-samples/src/main/java/org/foo/modules/events/OsgiSystemEventHandler.java.

Login and logout events

Login and logout event can be activated, if your application needs to listen to these events. You'll have to add fireLoginEvent and/or fireLogoutEvent properties in your jahia.properties file. An event will then be sent every time a user logs in or out.

JCR Events

You can extend the org.jahia.services.content.DefaultEventListener class to create a listener on JCR events. The event listener needs to be registered from a module using the following API call: jahiaTemplateManagerService.getTemplatePackageRegistry().handleJCREventListener(listener, register);

The jahiaTemplateManagerService is accessible through the OSGi service registry with the following interface: org.jahia.api.templates.JahiaTemplateManagerService

See JCR documentation for details on the different event types.