Workflow

Workflow plugin

The workflow support has been substantially improved and simplified in Ametys 3.0.

  1. Plugin informations
  2. Description
    1. Changelog
  3. Components
    1. Workflow component
    2. WorkflowStore component
  4. Usage
    1. Development

Plugin informations

Description

This plugins provides workflow feature using OpenSymphony OSWorkflow.

Workflow instances can be created and used for anything (task, bug, ...) but the main use case is content management.

Because of this, default implementation stores workflow instances inside a JCR (JSR 170) content repository and especially using Jackrabbit.

This plugin also provides JDBC workflow storage (MySQL, PostgreSQL, Oracle).

Changelog

TODO insert here changelog from JIRA.

Components

Workflow plugin comes with two Avalon components.

Workflow component

Workflow component is responsible for creating workflow instances, executing actions on them, fetching current steps, etc, ...

Workflow definitions are declared into WEB-INF/param/workflows.xml with the following syntax:

<workflows>
  <workflow name="myworkflow" type="file" location="myworkflow.xml"/>
  ...
</workflows>

location attribute value is relative to WEB-INF/param directory, for more information on XML syntax see OSWorkflow documentation .

Avalon component can be used as OSWorkflow FunctionProvider, Condition, Register, Validator inside workflow definition and must be declared like this:

...
  <pre-functions>
    <function type="avalon">
      <arg name="role">org.ametys.example.MyFunction</arg>
    </function>
  </pre-functions>
...
  <condition>
    <function type="avalon">
      <arg name="role">org.ametys.example.MyCondition</arg>
    </function>
  </condition>
...

As any Avalon component you need to declare them inside a plugin.xml file and all Ametys Avalon features are supported (Serviceable, Contextualizable, Configurable, ...).
Just do not forget that this component will be instantiated only once by the plugin manager (instead of each time when you used class type).

In order to attach an user for each action (caller property), CurrentUserProvider component is used.

Storage is delegated to the WorkflowStore component (see below).

WorkflowStore component

WorkflowStore component is responsible for storing workflow instances.

Default implementation uses a JCR repository provided by Repository plugin in order to store workflow instances information.
Other implementation can be used by deactivating this component (in runtime.xml) and by declaring another:

  • org.ametys.plugins.workflow.store.MysqlWorkflowStore
  • org.ametys.plugins.workflow.store.PostgresWorkflowStore
  • org.ametys.plugins.workflow.store.OracleWorkflowStore

Usage

For creating a workflow instance and performing an action:

  Workflow workflow = (Workflow) manager.lookup(Workflow.ROLE);
  long workflowId = workflow.initialize("myworkflow", 1, null);
  workflow.doAction(workflowid, 2, null);

As this kind of code is typically found inside a Cocoon Action, standard actions are provided:

  ...
  <map:action name="initialize" src="org.ametys.plugins.workflow.cocoon.InitializeWorkflowAction"/>
  <map:action name="do-action" src="org.ametys.plugins.workflow.cocoon.WorkflowAction"/>
  ...
  <map:match pattern="create-workflow/*">
    <map:act type="do-action">
      <map:parameter name="workflowName" value="myworkflow"/>
      <map:parameter name="actionId" value="{1}"/>

      <map:generate type="action-result">
        <map:parameter name="workflowId" value="{workflowId}"/>
      </map:generate>
      <map:serialize type="xml"/>
    </map:act>
  </map:match>
  ...
  <map:match pattern="do-action/*/for/*">
    <map:act type="do-action">
      <map:parameter name="workflowId" value="{2}"/>
      <map:parameter name="actionId" value="{1}"/>

      <map:generate type="action-result"/>
      <map:serialize type="xml"/>
    </map:act>
  </map:match>

A higher layer is used in CMS for Ametys content to simplify even more actions performed against a workflow.

Development

For ease development of FunctionProvider or Condition, you can use AbstractWorkflowComponent which provides:

  • a logger.
  • the service manager for accessing other avalon components.
  • the avalon context for accessing environment.
  • getUser(Map transientVars) for retrieving the current user (aka the current action caller).
  • getRequest() for retrieving the current Cocoon request if available.
  • getJSONParameters() for retrieving the JSON parameters map if available
  • getRedirector(Map transientVars) for retrieving the current Cocoon redirector if available.

For checking rights, the org.ametys.plugins.workflow.component.CheckRightsCondition condition can be used:

...
  <condition>
    <function type="avalon">
      <arg name="role">org.ametys.plugins.workflow.component.CheckRightsCondition</arg>
      <arg name="right">Right_Edition</arg>
      <arg name="context">/contributor</arg>
    </function>
  </condition>
...

right argument is mandatory and choose the right to check.
context argument is optional (default to /contributor) and choose the context to use.