JBoss Community Archive (Read Only)

ModeShape 5

Custom sequencers

Earlier in the introduction, we briefly described sequencers and how they work. In this section we go into more detail about the framework and describe all the steps for developing your own custom sequencers.

The Sequencer framework

A sequencer is actually just a plain old Java object (POJO). Creating a sequencer is pretty straightforward: create a Java class that extends a single abstract class, called Sequencer:

package org.modeshape.jcr.api.sequencer;

import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;

public abstract class Sequencer {

    ...

    /**
     * Execute the sequencing operation on the specified property, which has recently 
     * been created or changed.
     * 
     * Each sequencer is expected to process the value of the property, extract information
     * from the value, and write a structured representation (in the form of a node or a 
     * subgraph of nodes) using the supplied output node. Note that the output node
     * will either be:
     *   1. the selected node, in which case the sequencer was configured to generate the 
     *      output information directly under the selected input node; or
     *   2. a newly created node in a different location than node being sequenced (in 
     *      this case, the primary type of the new node will be 'nt:unstructured', but
     *      the sequencer can easily change that using Node.setPrimaryType(String) ).
     *
     * The implementation is expected to always clean up all resources that it acquired, 
     * even in the case of exceptions.
     * 
     * @param inputProperty the property that was changed and that should be used as 
     *        the input; never null
     * @param outputNode the node that represents the output for the derived information; 
     *        never null, and will either be a new node if the output is being placed 
     *        outside of the selected node, or will not be new when the output is to be
     *        placed on the selected input node
     * @param context the context in which this sequencer is executing, and which may 
     *        contain additional parameters useful when generating the output structure; never null
     * @return true if the sequencer's output should be saved, or false otherwise
     * @throws Exception if there was a problem with the sequencer that could not be handled.
     *         All exceptions will be logged automatically as errors by ModeShape.
     */
    public abstract boolean execute( Property inputProperty,
                                     Node outputNode,
                                     Context context ) throws Exception;

    /**
     * Initialize the sequencer. This is called automatically by ModeShape, and 
     * should not be called by the sequencer.
     * <p>
     * By default this method does nothing, so it should be overridden by  
     * implementations to do a one-time initialization of any internal components.  
     * For example, sequencers can use the supplied 'registry' and  
     * 'nodeTypeManager' objects to register custom namesapces and node types  
     * required by the generated content.
     * </p>
     * 
     * @param registry the namespace registry that can be used to register  
     * custom namespaces; never null
     * @param nodeTypeManager the node type manager that can be used to register  
     * custom node types; never null
     */
    public void initialize( NamespaceRegistry registry,
                            NodeTypeManager nodeTypeManager ) {
    }

}

The abstract class also contains fields and getters (not shown above) for the name, description, and path expressions that are automatically set by ModeShape during repository initialization. The initialize(...) method is run upon repository initialization and can be overridden by an implementation to register (if required) any custom namespaces and node types required by the sequencer's generated output.

The outputNode might belong to a different javax.jcr.Session object than the inputProperty, if the input and output paths of the sequencer configuration specify different workspaces. Therefore, be careful that all changes are made using the output node and its session.

The inputs to the sequencer depend on how it's configured, but often the inputProperty represents the jcr:data BINARY property on the "jcr:content" child of an nt:file node. The outputNode, however, will be one of two things:

  1. If there is no output path in the path expression, then the sequenced output is to be placed directly under the selected node, so therefore the "outputNode" will be the existing node being sequenced. In this case, the sequencer should place all content under the output node. In this case, the sequencers are not allowed to change the primary type.

  2. Otherwise, the sequenced output is to be placed in a different location than the selected node. In this case, ModeShape uses the name of the selected node and creates a new node under the output path. This new node will have a primary type of "nt:unstructured", but sequencers are allowed to change the primary type.

The final parameter to the execute(...) method is the SequencerContext object, which is an interface containing some extra information often useful when sequencing files:

package org.modeshape.jcr.api.sequencer;

import java.util.Calendar;

/**
 * The sequencer context represents the complete context of a sequencer invocation.
 * Currently, this information includes the current time of execution.
 */
public interface SequencerContext {

    /**
     * Get the timestamp of the sequencing. This is always the timestamp of the
     * change event that is being processed.
     * 
     * @return timestamp the "current" timestamp; never null
     */
    Calendar getTimestamp();

}

Creating a new sequencer

Create the Maven module

Create a Sequencer subclass

Create unit tests

Package your library

Deploy and configure

JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-11 12:13:01 UTC, last content change 2016-04-08 06:45:42 UTC.