Event Listener module
Job module
Language module
Macro Module
Servlet Filter module
Servlet module
Theme module
Web UI modules
Workflow module

Workflow Plugin Prototype

Introduction

This page describes a prototype Workflow Plugin for Confluence. After reading it you should be able to create a workflow description and use it to manage a set of pages in Confluence.

The purposes of the Confluence Workflow Plugin Prototype are:

  1. To provide a simple but usable workflow system for Confluence.
  2. To solicit further requirements for Workflow in Confluence.
  3. To demonstrate the power of the Confluence Plugin system - the workflow plugin did not require any changes to the core of Confluence.

The feature that this does not provide is the ability of different users to see different versions of a page. This is a problem for approval workflows, where we want an edit to remain invisible to 'ordinary' users until it has been approved.

I've also written up some ideas for a minimal Approval Workflow.

Plugin Information

You will need Java and Groovy development skills to implement this plugin. This is currently provided 'as-is' without Atlassian technical support, but you can search for or post questions relating to it in the Developer Forums. Alternatively, the Atlassian partner Saikore now offers paid support.

Workflow Concepts

This section describes the concepts used in building the Workflow Plugin.

Workflow Client

This is the entity whose life cycle is managed by the workflow plugin. In this implementation a client is a Confluence page. The client is responsible for remembering which workflow it is taking part in, remembering its workflow state, and changing this state when told to by the workflow system. A client may (and should) have other state information which is not visible to the workflow system, for instance the contents of a Confluence page are not managed by the workflow system at all.

Workflow Type

This is the set of data which defines a workflow. A workflow type is assembled from collections of States, Operations, Triggers and Actions.

Workflow State

At any time a Workflow Client is in one (and only one) State. This state determines which Operations are available to be performed on the client.

Operation

An Operation may be requested by the user on a Workflow Client. An Operation itself doesn't change any state, either in the workflow system or in the Workflow Client, but simply sends a signal to the Workflow Type that this Operation has been requested on that particular Workflow Client. It is just a description meaningful to a user, associated with a code meaningful to the Workflow Type, together with security rules to determine when the Operation can be performed. The signals sent to the Workflow Type may cause one or more Triggers to fire. Whether an Operation is available on a particular Client depends on the State of the client and the group membership of the current user. In addition to Operations defined in a particular Workflow Type, all Workflow Types recognize page edit and page view operations.

Trigger

A Trigger listens for Operations, and either fires or does not fire, depending on the Operation, its internal state (if any - many simple triggers are stateless) and its implementation. When a Trigger fires it tells the set of Actions it contains to execute.

Examples of Triggers are:

  1. Fire every time you receive a particular event.
  2. Fire after receiving any of a set of events.
  3. Fire after receiving all of a set of events, in any order. (This requires a Trigger which can maintain internal state)

Action

An Action is a piece of code which is executed in response to the firing of a Trigger.

Some Actions interact with the Workflow System:

  1. Change Workflow State of Client.
  2. Create a new Trigger.
  3. Remove a Trigger.

Others interact with Confluence:

  1. Restrict Page Permissions
  2. Remove Page Permissions restriction.
  3. Send Notification to prior editor of page.

Others could interact with the contents of the page itself:

  1. Add 'Draft' warning to page contents.
  2. Validate field values in the page contents.

Using The Prototype Confluence Workflow Plugin

Build and Install the Workflow Plugin

From you Confluence install directory, go to plugins/workflow or acccess from the Confluence source under src/etc/plugins/workflow. Build the plugin into a JAR file.

Configure groups and permissions

Decide what groups will be involved in the workflow, create them and assign appropriate users to them. Grant suitable permissions to the space.

Create a WorkflowType

You need to create an instance of a class which implements com.atlassian.confluence.extra.workflow.WorkflowType, and register it by passing it to WorkflowManager.registerType().

One way to do this on a test basis is to put your workflow type in a {script} macro. The script macro can be downloaded from here. You'll need to visit the page after restarting the server.

The example below uses a Groovy script - you could just as well use Beanshell, Jython or JRuby.

1
2
 
{script:groovy} 
import com.atlassian.confluence.extra.workflow.*; 
import com.atlassian.confluence.core.ContentPermission; 
State requested = new State("test", "In Progress", "In Progress"); 
State readyToReview = new State("test", "Ready for review", "Ready for review"); 
State accepted = new State("test", "Accepted", "Accepted"); 
State rejected = new State("test", "Rejected", "Rejected"); 
def states = [DEV:requested, readyToReview, accepted, rejected]; 
def ops = [ 
new DefaultOperation([DEV:requested, rejected], [DEV:"writer"], "completed", "Submit for Review"), 
new DefaultOperation([DEV:readyToReview],[DEV:"reviewer"], "accept", "Accept"), 
new DefaultOperation([DEV:readyToReview],[DEV:"reviewer"], "reject", "Reject"), 
]; 
def groups = [DEV:"writer", "reviewer", "confluence-administrator"]; 
def triggers = [ 
new SingleEventTrigger("init", 
[DEV: 
new StateChangeAction(requested), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.EDIT_PERMISSION,"writer")), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.VIEW_PERMISSION,"writer")), 
] 
), 
new SingleEventTrigger( 
"completed", 
[DEV: 
new StateChangeAction(readyToReview), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.EDIT_PERMISSION,"reviewer")), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.VIEW_PERMISSION,"reviewer")), 
] 
), 
new SingleEventTrigger( 
"accept", 
[DEV: 
new StateChangeAction(accepted), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.EDIT_PERMISSION,"empty-group")), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.VIEW_PERMISSION,"confluence-users")) 
] 
), 
new SingleEventTrigger( 
"reject", 
[DEV: 
new StateChangeAction(rejected), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.EDIT_PERMISSION,"writer")), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.VIEW_PERMISSION,"writer")) 
] 
), 
new SingleEventTrigger( 
PageEditOperation.OPERATION_NAME, 
[DEV: 
new StateChangeAction(requested), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.EDIT_PERMISSION,"writer")), 
new RestrictAccessToGroupAction(new ContentPermission(ContentPermission.VIEW_PERMISSION,"writer")) 
] 
), 
]; 
WorkflowManager.registerType(new DefaultWorkflowType("test2","Page Review 2",states,ops,triggers,groups)); 
{script} 

Put a {workflowtype:yourWorkflowTypeName} macro after your script, so you can see that it is properly creating the WorkflowType.

Create a Workflow Page

To make a page take part in the workflow you have just created, add the {workflow:workflowTypeName} macro to the page and hit Update.

You'll get a workflow box with the option 'Start Workflow'. Select this and the page will refresh. The workflow box will now indicate that the page is in the starting state for that workflow type.

Monitoring Workflow

You can use the {workflowTasks} macro to display a list of all workflow pages which are descendants of the current page. Any task which the viewing user can perform an action on will be starred.

To Do

  1. More Trigger types.
  2. More Action types.
  3. Easy editing of WorkflowTypes.
  4. Workflow of parent can depend on states of children
  5. Introduce concept of 'Assignments', where at one workflow step a particular user is assigned to a role which nominates them to perform other operations.
  6. Think about the visual style - the current style is good for when workflow is 'out of band', that is, it's an activity undertaken by site maintainers invisible to site users, but doesn't suit a 'Confluence as web-app' application, where workflow should blend in...

Rate this page: