Workflow definition: 2-Step-Approver · Liferay 7.4 Kaleo workflow schema

 

Kaleo Workflow XML Definition

The complete XML definition for the 2-Step Approver workflow is shown below. This file is imported into Liferay DXP via Control Panel → Process Builder → Workflows → Add (+) → Source tab.

 

<?xml version="1.0"?>

<workflow-definition   xmlns="urn:liferay.com:liferay-workflow_7.4.0"  xsi:schemaLocation="urn:liferay.com:liferay-workflow_7.4.0 http://www.liferay.com/dtd/liferay-workflow-definition_7_4_0.xsd"

            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

            <name>2-Step-Approver</name>

            <description>Two-step approval workflow.</description>

            <version>1</version>

            <!-- ══ INITIAL STATE ══ -->

            <state>

                        <name>created</name>

                        <initial>true</initial>

                        <transitions>

                                    <transition>

                                                <name>review</name>

                                                <target>step-1-review</target>

                                                <default>true</default>

                                    </transition>

                        </transitions>

            </state>

            <!-- ══ TERMINAL STATE ══ -->

            <state>

                        <name>approved</name>

                        <metadata>

                                    <![CDATA[{"terminal": true}]]>

                        </metadata>

                        <actions>

                                    <action>

                                                <name>approve</name>

                                                <status>0</status>

                                                <execution-type>onEntry</execution-type>

                                    </action>

                        </actions>

            </state>

            <!-- ══ UPDATE TASK (Rejection target — assigned back to original author) ══ -->

            <task>

                        <name>update</name>

                        <actions>

                                    <action>

                                                <name>deny</name>

                                                <status>4</status>

                                                <priority>1</priority>

                                                <execution-type>onAssignment</execution-type>

                                    </action>

                                    <action>

                                                <name>pending</name>

                                                <status>1</status>

                                                <priority>2</priority>

                                                <execution-type>onAssignment</execution-type>

                                    </action>

                                    <notification>

                                                <name>Creator Modification Notification</name>

                                                <template>

                                                            <![CDATA[Your submission was rejected by ${userName}, please modify and resubmit.]]>

                                                </template>

                                                <template-language>freemarker</template-language>

                                                <notification-type>email</notification-type>

                                                <notification-type>user-notification</notification-type>

                                                <recipients receptionType="to">

                                                            <user></user>

                                                </recipients>

                                                <execution-type>onAssignment</execution-type>

                                    </notification>

                        </actions>

                        <assignments>

                                    <user></user>

                        </assignments>

                        <transitions>

                                    <transition>

                                                <name>resubmit</name>

                                                <target>step-1-review</target>

                                                <default>true</default>

                                    </transition>

                        </transitions>

            </task>

 

            <!-- ══ STEP 1: REVIEW TASK ══ -->

            <task>

                        <name>step-1-review</name>

                        <actions>

                                    <action>

                                                <name>pending</name>

                                                <status>1</status>

                                                <execution-type>onAssignment</execution-type>

                                    </action>

                                    <notification>

                                                <name>Step 1 Review Notification</name>

                                                <template>

                                                            <![CDATA[${userName} sent you a ${entryType} for review in the workflow.]]>

                                                </template>

                                                <template-language>freemarker</template-language>

                                                <notification-type>email</notification-type>

                                                <notification-type>user-notification</notification-type>

                                                <recipients receptionType="to">

                                                            <assignees></assignees>

                                                </recipients>

                                                <execution-type>onAssignment</execution-type>

                                    </notification>

                        </actions>

                        <assignments>

                                    <roles>

                                                <role>

                                                            <role-type>regular</role-type>

                                                            <name>Reviewer</name>

                                                </role>

                                    </roles>

                        </assignments>

                        <transitions>

                                    <transition>

                                                <name>approve</name>

                                                <target>step-2-final-approval</target>

                                                <default>true</default>

                                    </transition>

                                    <transition>

                                                <name>reject</name>

                                                <target>update</target>

                                                <default>false</default>

                                    </transition>

                        </transitions>

            </task>

 

            <!-- ══ STEP 2: FINAL APPROVAL TASK ══ -->

            <task>

                        <name>step-2-final-approval</name>

                        <actions>

                                    <action>

                                                <name>pending</name>

                                                <status>1</status>

                                                <execution-type>onAssignment</execution-type>

                                    </action>

                                    <notification>

                                                <name>Step 2 Final Approval Notification</name>

                                                <template>

                                                            <![CDATA[${userName} sent you a ${entryType} for final approval in the workflow.]]>

                                                </template>

                                                <template-language>freemarker</template-language>

                                                <notification-type>email</notification-type>

                                                <notification-type>user-notification</notification-type>

                                                <recipients receptionType="to">

                                                            <assignees></assignees>

                                                </recipients>

                                                <execution-type>onAssignment</execution-type>

                                    </notification>

                        </actions>

                        <assignments>

                                    <roles>

                                                <role>

                                                            <role-type>regular</role-type>

                                                            <name>Approver</name>

                                                </role>

                                    </roles>

                        </assignments>

                        <transitions>

                                    <transition>

                                                <name>approve</name>

                                                <target>approved</target>

                                                <default>true</default>

                                    </transition>

                                    <transition>

                                                <name>reject</name>

                                                <target>update</target>

                                                <default>false</default>

                                    </transition>

                        </transitions>

            </task>

 

