<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<section id="JCR.Extensions">
    <title>JCR Service Extensions</title>
    <section id="JCR.Extensions.Concept">
      <title>Concept</title>

      <para>eXo JCR supports <emphasis role="bold">observation</emphasis>
      (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 <emphasis role="bold">persistent change</emphasis> to the workspace
      is made.</para>

      <para>eXo JCR also offers a proprietary <emphasis role="bold">Extension
      Action</emphasis> which dispatches and fires an event upon each
      <emphasis role="bold">transient session level change</emphasis>,
      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.</para>

      <para>By default when an action fails, the related exception is simply logged.
       In case you would like to change the default exception handling, you can implement
       the interface AdvancedAction. In case the JCR detects that your action is of type AdvancedAction,
       it will call the method onError instead of simply logging it.
       A default implementation of the onError method is available in the abstract class AbstractAdvancedAction.
       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 type AdvancedActionException, it will throw it otherwise it will log simply it.
       An AdvancedActionException will be thrown in case the changes could not be reverted.</para>

	  <warning>
	    <para>
	      AdvancedAction interface must be implemented with a lot of caution to avoid being a performance killer.
	    </para>
	  </warning>

      <para>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.</para>

      <para>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.</para>

    </section>

    <section id="JCR.Extensions.Implementation">
      <title>Implementation</title>

      <mediaobject>
        <imageobject>
          <imagedata fileref="images/concepts/interceptor.jpg" />
        </imageobject>
      </mediaobject>

      <para>Interceptor framework class diagram</para>
    </section>

    <section id="JCR.Extensions.Configuration">
      <title>Configuration</title>

      <para>Add a <emphasis role="bold">SessionActionCatalog</emphasis>
      service and an appropriate <emphasis
      role="bold">AddActionsPlugin</emphasis> (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).</para>

      <para>Each Action entry is exposed as
      org.exoplatform.services.jcr.impl.ext.action. <emphasis
      role="bold">ActionConfiguration</emphasis> of actions collection of
      org.exoplatform.services.jcr.impl.ext.action.AddActionsPlugin$ActionsConfig
      (see an example below). The mandatory field named <emphasis
      role="bold">actionClassName</emphasis> 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 <emphasis
      role="bold">criteria</emphasis>. 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:</para>

      <para>* <emphasis role="bold">workspace</emphasis>: the comma delimited
      (ORed) list of workspaces</para>

      <para>* <emphasis role="bold">eventTypes</emphasis>: a comma delimited
      (ORed) <emphasis role="bold">list of event names</emphasis> (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.</para>

      <para>* <emphasis role="bold">path</emphasis> - a comma delimited (ORed)
      list of <emphasis role="bold">item absolute paths</emphasis> (or within
      its subtree if <emphasis role="bold">isDeep</emphasis> is <emphasis
      role="bold">true</emphasis>, which is the default value)</para>

      <para>* <emphasis role="bold">nodeTypes</emphasis> - a comma delimited
      (ORed) list of the <emphasis role="bold">current NodeType</emphasis>.
      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 <emphasis
      role="bold">current item</emphasis> is a <emphasis
      role="bold">property</emphasis> it means the <emphasis
      role="bold">parent node type</emphasis>. If the <emphasis
      role="bold">current item</emphasis> is a <emphasis
      role="bold">node,</emphasis> the semantic depends on the event type: **
      <emphasis role="bold">add node event</emphasis>: the node type of the
      newly added node. ** <emphasis role="bold">add mixin event</emphasis>:
      the newly added mixing node type of the current node. ** <emphasis
      role="bold">remove mixin event</emphasis> the removed mixin type of the
      current node. ** <emphasis role="bold">other events</emphasis>: the
      already assigned NodeType(s) of the current node (can be both primary
      and mixin).</para>

      <note><para> The list of fields can be extended.</para></note>

      <note><para> No spaces between list elements.</para></note>

      <note><para> <emphasis role="bold">isDeep=false</emphasis> means <emphasis role="bold">node,
      node properties and child nodes</emphasis>.</para></note>

      <para>The list of supported Event names: <emphasis role="bold">addNode,
      addProperty, changeProperty, removeProperty, removeNode, addMixin,
      removeMixin, lock, unlock, checkin, checkout, read, moveNode.</emphasis></para>

      <programlisting language="xml">&lt;component&gt;
   &lt;type&gt;org.exoplatform.services.jcr.impl.ext.action.SessionActionCatalog&lt;/type&gt;
   &lt;component-plugins&gt;
      &lt;component-plugin&gt;
         &lt;name&gt;addActions&lt;/name&gt;
         &lt;set-method&gt;addPlugin&lt;/set-method&gt;
         &lt;type&gt;org.exoplatform.services.jcr.impl.ext.action.AddActionsPlugin&lt;/type&gt;
         &lt;description&gt;add actions plugin&lt;/description&gt;
         &lt;init-params&gt;
            &lt;object-param&gt;
               &lt;name&gt;actions&lt;/name&gt;
               &lt;object type="org.exoplatform.services.jcr.impl.ext.action.AddActionsPlugin$ActionsConfig"&gt;
               &lt;field  name="actions"&gt;
                  &lt;collection type="java.util.ArrayList"&gt;
                     &lt;value&gt;
                        &lt;object type="org.exoplatform.services.jcr.impl.ext.action.ActionConfiguration"&gt;
                          &lt;field  name="eventTypes"&gt;&lt;string&gt;addNode,removeNode&lt;/string&gt;&lt;/field&gt;
                          &lt;field  name="path"&gt;&lt;string&gt;/test,/exo:test&lt;/string&gt;&lt;/field&gt;       
                          &lt;field  name="isDeep"&gt;&lt;boolean&gt;true&lt;/boolean&gt;&lt;/field&gt;       
                          &lt;field  name="nodeTypes"&gt;&lt;string&gt;nt:file,nt:folder,mix:lockable&lt;/string&gt;&lt;/field&gt;       
                          &lt;!-- field  name="workspace"&gt;&lt;string&gt;backup&lt;/string&gt;&lt;/field --&gt;
                          &lt;field  name="actionClassName"&gt;&lt;string&gt;org.exoplatform.services.jcr.ext.DummyAction&lt;/string&gt;&lt;/field&gt;       
                        &lt;/object&gt;
                     &lt;/value&gt;
                  &lt;/collection&gt;
               &lt;/field&gt;
            &lt;/object&gt;
          &lt;/object-param&gt;
        &lt;/init-params&gt;
      &lt;/component-plugin&gt;
    &lt;/component-plugins&gt;
&lt;/component&gt;</programlisting>
    </section>

  <section id="JCR.Extensions.RelatedPages">
    <title>Related Pages</title>

    <para><link linkend="JCR.AccessControlExtension">Access Control
    extension</link></para>

    <para><link linkend="JCR.RegistryService">Registry Service</link></para>

    <para><link linkend="JCR.RESTServicesOnGroovy">REST Groovy
    services</link></para>
  </section>
</section>
