Obsolete Pages{{Obsolete}}
The official documentation is at: http://docs.alfresco.com
Back to Workflow.
This document describes requirements for advanced workflow within Alfresco and the approach taken during the v1.4 development cycle.
Focus is given to providing support for user-oriented processes that are managed within the context of a Repository e.g. review and approve, translation, publish. It is envisioned that BPEL will still provide support for enterprise-wide process management where content management is a piece of the process i.e. CRM/Accounting/Contract process. The former we can call Content Management Process, the latter Content Integration Process (note: any other terms that better describe - I'm not married to these).
Workflow User interface design is not included in this document. Focus is given to use-cases and services required.
Since its inception, Alfresco has supported 'simple' workflow, which is aimed at providing an end-user with the capability to define their own content-oriented workflows. It's simple in that each workflow definition is restricted to a single state. Multiple states are represented by loosely tying multiple workflow definitions. Loose coupling is achieved by attaching a workflow definition to a folder and a workflow instance to a content item. A Content item is moved or copied to a new folder at which point a new workflow instance is attached based on the workflow definition of the folder. A workflow definition is unaware of other 'related' workflow definitions.
Limitations:
To resolve these limitations, Alfresco will integrate a best-of-breed BPM engine into its core. This will extend the Alfresco platform to include support for bespoke content-oriented processes.
The difference between 'simple' and advanced workflow can be described as...
Any kind of workflow should be supported by advanced workflow, but to bring some focus, the following examples must be catered for:
1) Simple multi-step Review (requested by several customers)
For example, send this document to Fred for review and once approved notify me.
TODO: document this process
2) WCM Press Release Publishing Workflow
As described by Kevin Cochrane.
TODO: reference documented process
3) Alfresco Test 'Approval' Workflow
Example/Test demonstrating the commonly requested features of Workflow.
4) Alfresco 'simple' workflow
Must be able to express existing simple workflows in the language of the integrated BPM engine.
Basically, the basis of any BPM engine is a state machine. However, to support the above workflows, the following is specifically required:
A user of a Content Management application requires the following interactions with an advanced workflow.
Via the CM Client (i.e. Web Browser):
Via a notification medium (e.g. E-mail, IM):
Each advanced (in-flight) workflow instance may require one or more of the following parameters:
It should be possible to ask a workflow definition for a description of its parameters, in particular, the task assignments required.
Parameter values are provided at process initiation time. Some parameters may be discarded after initiation once they have been used to determine some dynamic aspect of the workflow. However, the majority of them will be carried through the lifetime of the process instance.
In some scenarios, it is useful to encapsulate process parameter values so they can be re-used. For example, a Space Template may be associated with a particular Workflow definiton with 'canned' parameter values (known as a Workflow Template?). Users within that Space may initiate the Workflow without having to detour from the defaults i.e. the best practice is encapsulated.
Each process instance will carry variables which can be read or set during the lifetime of the instance, in particular, when evaluating Decisions and Managing Content. Most BPM engines offer this facility, but not all support scoped process variables for parallel execution paths.
It is important to distinguish between process context and content state. The Repository already does an excellent job of maintaining content state and will continue to do so in an in-flight process. The process instance is solely responsible for maintaining process context i.e. the variables it's carrying and the position(s) within the process. During the execution of a process instance, content state may be modified or read as actions are performed against content, or process decisions are driven by content.
At some point in the future, the notion of Content Lifecycle may be formalised in the Content Repository. Even without formalised Content Lifecycle, a poor man's version can be implemented using aspects, property setting and categorisation.
A process flow (or execution) may be driven by the context (e.g. content, folder, space, user) attached to the process. Most workflow engines provide a fork or decision node where the condition is written using a native expression language. However, as Alfresco utilises JavaScript for managing logic, it would be ideal to allow JavaScript to determine decisions points within the process and for that JavaScript to have access to the following:
as simple objects for easy navigation and examination.
During an in-flight process, it may be necessary to perform operations against content in the repository. There shouldn't be a restriction on what operations may be performed.
Alfresco already provides the notion of an Action which encapsulates a re-usable repository operation. Configuration of Actions into a process should be made very easy, whereas, configuration of arbitrary logic should be possible. Actions already support parameters, so a mechanism to map process state to action parameters is required.
Operating against the Repository requires prior authentication. Operations are performed on state entry & exit or on transition, which happen when starting a workflow and signalling continuation of a workflow. The authenticated identity for an operation may come from:
The transaction of the operation is either:
A process must be sensitive to errors which may occur during an operation. It should be possible to handle an error by triggering an explicit error transition which moves the process to a state for recovery or even end. When an error occurs, the content operation must exhibit ACID behaviour in that it will be rolled-back, but the process will still move to the next state, allowing for the issue to be (system or user) resolved.
Not all Workflows are applicable to all situations.
Within an Alfresco Space it may be necessary to specify which Workflows are applicable. This could simply be a list, or more specifically, a list of Content Type to Workflow mappings.
In particular, it is often required to implicitly start a workflow when:
In WCM, during Web Space setup, it is necessary to support the linking of Form, Presentation Template and Workflow. In this case, it's not just the selection of the Workflow, but also the configuration of it i.e. the setting of its parameter values. The saving of Workflow parameter values is required so each subsequent use of a Form kicks off the same associated & configured Workflow.
Advanced workflows, in particular, the ones we're focusing on above, require user intervention in the form of tasks.
Viewing and acting upon a task will require a user interface that is sensitive to the task in hand. In particular the viewing / setting of task specific state, parameters and for selecting a task outcome. It should be possible for a task to describe itself.
Outside-in approach:
The workflow definition specifies the task assignment slots to be filled. On start of the workflow, users or groups are assigned to the slots. The mapping takes place outside of the workflow and may be driven by any means whether manual or automatic e.g. map users & groups via their assigned role in the initiating Alfresco space.
Inside-out approach:
Within a workflow definition, logic is provided to 'dynamically' assign users and groups to task assignment slots. The logic may rely on context provided to the process (e.g. query roles on space provided to process) or any other external mechanism.
For each distinct person in group(s), allocate task to person (i.e. one task instance per person).
NOTE: Make use of ForEachFork to iterate over group members
Group(s) as a whole are assigned to task. Someone in group takes ownership of task.
A User may be notified when:
Tasks are created within a context, where the context is typically:
Need to perform the following queries:
Q: Do we need to support the notion of tasks outside workflow?
There's no reason why tasks cannot be managed outside of workflow. For example, a user may wish to manage their day-to-day activities. This could be supported by wrapping each task in a single workflow, but I think we want to provide task management as an independent service of the Alfresco platform. We could support integration with an external task system (e.g. Outlook) behind this service.
The following additional user actions may be supported for task management:
Agree?
Kevin Cochrane: More I think about your task proposal, the more I warm up to it. Another reason: outside of the context of WCM (which can tend to be very process-centric because you are distributing information so broadly for public consumption), the notion of simple tasks a user can create in the context of their workspace as a TO DO list for a given project is an absolute must. For WCM, it's a nice to have convenience that becomes a particularly acute need in the context of a simple intranet publishing op, but for collab activities I imagine it's a hard requirement.
TODO: Expand on formalising the notion of Content Lifecycle...
TODO: Expand on this...
Processes require care and attention. To simplify management of processes, the following features are required:
TODO: Expand this...
BPEL4WS Business Process Execution Language (for Web Services)
WSIF Web Services Invocation Framework
Starting from Alfresco Community 3.4.e, Alfresco provides both the Activiti BPMN 2.0 BPM engine and the original JBoss jBPM engine . You can discover more on the Activiti implementation in Workflow_with_Activiti.
The rest of this page discusses Workflow using the original jBPM engine:-
Provides:
Originally, the thought was to manage Tasks within Alfresco where we provide a loose coupling between workflow transitions (managed by the BPM engine) and the creation/assignments of tasks in Alfresco.
However, after much deliberation, a change of mind has been made. Workflow Tasks will now be managed by the BPM engine. The reasoning is that all process information is encapsulated in one place allowing complete reporting, tracking and load balancing. Also, Alfresco can concentrate on content management focusing on the touch points between content management and process management.
Benefits of this route:
An Alfresco Workflow definition is made up of four parts:
none|500px|Workflow Definition
Splitting the workflow definition this way allows for an external & pluggable BPM engine to provide the Process Definition (the first of which is jPDL of jBPM). Each BPM engine will provide its own set of features and process definition language.
Fronting the Process Definition is a Task Model which is understood by clients of the Workflow i.e. those who wish to initiate a workflow, move a workflow forward, or interact with workflow tasks. It provides the public contract and is independent of BPM engine. As a public contract, an attempt to maintain compatibility between Alfresco versions will be made.
The Workflow contract is described as an Alfresco Dictionary Model. Each task within a workflow is represented as a Dictionary Type where task properties and associations are modelled as Type properties and associations. An Alfresco client may use the Type definition to drive the collection of data required for the task. In fact, the Alfresco Web Client infrastructure (e.g. dialog and wizard framework) already provides Type-driven UI allowing for easy construction and configuration of Task dialogs.
Workflow parameters required to start a workflow are also modelled as a Task. Each workflow may have the notion of a special 'Start' Task which is created upon launch of the workflow. The properties and associations of the 'Start' Task represent the workflow parameters to collect. Again, the same UI configuration may be used for initiating a workflow. Another benefit of having a 'Start' task is it appears in the initiators completed task list providing a point for determining the status of the workflow or cancelling it.
Examples workflow models follow:
With these models, Web Client configuration can include:
Given that each Workflow maps to a Dictionary Model, it is possible to create Workflow Task nodes within the Alfresco Repository. For example, with the ReviewApproveWorkflow.xml model registered, a node of type 'wf:submitReviewTask' can be persisted and for each of its properties a value may be stored. Essentially, this provides a Workflow Start Task Template node. Enough information is stored to know which Workflow to start and the values to use for its parameters. This is particularly useful when used in conjunction with Space Templates and also useful for WCM Web Space setups.
The approach used for Dictionary Model localisation will also be used for Workflow & Task Models. Task localisation uses the same message keys as Type.
However, the following workflow specific keys are also supported:
where:
For example:
wf_review.workflow.title=Review & Approve
wf_review.workflow.description=Send documents for approval
wf_review.node.start.title=Start
wf_review.node.start.transition.review.title=Review
wf_review.node.review.title=Review
# for tasks, either rely on Type definition for task
wf_workflowmodel.type.wf_submitReviewTask.title=Review
# or, provide explicit title and description
wf_review.task.wf_submitReviewTask.title=Review
jBPM provides a (Eclipse hosted) GUI for defining workflow processes. One feature of the designer is the ability to deploy a definition to a server. Alfresco will provide the necessary support to allow the jBPM Process Designer to deploy directly to Alfresco.
The following type will be added to the Content Model to support the storage of process definitions within the Alfresco Repository. Process definitions are then under content management.
Process Definition - Content Type for storing a Process Definition.
<type name='bpm:processdefinition'>
<title>Process Definition</title>
<parent>cm:content</parent>
<properties>
<property name='bpm:engineId'>
<type>d:text</text>
</property>
</properties>
</type>
Against this type, an Alfresco 'Deploy/Publish' action could be registered allowing for the deployment of Process Definitions within the Alfresco Web Client.
Process Definitions may live in the Data Dictionary Folder, but are only of use to 'Process Designers' who design and edit them, so the visibility will be restricted.
Content-oriented workflows operate against Content!
The content routed through an Alfresco workflow is stored in the Alfresco Repository. To represent the package of content (where zero, one or more pieces of content may be in play at any point) during the workflow, a new concept of a Workflow Package is introduced.
A Workflow Package is simply a container of content items which itself is stored in the Repository. Initially, Alfresco will support a single Workflow Package per workflow instance meaning that all active tasks within a workflow instance have access to the same package. For example, in a review process many people (i.e. many tasks) may be involved in the approval of the same content. Other tasks may involve the collection of new content, in which case, it's added to the package.
The container may be one of folder, versioned folder or layered folder to which a workflow package aspect is applied. The aspect keeps track of the association back to the workflow plus any other important workflow information that may want to be searched against in the repository. A running list of comments about the package may also be persisted in the Repository as an attached Discussion Thread.
Within each Task, the set of Workflow Package actions may be defined:
The definition is simply an Alfresco Web Client named 'Action Group'. Each workflow task instance supports an Action Group property which may be set at process definition time, or at process instance run-time.
none|500px|Workflow Service API Data Model
/** Workflow Definition unique id */
public String id;
/** Workflow Definition name */
public String name;
/** Workflow Definition version */
public String version;
/** Workflow Definition Title (Localised) */
public String title;
/** Workflow Definition Description (Localised) */
public String description;
/** Task Definition for Workflow Start Task (Optional) */
public WorkflowTaskDefinition startTaskDefinition;
/** Workflow Instance unique id */
public String id;
/** Workflow Instance description */
public String description;
/** Is this Workflow instance still 'in-flight' or has it completed? */
public boolean active;
/** Initiator (cm:person) - null if System initiated */
public NodeRef initiator;
/** Workflow Start Date */
public Date startDate;
/** Workflow End Date */
public Date endDate;
/** Workflow Package */
public NodeRef workflowPackage;
/** Workflow Context */
public NodeRef context;
/** Workflow Definition */
public WorkflowDefinition definition;
/** Workflow Node Name */
public String name;
/** Workflow Node Title (Localised) */
public String title;
/** Workflow Node Description (Localised) */
public String description;
/** Type of the Workflow Node (typically this is BPM engine specific - informational only */
public String type;
/** Does this Workflow Node represent human interaction? */
public boolean isTaskNode;
/** The transitions leaving this node (or null, if none) */
public WorkflowTransition[] transitions;
/** Transition Id */
public String id;
/** Transition Title (Localised) */
public String title;
/** Transition Description (Localised) */
public String description;
/** Is this the default transition */
public boolean isDefault;
/** Unique id of Workflow Path */
public String id;
/** Workflow Instance this path is part of */
public WorkflowInstance instance;
/** The Workflow Node the path is at */
public WorkflowNode node;
/** Is the path still active? */
public boolean active;
/** Unique id of Task */
public String id;
/** Task Name */
public String name;
/** Task Title (Localised) */
public String title;
/** Task Description (Localised) */
public String description;
/** Task State */
public WorkflowTaskState state;
/** Workflow path this Task is associated with */
public WorkflowPath path;
/** Task Definition */
public WorkflowTaskDefinition definition;
/** Task Properties as described by Task Definition */
public Map<QName, Serializable> properties;
/** Unique id of Workflow Task Definition */
public String id;
/** Workflow Node this task created from */
public WorkflowNode node;
/** Task Metadata */
public TypeDefinition metadata;
/** Timer Id */
public String id;
/** Transition Name */
public String name;
/** Associated Workflow Path */
public WorkflowPath path;
/** Associated Workflow Task (if any) */
public WorkflowTask task;
/** Due Date */
public Date dueDate;
Identifies a workflow definition. The format is as follows:
bpmengine$definitionId
bpmengine = identifier of BPM engine (specified in registration of engine)
definitionId = BPM engine specific identifier for a given workflow definition
e.g. jbpm$wf:review
Identifies an 'in-flight' workflow (i.e. an instance of a workflow definition). This identifier is tied to the BPM engine supporting the workflow. The format is as follows:
bpmengine$instanceId
where:
bpmengine = identifier of BPM engine (specified in registration of engine)
instance = BPM engine specific identifer for a given workflow instance
e.g. jbpm$1234
Identifies a position within an 'in-flight' workflow (i.e. a workflow path within a workflow instance). This identifier is tied to the BPM engine supporting the workflow.
bpmengine$position
where:
bpmengine = identifier of BPM engine (specified in registration of engine)
position = BPM engine specific identifer for a given workflow instance
e.g. jbpm$1234-@ represents the root path of jBPM workflow instance 1234
Client facing API for interacting with Alfresco Workflows and Tasks
//
// Workflow Definition Management
//
/**
* Deploy a Workflow Definition to the Alfresco Repository
*
* @param engineId the bpm engine id
* @param workflowDefinition the workflow definition
* @param mimetype the mimetype of the workflow definition
* @return workflow deployment descriptor
*/
@Auditable(parameters = {'engineId', 'workflowDefinition', 'mimetype'})
public WorkflowDeployment deployDefinition(String engineId, InputStream workflowDefinition, String mimetype);
/**
* Deploy a Workflow Definition to the Alfresco Repository
*
* Note: The specified content object must be of type bpm:workflowdefinition.
* This type describes for which BPM engine the definition is appropriate.
*
* @param workflowDefinition the content object containing the definition
* @return workflow deployment descriptor
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {'workflowDefinition'})
public WorkflowDeployment deployDefinition(NodeRef workflowDefinition);
/**
* Is the specified Workflow Definition already deployed?
*
* Note: the notion of 'already deployed' may differ between bpm engines. For example,
* different versions of the same process may be considered equal.
*
* @param engineId the bpm engine id
* @param workflowDefinition the definition to check
* @param mimetype the mimetype of the definition
* @return true => already deployed
*/
@Auditable(parameters = {'engineId', 'workflowDefinition', 'mimetype'})
public boolean isDefinitionDeployed(String engineId, InputStream workflowDefinition, String mimetype);
/**
* Undeploy an exisiting Workflow Definition
*
* @param workflowDefinitionId the id of the definition to undeploy
*/
@Auditable(parameters = {'workflowDefinitionId'})
public void undeployDefinition(String workflowDefinitionId);
/**
* Gets latest deployed Workflow Definitions
*
* @return the latest deployed workflow definitions
*/
@Auditable
public List<WorkflowDefinition> getDefinitions();
/**
* Gets all deployed Workflow Definitions (with all previous versions)
*
* @return the deployed (and previous) workflow definitions
*/
@Auditable
public List<WorkflowDefinition> getAllDefinitions();
/**
* Gets a Workflow Definition by unique Id
*
* @param workflowDefinitionId the workflow definition id
* @return the deployed workflow definition (or null if not found)
*/
@Auditable(parameters = {'workflowDefinitionId'})
public WorkflowDefinition getDefinitionById(String workflowDefinitionId);
/**
* Gets the latest Workflow Definition by unique name
*
* @param workflowName workflow name e.g. jbpm$wf:review
* @return the deployed workflow definition (or null if not found)
*/
@Auditable(parameters = {'workflowName'})
public WorkflowDefinition getDefinitionByName(String workflowName);
/**
* Gets all (including previous) Workflow Definitions for the given unique name
*
* @param workflowName workflow name e.g. jbpm$wf:review
* @return the deployed workflow definition (or null if not found)
*/
@Auditable(parameters = {'workflowName'})
public List<WorkflowDefinition> getAllDefinitionsByName(String workflowName);
/**
* Gets a graphical view of the Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return image view of the workflow definition
*/
@Auditable(parameters = {'workflowDefinitionId'})
public byte[] getDefinitionImage(String workflowDefinitionId);
//
// Workflow Instance Management
//
/**
* Start a Workflow Instance
*
* @param workflowDefinitionId the workflow definition id
* @param parameters the initial set of parameters used to populate the 'Start Task' properties
* @return the initial workflow path
*/
@Auditable(parameters = {'workflowDefinitionId', 'parameters'})
public WorkflowPath startWorkflow(String workflowDefinitionId, Map<QName, Serializable> parameters);
/**
* Start a Workflow Instance from an existing 'Start Task' template node held in the
* Repository. The node must be of the Type as described in the Workflow Definition.
*
* @param templateDefinition the node representing the Start Task properties
* @return the initial workflow path
*/
@Auditable(parameters = {'templateDefinition'})
public WorkflowPath startWorkflowFromTemplate(NodeRef templateDefinition);
/**
* Gets all 'in-flight' workflow instances of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of 'in-flight' workflow instances
*/
@Auditable(parameters = {'workflowDefinitionId'})
public List<WorkflowInstance> getActiveWorkflows(String workflowDefinitionId);
/**
* Gets a specific workflow instances
*
* @param workflowId the id of the workflow to retrieve
* @return the workflow instance (or null if not found)
*/
@Auditable(parameters = {'workflowId'})
public WorkflowInstance getWorkflowById(String workflowId);
/**
* Gets all Paths for the specified Workflow instance
*
* @param workflowId workflow instance id
* @return the list of workflow paths
*/
@Auditable(parameters = {'workflowId'})
public List<WorkflowPath> getWorkflowPaths(String workflowId);
/**
* Gets the properties associated with the specified path (and parent paths)
*
* @param pathId workflow path id
* @return map of path properties
*/
@Auditable(parameters = {'pathId'})
public Map<QName, Serializable> getPathProperties(String pathId);
/**
* Cancel an 'in-flight' Workflow instance
*
* @param workflowId the workflow instance to cancel
* @return an updated representation of the workflow instance
*/
@Auditable(parameters = {'workflowId'})
public WorkflowInstance cancelWorkflow(String workflowId);
/**
* Delete an 'in-flight' Workflow instance
*
* NOTE: This will force a delete, meaning that the workflow instance may not
* go through all the appropriate cancel events.
*
* @param workflowId the workflow instance to cancel
* @return an updated representation of the workflow instance
*/
@Auditable(parameters = {'workflowId'})
public WorkflowInstance deleteWorkflow(String workflowId);
/**
* Signal the transition from one Workflow Node to another
*
* @param pathId the workflow path to signal on
* @param transition the transition to follow (or null, for the default transition)
* @return the updated workflow path
*/
@Auditable(parameters = {'pathId', 'transitionId'})
public WorkflowPath signal(String pathId, String transitionId);
/**
* Fire custom event against specified path
*
* @param pathId the workflow path to fire event on
* @param event name of event
* @return workflow path (it may have been updated as a result of firing the event
*/
@Auditable(parameters = {'pathId', 'event'})
public WorkflowPath fireEvent(String pathId, String event);
/**
* Gets all Tasks associated with the specified path
*
* @param pathId the path id
* @return the list of associated tasks
*/
@Auditable(parameters = {'pathId'})
public List<WorkflowTask> getTasksForWorkflowPath(String pathId);
//
// Workflow Timer Management
//
/**
* Gets all active timers for the specified workflow
*
* @return the list of active timers
*/
@Auditable(parameters = {'workflowId'})
public List<WorkflowTimer> getTimers(String workflowId);
//
// Task Management
//
/**
* Gets a Task by unique Id
*
* @param taskId the task id
* @return the task (or null, if not found)
*/
@Auditable(parameters = {'taskId'})
public WorkflowTask getTaskById(String taskId);
/**
* Gets all tasks assigned to the specified authority
*
* @param authority the authority
* @param state filter by specified workflow task state
* @return the list of assigned tasks
*/
@Auditable(parameters = {'authority', 'state'})
public List<WorkflowTask> getAssignedTasks(String authority, WorkflowTaskState state);
/**
* Gets the pooled tasks available to the specified authority
*
* @param authority the authority
* @return the list of pooled tasks
*/
@Auditable(parameters = {'authority'})
public List<WorkflowTask> getPooledTasks(String authority);
/**
* Query for tasks
*
* @param query the filter by which tasks are queried
* @return the list of tasks matching the specified query
*/
@Auditable(parameters = {'query'})
public List<WorkflowTask> queryTasks(WorkflowTaskQuery query);
/**
* Update the Properties and Associations of a Task
*
* @param taskId the task id to update
* @param properties the map of properties to set on the task (or null, if none to set)
* @param add the map of items to associate with the task (or null, if none to add)
* @param remove the map of items to dis-associate with the task (or null, if none to remove)
* @return the update task
*/
@Auditable(parameters = {'taskId', 'properties', 'add', 'remove'})
public WorkflowTask updateTask(String taskId, Map<QName, Serializable> properties, Map<NodeRef>> add, Map<NodeRef>> remove);
/**
* End the Task (i.e. complete the task)
*
* @param taskId the task id to end
* @param transition the task transition to take on completion (or null, for the default transition)
* @return the updated task
*/
@Auditable(parameters = {'taskId', 'transitionId'})
public WorkflowTask endTask(String taskId, String transitionId);
//
// Package Management
//
/**
* Create a Workflow Package (a container of content to route through the Workflow).
*
* If an existing container is supplied, it's supplemented with the workflow package aspect.
*
* @param container (optional) a pre-created container (e.g. folder, versioned folder or layered folder)
* @return the workflow package
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {'container'})
public NodeRef createPackage(NodeRef container);
/**
* Gets the Workflows that act upon the specified Repository content.
*
* @param packageItem the repository content item to get workflows for
* @param active true => active workflows only, false => completed workflows only
* @return list of workflows which act upon the specified content
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {'packageItem', 'active'})
public List<WorkflowInstance> getWorkflowsForContent(NodeRef packageItem, boolean active);
SPI to be implemented by a BPM Engine that provides Workflow management.
//
// Workflow Definition Support
//
/**
* Deploy a Workflow Definition
*
* @param workflowDefinition the content object containing the definition
* @param mimetype (optional) the mime type of the workflow definition
* @return workflow deployment descriptor
*/
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype);
/**
* Is the specified Workflow Definition already deployed?
*
* Note: the notion of 'already deployed' may differ between bpm engines. For example,
* different versions of the same process may be considered equal.
*
* @param workflowDefinition the definition to check
* @param mimetype the mimetype of the definition
* @return true => already deployed
*/
public boolean isDefinitionDeployed(InputStream workflowDefinition, String mimetype);
/**
* Undeploy an exisiting Workflow Definition
*
* TODO: Determine behaviour when 'in-flight' workflow instances exist
*
* @param workflowDefinitionId the id of the definition to undeploy
*/
public void undeployDefinition(String workflowDefinitionId);
/**
* Gets all deployed Workflow Definitions
*
* @return the deployed workflow definitions
*/
public List<WorkflowDefinition> getDefinitions();
/**
* Gets a Workflow Definition by unique Id
*
* @param workflowDefinitionId the workflow definition id
* @return the deployed workflow definition
*/
public WorkflowDefinition getDefinitionById(String workflowDefinitionId);
/**
* Gets a Workflow Definition by unique name
*
* @param workflowName workflow name e.g. jbpm$wf:review
* @return the deployed workflow definition
*/
public WorkflowDefinition getDefinitionByName(String workflowName);
//
// Workflow Instance Support
//
/**
* Start a Workflow Instance
*
* @param workflowDefinitionId the workflow definition id
* @param parameters the initial set of parameters used to populate the 'Start Task' properties
* @return the initial workflow path
*/
public WorkflowPath startWorkflow(String workflowDefinitionId, Map<QName, Serializable> parameters);
/**
* Gets all 'in-flight' workflow instances of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of 'in-flight' workflow instances
*/
public List<WorkflowInstance> getActiveWorkflows(String workflowDefinitionId);
/**
* Gets a specific workflow instances
*
* @param workflowId the id of the workflow to retrieve
* @return the workflow instance
*/
public WorkflowInstance getWorkflowById(String workflowId);
/**
* Gets all Paths for the specified Workflow instance
*
* @param workflowId workflow instance id
* @return the list of workflow paths
*/
public List<WorkflowPath> getWorkflowPaths(String workflowId);
/**
* Cancel an 'in-flight' Workflow instance
*
* @param workflowId the workflow instance to cancel
* @return an updated representation of the workflow instance
*/
public WorkflowInstance cancelWorkflow(String workflowId);
/**
* Signal the transition from one Workflow Node to another within an 'in-flight'
* process.
*
* @param pathId the workflow path to signal on
* @param transition the transition to follow (or null, for the default transition)
* @return the updated workflow path
*/
public WorkflowPath signal(String pathId, String transitionId);
/**
* Gets all Tasks associated with the specified path
*
* @param pathId the path id
* @return the list of associated tasks
*/
public List<WorkflowTask> getTasksForWorkflowPath(String pathId);
SPI to be implemented by a BPM Engine that provides Task management.
/**
* Gets a Task by unique Id
*
* @param taskId the task id
* @return the task
*/
public WorkflowTask getTaskById(String taskId);
/**
* Gets all tasks assigned to the specified authority
*
* @param authority the authority
* @param state filter by specified workflow task state
* @return the list of assigned tasks
*/
public List<WorkflowTask> getAssignedTasks(String authority, WorkflowTaskState state);
/**
* Gets the pooled tasks available to the specified authority
*
* @param authority the authority
* @return the list of pooled tasks
*/
public List<WorkflowTask> getPooledTasks(List<String> authorities);
/**
* Update the Properties and Associations of a Task
*
* @param taskId the task id to update
* @param properties the map of properties to set on the task (or null, if none to set)
* @param add the map of items to associate with the task (or null, if none to add)
* @param remove the map of items to dis-associate with the task (or null, if none to remove)
* @return the update task
*/
public WorkflowTask updateTask(String taskId, Map<QName, Serializable> properties, Map<NodeRef>> add, Map<NodeRef>> remove);
/**
* Start the specified Task
*
* Note: this is an optional task operation. It may be used to track
* when work started on a task as well as resume a suspended task.
*
* @param taskId the task to start
* @return the updated task
*/
public WorkflowTask startTask(String taskId);
/**
* Suspend the specified Task
*
* @param taskId
* @return the update task
*/
public WorkflowTask suspendTask(String taskId);
/**
* End the Task (i.e. complete the task)
*
* @param taskId the task id to end
* @param transition the task transition to take on completion (or null, for the default transition)
* @return the updated task
*/
public WorkflowTask endTask(String taskId, String transitionId);
You can find an example of how to deal with those API by looking at the source code of class WorkflowInterpretor.
jBPM has several hook points for integrating custom behaviour into a Workflow. To start with, extensions will take the form a jBPM ActionHandler.
It seems it's also possible to plug-in new node types (with their own xml declaration) into jBPM, so alternative xml representations may also be available. TODO: Document...
An ActionHandler that invokes an Alfresco Script.
<action class='org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript'>
<script>
<expression>
// some alfresco javascript
</expression>
<variable name='passedInValue' access='read'/>
<variable name='passedOutValue' access='write'/>
</script>
</action>
Or
<action class='org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript'>
<script>
// some alfresco javascript
</script>
</action>
The script is passed all process variables and executed, unless the <variables> element is provided, in which case, specific variables may be passed in and out. Node References will be converted to Node objects for simple Alfresco Node navigation and operation. The standard jBPM objects accessible in BeanShell are also accessible in Alfresco JavaScript e.g. executionContext, taskInstace...
jBPM already provides scripting support in the form of BeanShell. It provides access to workflow context in the form of some pre-defined variables (Java Objects). The Alfresco script will also have access to the same variables. In return, BeanShell scripts will have access to Alfresco Node objects.
Alfresco actions are now invocable via Alfresco JavaScript. Please see JavaScript_API#Actions_API.
The action named 'start-workflow' is used to automate the start of advanced workflows e.g. from rules. It supports the following parameters:
All other parameters are passed to the start task of the workflow. Namespaced parameters such as bpm:workflowDueDate are allowed.
The 'actioned' upon Repository node is placed into the workflow package of the started workflow.
e.g.
The following Rule script may be used to initiate the 'Review & Approve' workflow for content that is acted upon by the rule. The script assigns the workflow to the person who kicked off the rule, and sets a due date to 7 days in the future.
var workflow = actions.create('start-workflow');
workflow.parameters.workflowName = 'jbpm$wf:review';
workflow.parameters['bpm:assignee'] = person;
var futureDate = new Date();
futureDate.setDate(futureDate.getDate() + 7);
workflow.parameters['bpm:workflowDueDate'] = futureDate;
workflow.execute(document);
Refer to Task Command Processor.
Workflow Plan - for historical reasons only.
russ:
What does it take to describe a task (task prototype)?
If it possible for a task / or even the runtime to publish certain event like task started, suspended, continued, stopped, failed, completed; it be comes natural to support operations such as sending email notifications or much richer functionalities. Other processes may subscribe for events allowing them to be separately described and loosely coupled via asynchronous messaging paradigm. In terms of implementation it is consistant with almost any BPM because evented process is just like any other process the only differnce is how it was started.
Challanges can be auditing the results of a process which published an event which may or may not initiate another process: it can be difficult to say let me see the history of this process and all of the effects it created.
What are tasks described in? Is this tied to the implementation? JDML is a job description markup targeted at Grid but incorporates some of the concepts discussed by this document.