</workflow-definition>

This guide explains every XML element used in the attached 2-Step-Approver workflow definition, one tag at a time, with the exact values from the file and what each one does at runtime. It's organized to be read top-to-bottom as a reference, or used to look up a single tag.

1. What This Workflow Does

Before going tag-by-tag, here is the routing this specific definition implements:

Node

Type

Assigned to

Where it can go next

created

state (initial)

— (no assignee)

Automatically moves to step-1-review

step-1-review

task

Role: Reviewer

approve → step-2-final-approval  |  reject → update

step-2-final-approval

task

Role: Approver

approve → approved (terminal)  |  reject → update

update

task

Original submitter (empty <user/>)

resubmit → step-1-review

approved

state (terminal)

— (no assignee)

End of workflow; sets content status to Approved

 

In short: content enters the workflow, a Reviewer checks it, an Approver gives final sign-off, and if either one rejects it, it's routed back to whoever originally submitted it for correction and resubmission — which loops back to Step 1.

2. Root & Header Tags

Tag

Value in this file

Purpose

<workflow-definition>

root element

The document root. The xmlns/xsi:schemaLocation attributes bind this file to the Liferay 7.4.0 Kaleo workflow XSD, so Liferay validates the structure against that schema on import.

<name>

2-Step-Approver

Display name shown in Control Panel → Workflow → Definitions, and in the dropdown when assigning this workflow to a content type.

<description>

Two-step approval workflow.

One-line summary shown next to the name in the admin UI. Purely descriptive — has no effect on execution.

<version>

1

Liferay's internal revision counter for this definition name. Every time you republish a definition under the same name, Liferay auto-increments this; a brand-new definition always starts at 1.

3. State Nodes — <state>

A <state> is a routing point with no owner. Nothing appears in anyone's task inbox for a state — the workflow just passes through it (or, for a terminal state, stops there). This file has exactly two: created and approved.

Tag

Seen on

Purpose

<initial>true</initial>

created

Marks this as the workflow's entry point. Every definition must have exactly one <state> with <initial>true</initial> — this is where new content lands the moment it enters workflow.

<metadata>

approved

Free-form CDATA JSON consumed by the graphical Workflow Designer in the admin UI. {"terminal": true} tells the designer to draw this node as an end-point. It is a UI hint only — it does not stop the engine from adding transitions out of it if you wanted to.

<transitions>

created

Wraps the outgoing <transition> elements for this node — see Section 5.

4. Task Nodes — <task>

A <task> is a node that requires a human decision — it shows up in a real user's (or role's) Assigned To Me list until someone acts on it. This file has three: step-1-review (Reviewer role), step-2-final-approval (Approver role), and update (routed back to whoever submitted the content).

4.1 <assignments>

