eXo JCR supports observation, which enables applications to register interest in events that describe changes on a workspace, and then monitor and respond to those events. The standard observation feature allows dispatching events when persistent change on the workspace is made.
eXo JCR also offers a proprietary
Extension
Action
which dispatches and fires an event upon each
transient session level change,
performed by a client. In other words, the event is triggered when a
client's program invokes some updating methods in a session or a
workspace, such asSession.addNode()
,Session.setProperty()
,
Workspace.move()
and more.
By default, when an action fails, the related exception is simply logged.
In case you want to change the default exception handling, you can implement
the
AdvancedAction
interface. In case the JCR detects that your action is of the
AdvancedAction
type,
it will call the
onError
method instead of simply logging it.
A default implementation of the
onError
method is available in the
AbstractAdvancedAction
abstract class.
It reverts all pending changes of the current JCR session for any kind of event corresponding to a write operation.
Then, in case the provided exception is an instance of the
AdvancedActionException
type, it will throw it; otherwise it
will log simply it.
An
AdvancedActionException
will be thrown in case the changes could not be reverted.
The AdvancedAction
interface must be implemented with a lot of caution to avoid being a performance killer.
One important recommendation should be applied for an extension
action implementation. Each action will add its own execution time to
standard JCR methods (Session.addNode()
, Session.setProperty()
,
Workspace.move()
, and more.) execution time. As a result, you need
to minimize the Action.execute(Context)
body execution time.
To make the rule, you can use the dedicated Thread in
the Action.execute(Context)
body for a custom logic. But if your application
logic requires the action to add items to a created/updated item and you
save these changes immediately after the JCR API method call is
returned, the suggestion with Thread is not applicable for you in this
case.
The JCR Service’s implementation may be illustrated in the following interceptor framework class diagram.
Add a SessionActionCatalog service and an appropriate AddActionsPlugin configuration to your eXo Container configuration. As usual, the plugin can be configured as in-component-place.
Each Action entry is exposed as
org.exoplatform.services.jcr.impl.ext.action.ActionConfiguration
of the actions collection of
org.exoplatform.services.jcr.impl.ext.action.AddActionsPlugin$ActionsConfig
.
The mandatory field named actionClassName is the fully qualified name of
org.exoplatform.services.command.action.Action
implementation - the
command will be launched in case the current event matches the criteria. All other fields are criteria. The
criteria are *AND*ed together. In other words, for a particular item to
be listened to, it must meet ALL the criteria:
workspace
: A comma delimited (ORed) list of workspaces.
eventTypes
: A comma delimited (ORed) list of event names
to be listened to. This is the only mandatory field, others are optional
and if they are missing they are interpreted as ANY.
path
: A comma delimited (ORed)
list of item absolute paths (or within
its subtree if isDeep is true, which is the default value).
nodeTypes
: A comma delimited (ORed) list of the current NodeType.
JCR supports the functionality of nodeType
and
parentNodeType
. This parameter has different semantics, depending on the
type of the current item and the operation performed.
If the current item is a property, it means parent node type.
If the current item is a node, the semantic depends on the event type:
add node event: the node type of the newly added node.
add mixin event: the newly added mixing node type of the current node.
remove mixin event: the removed mixin type of the current node.
other events: the already assigned NodeType(s) of the current node (can be both primary and mixin).
The list of fields can be extended.
No spaces between list elements.
isDeep=false means node, node properties and child nodes.
The list of supported Event names: addNode, addProperty, changeProperty, removeProperty, removeNode, addMixin, removeMixin, lock, unlock, checkin, checkout, read.
<component>
<type>org.exoplatform.services.jcr.impl.ext.action.SessionActionCatalog</type>
<component-plugins>
<component-plugin>
<name>addActions</name>
<set-method>addPlugin</set-method>
<type>org.exoplatform.services.jcr.impl.ext.action.AddActionsPlugin</type>
<description>add actions plugin</description>
<init-params>
<object-param>
<name>actions</name>
<object type="org.exoplatform.services.jcr.impl.ext.action.AddActionsPlugin$ActionsConfig">
<field name="actions">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.jcr.impl.ext.action.ActionConfiguration">
<field name="eventTypes"><string>addNode,removeNode</string></field>
<field name="path"><string>/test,/exo:test</string></field>
<field name="isDeep"><boolean>true</boolean></field>
<field name="nodeTypes"><string>nt:file,nt:folder,mix:lockable</string></field>
<!-- field name="workspace"><string>backup</string></field -->
<field name="actionClassName"><string>org.exoplatform.services.jcr.ext.DummyAction</string></field>
</object>
</value>
</collection>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</component-plugins>
</component>