eXo Platform 3.5

## Chapter 7. JCR Extensions

## JCR Service Extensions

### Concept

eXo JCR supports observation (JSR-170 8.3), which enables applications to register interest in events that describe changes to a workspace, and then monitor and respond to those events. The standard observation feature allows dispatching events when persistent change to 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 as: Session.addNode(), Session.setProperty(), Workspace.move() etc.

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() etc.) execution time. As a consequence, it's necessary to minimize Action.execute(Context) body execution time.

To make the rule, you can use the dedicated Thread in 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.

### Implementation

Interceptor framework class diagram

### Configuration

Add a SessionActionCatalog service and an appropriate AddActionsPlugin (see the example below) configuration to your eXo Container configuration. As usual, the plugin can be configured as in-component-place, which is the case for a Standalone Container or externally, which is a usual case for Root/Portal Container configuration).

Each Action entry is exposed as org.exoplatform.services.jcr.impl.ext.action. ActionConfiguration of actions collection of org.exoplatform.services.jcr.impl.ext.action.AddActionsPlugin$ActionsConfig (see an example below). 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: the comma delimited (ORed) list of workspaces

* eventTypes: a comma delimited (ORed) list of event names (see below) 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. Since version 1.6.1 JCR supports the functionalities 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 the 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).

NOTE: the list of fields can be extended.

NOTE2: no spaces between list elements.

NOTE3: 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>

## Related Pages

Access Control extension

Registry Service

REST Groovy services