Declares who a task is routed to. Liferay supports several assignment strategies; this file uses two of them:

Tag

Seen on

Purpose

<user></user>

update

An empty <user/> element is Liferay's shorthand for "the user who originally submitted this content into the workflow" — not a specific named account. This is what routes a rejected item back to its author instead of to a fixed person.

<roles>

step-1-review, step-2-final-approval

Wraps one or more <role> elements. Assigns the task to every user holding that role — any one of them can claim and complete it, rather than one fixed individual.

<role><role-type>

regular

Scope of the role lookup. regular means a global Liferay Role (defined once under Users & Organizations → Roles), independent of any specific site — as opposed to site or organization roles, which are scoped to a particular site/org.

<role><name>

Reviewer / Approver

The exact role name Liferay looks up at runtime. These roles must already exist in the portal (Regular Role) before this workflow is assigned to content, or task assignment will fail silently.

4.2 <notification> (inside <actions> on a task)

Covered in full in Section 7, since the same notification tags are used identically on states, tasks, and actions.

5. Transitions — <transitions> / <transition>

Every <state> or <task> that isn't terminal has a <transitions> block listing the paths a user (or the engine) can take out of it.

Tag

Example from file

Purpose

<transitions>

wraps 1+ <transition>

Container for every possible outward path from this node. A task with two <transition> children (like step-1-review's approve/reject) shows the assignee two action buttons.

<transition><name>

approve, reject, resubmit, review

The label for this path. On a task, this becomes the literal button text/action name the assignee clicks. On a state, it's just the internal transition name (states auto-fire, so there's no button).

<target>

e.g. step-2-final-approval

The name of the <state> or <task> this transition leads to. Must exactly match another node's <name> in the file.

<default>

true / false

Marks the primary transition on a node. When a node has multiple transitions, exactly one should be true — that's the one triggered by the definition's default action (and rendered as the primary button in the UI); others are secondary/alternate actions.

Concrete example — step-1-review's two transitions:

●       approve → target: step-2-final-approval, default: true — the primary path when the Reviewer approves.

●       reject → target: update, default: false — the alternate path when the Reviewer sends it back for correction.

6. Actions — <actions> / <action>

An <action> is something the engine does automatically at a defined point in a node's lifecycle — most commonly, changing the content's workflow status. Every <state> and <task> in this file has an <actions> wrapper containing one or more of these.

Tag

Purpose

<actions>

Container for one or more <action> and/or <notification> elements attached to a state or task.

<action><name>

A label for the action (e.g. "approve", "deny", "pending") — for readability only; it does not have to match a transition name.

<action><status>

The numeric WorkflowConstants status code applied to the content when this action fires. See the status code table below — this is the actual mechanism that marks content Approved, Denied, or Pending in Liferay.

<action><execution-type>

When the action fires — see the execution-type table below.

<action><priority>

Only needed when a node has multiple actions with the same execution-type. Lower number runs first. Used on the update task (see 6.3).

6.1 Status codes used in this file

These come from Liferay's WorkflowConstants class (com.liferay.portal.kernel.workflow.WorkflowConstants) — the numbers are fixed by Liferay core, not by this workflow file:

Value

Constant

Used on

0

STATUS_APPROVED

The approved state's action — marks content as live/published.

1

STATUS_PENDING

The pending action on step-1-review, step-2-final-approval, and (2nd) on update — content is still mid-workflow.

4

STATUS_DENIED

The deny action on update — briefly marks content Denied so any "denied" notification/rule fires, immediately before it's flipped back to Pending.

6.2 <execution-type> values used in this file

Value

Fires when...

Used on

onEntry

The moment the workflow enters this node.

The approve action on the approved state — status flips to Approved as soon as the workflow arrives there.

onAssignment

Every time this task is assigned (or re-assigned) to a user/role — including the very first assignment and any resubmission.

All pending/deny actions on the three tasks, and all four <notification> blocks.

6.3 Why the update task has two actions

This is a standard Liferay pattern (also used in the built-in Single Approver definition): when a task is rejected, the update task first sets status to Denied (priority 1), then immediately sets it to Pending (priority 2).

●       The brief Denied status is what triggers Liferay's "content was denied" notification behavior for the submitter.

●       It's then moved to Pending because the item is not actually finished — it's sitting in an active task (update) waiting on the author to fix and resubmit it, not permanently rejected.

●       The <priority> tag is what guarantees deny runs before pending, since both share execution-type onAssignment.


 

7. Notifications — <notification>

A <notification> sends a message when its parent action's execution-type condition is met. This file defines three, all firing onAssignment (i.e. every time the relevant task is handed to someone).

Tag

Purpose

<notification><name>

Internal label for the notification, shown to administrators only (e.g. "Step 1 Review Notification"). Not seen by end users.

<template> (CDATA)

The actual message body. Written in FreeMarker syntax here, using workflow context variables — ${userName} (who triggered it) and ${entryType} (the type of content, e.g. "Web Content Article").

<template-language>

Which templating engine parses <template>. All three notifications use freemarker (Liferay also supports plain text).

<notification-type>

Delivery channel. This file repeats the tag to send both email and user-notification (Liferay's in-app bell/notification panel) for every notification — recipients get both.

<recipients receptionType="to">

Who receives it. receptionType="to" marks these as primary recipients (Liferay also supports cc/bcc).

<recipients><user></user>

Empty <user/> here means the same thing it means in <assignments>: the original content submitter. Used on the update task's notification, so the author is told why their submission was rejected.

<recipients><assignees></assignees>

Sends to whoever the task was just assigned to — i.e. every member of the Reviewer or Approver role, on the two review notifications.

<notification><execution-type>

Same enumeration as action execution-type. onAssignment on all three — the notification fires every time the task is (re)assigned, not just the first time.

Message text used in this file, for reference:

●       Step 1 Review Notification: "${userName} sent you a ${entryType} for review in the workflow."

●       Step 2 Final Approval Notification: "${userName} sent you a ${entryType} for final approval in the workflow."

●       Creator Modification Notification: "Your submission was rejected by ${userName}, please modify and resubmit."

8. Quick Reference — All Tags, A→Z

Tag

Appears on

One-line meaning

<action>

state, task

One automatic effect (status change) fired at a lifecycle point.

<actions>

state, task

Container for that node's <action>/<notification> children.

<assignees>

recipients

Notification recipient = whoever the task was just assigned to.

<assignments>

task

Who a task is routed to.

<default>

transition

Marks the primary transition/button on a node.

<description>

workflow-definition

Admin-UI summary of the whole workflow.

<execution-type>

action, notification

When the action/notification fires (onEntry, onAssignment).

<initial>

state

Marks the workflow's single entry-point state.

<metadata>

state

Designer-UI hint (e.g. terminal node styling); not engine logic.

<name>

workflow-definition, state, task, action, transition, role, notification

The identifier/label for whichever element it's nested in.

<notification>

actions

An automatic email / in-app message.

<notification-type>

notification

Delivery channel: email and/or user-notification.

<priority>

action

Execution order when a node has multiple same-type actions.

<recipients>

notification

Who receives the notification, and how (to/cc/bcc).

<role>

roles

One role a task is assigned to.

<role-type>

role

Scope of the role: regular, site, or organization.

<roles>

assignments

Wraps one or more <role> assignees.

<state>

workflow-definition

An unowned routing node (no task inbox entry).

<status>

action

The WorkflowConstants status code to apply (0/1/4 in this file).

<target>

transition

The node this transition leads to.

<task>

workflow-definition

An owned routing node — appears in a user/role's task inbox.

<template>

notification

The notification message body (CDATA, FreeMarker).

<template-language>

notification

Templating engine for <template> — freemarker here.

<transition>

transitions

One possible outward path from a state or task.

<transitions>

state, task

Container for a node's outgoing <transition> elements.

<user>

assignments, recipients

Empty = "the original content submitter", not a fixed account.

<version>

workflow-definition

Liferay's auto-incremented revision number for this definition.

<workflow-definition>

root

Root element; binds the file to the Kaleo 7.4.0 XSD.

Comments