User Task
Overview
A User Task is a type of task that is assigned to a user or a group for manual completion within a business process. User tasks are integral to the workflow, allowing human participants to interact with the process by performing specific actions, making decisions, or providing input.
Single performer vs. group In BPMN can be the only performer of the task. When we say "the task is assigned to group", it means there is a list of potential performers, not a UserGroup object. One of them must become an actual task performer by claiming the task on himself. |
A user task is visualized as a typical task (rounded rectangle), with a small user icon in the left upper corner.
A user task is defined in XML as follows.
The id
attribute is required, the name
attribute is optional.
<userTask id="user-task-01" name="User task" />
Properties
User task has common properties as other activities have and three specific sections:
-
Assignee, where you can assign a single task performer or potential performers (candidates);
-
Form, where you can define a user interface for the task;
-
Task Listeners, where you can add listeners triggered by task lifecycle events.
Besides, it has an additional property in the General section — Due Date to inform the performer when the task must be completed.
Due Date
The due date parameter in a user task specifies the deadline by which the task must be completed. This parameter is crucial for managing time-sensitive activities within a business process.
Take in account that due date doesn’t affect the process itself. When the appointed date arrives, nothing happens in the process — you should manage this event yourself. For example, in the custom task list.
Setting Due Date
There is a due date field at the user task properties panel in the General section:
The Due date parameter can be set in two variants:
-
Fixed date: Some date in the future that means a deadline. (The date in the past will be ignored, the task will be shown as overdue.)
-
Duration: A period of time started from the moment when the task is created.
Actually, due date is a text field that will be interpreted by the process engine at runtime. The following variants are available:
-
Literal string in ISO8601 format, representing fixed date or duration.
-
Process variable of the type:
-
java.lang.String
— must contain a value in ISO8601 format. -
java.util.Date
— must contain date value.
-
-
Expression that must be resolved at runtime as one of the above variants, for example
$/{someDateVariable/}
.
|
ISO 8601 examples
-
Fixed date:
-
2024-02-01T08:40:37
-
2050-01-01
-
-
Duration:
-
PT20M - in 20 minutes
-
PT5H - in 5 hours
-
PT3D - in 3 days
-
Accessing Due Date Programmatically
It is possible to manipulate due date parameter using Task
class methods:
Task task = taskService.createTaskQuery()
.taskId("taskId").singleResult(); (1)
task.getDueDate(); (2)
task.setDueDate(null); (3)
taskService.saveTask(task); (4)
1 | — get task by id |
2 | — get the current value of due date |
3 | — set new due date value equals 'null' |
4 | — save task object |
So, you can change due dates dynamically depending on your business logic. For example, the assignee can ask for additional time to complete the task.
Using Business Calendar
When you have a Business Calendars add-on installed, the corresponding field appears in the General properties section in the Web BPM Modeler:
Here you can select one of preconfigured business calendars from the pull-down list. In this case, the due date can be set only as duration, and the elapsed time will be calculated taking into account the business calendar.
For example, the user received the task at 04:00 PM.
In the business calendar standard working time is set from 10:00 AM till 06:00 PM,
and a due date parameter is set for 3 hours (PT3H
).
The deadline will be set not at 07:00 PM right after 3 hours but at 11:00 AM the next working day. With business calendar, only working hours are counted.
With business calendar duration can be set in hours and minutes, not in days. |
XML representation A user task with due date:
<userTask id="Activity_0gsy9yk" name="User task"
flowable:dueDate="PT3H" (1)
flowable:businessCalendarName="test-calendar"> (2)
. . .
</userTask>
1 | — Due date as duration |
2 | — Business calendar attribute |
See details in Business Calendars add-on.
User Assignment
In order for a task to be ultimately completed, it must be assigned a performer. Only one user can be assigned as the human performer for the task, this user is called an assignee.
The assignee
attribute can be empty. It means there is no user who sees this task in his task list.
Such a task usually is considered as a group task, when there is a list of potential performers or candidates.
As well, you can set the assignee at runtime — by using administrative functions or programmatically.
Assignee Sources
In Jmix BPM, the assignee source refers to the mechanism used to determine which way the user will be selected to be an assignee for a specific user task in a business process. There are three options, how to do that:
Expression |
— here must be an expression that result is a String containing username. |
Process variable |
— a variable that refers to User entity. |
User provider |
— a special Java class with the method returning a username. |
Assigning Task by Expression
Expression is a default assignee source.
You will need to write an expression that evaluates a username of an assignee.
For example, if the User
entity is stored in a process variable called manager
, then the expression will be ${manager.username}
:
XML representation
<userTask id="user-task-01" name="User task"
flowable:assignee="${manager.username}"
jmix:assigneeSource="expression"
jmix:assigneeValue="${manager.username}" />
If you want to assign a task to a specific user, you can write a username directly:
Also, you can invoke Spring bean method that returns username:
${smpl_MyBean.evaluateManager(methodParam1, 'methodParam2')}
Assigning Task by Process Variable
If you select the Process variable assignee source, the ComboBox component will be displayed in the properties panel. This field displays those fields and process variables that are of the Entity
type, and their entity class implements the UserDetails
interface.
Built-in initiator
variable
The build-in initiator
process variable is available for assigning tasks while modeling a process. It contains an entity of the user that started the process:
XML representation
A user task with the performer assigned by process variable:
<userTask id="user-task-01" name="User task"
camunda:assignee="${initiator.username}"
jmix:assigneeSource="processVariable"
jmix:assigneeValue="initiator" />
If the process was started via API or by message/signal, |
You can disable the initiator
process variable using the following property:
jmix.bpm.process-initiator-variable-enabled=false
Also, you can change the name of the initiator property:
jmix.bpm.process-initiator-variable-name=manager
Assigning Task by User Provider
If you need to apply a complicated business logic to define a task performer, better to choose a User provider option. In this case, the system offers to select an existing user provider Java class or allows to create a new one:
User provider should implement one or more methods with the String
returned type.
A method gets parameter values that are specified in the modeler and returns a username of the user that should become a task assignee.
If the class has the only method, it’d be applied automatically:
XML representation
A user task with performer assigned by User Provider:
<userTask id="user-task" name="User task" jmix:assigneeSource="userProvider" jmix:assigneeValue="smpl_MyUserProvider">
<extensionElements>
<jmix:springBean beanName="smpl_MyUserProvider" methodName="getUser" />
</extensionElements>
</userTask>
User provider class is a common Spring bean, annotated by @UserProvider
annotation.
Here is an example of the user provider that reads a process variable with the user email and finds the user in the database.
@UserProvider(value = "smpl_MyUserProvider", description = "Returns a user with the specified email")
public class MyUserProvider {
@Autowired
private DataManager dataManager;
public String getUserByEmail(String parameter) {
return dataManager.load(User.class)
.query("select u from smpl_User u where u.email = :email")
.parameter("email", parameter)
.one()
.getUsername();
}
}
You can implement any business rules in UserProvider
class.
For example, select the less busy user from the role or from the department; select next in turn; at least, select a random user from the group.
Assigning Task Programmatically
To set the task assignee programmatically, you can use the setAssignee
method on the TaskService
. Here’s an example:
Task task = taskService.createTaskQuery()
.taskId("taskId")
.singleResult(); (1)
taskService.setAssignee(task.getId(), "jane"); (2)
1 | — getting task object by Query API |
2 | — setting assignee by username |
Tasks assigned to the certain user can be retrieved through the TaskService
as follows:
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee("jane") (1)
.list();
1 | — username |
Task Candidate Users and Groups
Candidates refer to users or groups who are eligible to claim and complete a task. When a task has multiple candidates assigned to it, the task appears in the task lists of all the candidates. The first candidate who claims the task becomes the assignee and can then complete the task. After that, the task becomes not visible to other candidates.
The term "groups" here technically means a list of User group codes. |
Claiming Group Tasks
It often happens that we don’t need it a certain user performs the task. For example, it doesn’t matter for a manager who from two accountants make a decision about his order.
In this case, Jmix BPM allows assigning the task to candidates list — and any of its members can become a performer. But previously he or she must claim the task. Claiming is an action of taking task ownership by user.
The task with candidates appears in My tasks view in the Group tasks section for each candidate.
After any of the candidates claims the task, the task moves to the Assigned tasks list for this user and disappears from the Group tasks list of other candidates.
To claim the task user must open it and take one of the actions:
-
Claim and resume — the user becomes a task assignee, the task form will be reopened in normal mode, and he or she can continue to work with it.
-
Claim and close — the user becomes a task assignee, the task form will be closed; he or she can find it later in the Assigned tasks section of a task list:
Claiming Task Programmatically
It’s possible to claim the task on the specified user via API:
taskService.claim("taskId", "userId");
Setting Candidates in Studio
To set up candidates in Studio use corresponding user task properties in BPMN Inspector:
To enter values in these fields, click an Edit button , and type user groups codes or usernames in editor window as a comma-separated list:
XML representation
<userTask id="Activity_0cu0xtq" name="User task"
camunda:candidateUsers="bob, peter"
camunda:candidateGroups="accountants, sales"
jmix:candidateGroupsValue="accountants, sales"
jmix:candidateUsersValue="bob, peter" />
. . .
</userTask>
Studio doesn’t see real user groups and users. So it is on developer’s responsibility to use only valid group codes and usernames as candidates. Otherwise, it causes a runtime error. |
Setting Candidates in Web BPM Modeler
In the Web BPM Modeler, more options for setting candidate groups and users are available. For setting candidate groups, click the Edit button:
Then the Candidate groups editor window will be opened where you’d be able to select the candidate groups source:
-
User groups — pick user groups from the list.
-
User groups provider — select a special Java class that returns a list of user groups.
-
Expression — get a list of user groups from expression, for example, from the process variable defined earlier in the process.
Set Candidates by User Groups
If you have chosen a User groups option as a source, you can select any from existing user groups:
User Groups Provider
If you need to implement a complicated logic when setting candidate groups, better choose the User groups provider option.
It allows to select one of previously created Java beans provided with the @UserGroupListProvider
annotation.
This bean must implement one or more methods returning List<String>
containing user group codes.
The @UserGroupListProvider
annotation has two attributes:
-
value — a name that will be displayed in the modeler.
-
description — an explanation of the method’s purpose, optional.
Here is an example:
@UserGroupListProvider(value="allGroups",
description = "Returns a list of all groups")
public class MyGroupListProvider {
@Autowired
private UserGroupService userGroupService;
public List<String> getAllUserGroups() {
List<UserGroup> allUserGroups = userGroupService.getAllUserGroups();
if (!allUserGroups.isEmpty()) {
return allUserGroups.stream().map(UserGroup::getCode).toList();
} else {
return Collections.emptyList();
}
}
}
See the User groups section for more information.
Set Candidate Groups by Expression
The most general way of setting BPMN parameters is expression. For candidate groups, it is also available:
Candidate Users Options
Setting candidate users in the Web BPM Modeler is very similar to setting candidate groups. Here are sources you can choose from:
-
User groups — pick usernames from the list.
-
User groups provider — select a special Java class that returns a list of usernames.
-
Expression — get a list of usernames from expression.
User List Provider
Similar to User Groups Provider, you can get a list of candidate users programmatically
via calling a method of the Spring bean annotated by @UserListProvider
annotation:
Here is an example:
@UserListProvider(value = "smpl_UserListProviderDemo",
description = "Get all users")
public class UserListProviderDemo {
@Autowired
private DataManager dataManager;
@Autowired
private SystemAuthenticator authenticator;
public List<String> getAllUsers() {
authenticator.begin();
try {
List<User> users = dataManager.load(User.class).all().list();
return users.stream().map(User::getUsername).toList();
} finally {
authenticator.end();
}
}
}
Set Candidate Users by Expression
As well, you can use the most common way of setting parameter of the process model — by expression:
For example, this way you can refer to the username of the User entity variable:
${initiator.username}
CandidateUsers and candidateGroups can both be defined on the same user task.
Defining User Task Forms
User task can be configured to use a process form to visualize it for performer. Jmix BPM offers the following options for process forms:
By default, a new user task is created with no form. You can select one while configuring the task.
Recommendations on using process forms
Choose Input dialog forms for the rapid prototyping or for uncomplicated forms not needed customization even in production. Such forms usually operate with simple data types — strings, numbers, enums, dates.
When you need to show on the form complex data objects like entities or collections of entities with many fields, validations, and formatting requirements, it’d be better to choose Jmix view. However, this requires more efforts.
User Task Outcomes
When users complete a user task, they often have to make a decision, for example, approve or reject the document. After that, the process should go one or another way. You can use task outcomes for modeling such cases.
Outcomes appear on process forms as buttons that may be provided with icon. Wherein, default Complete button becomes not visible.
You can create outcomes both in input dialog forms and Jmix views but different ways. See details below.
Outcomes in Input Dialog Forms
For input dialog process forms, outcomes are defined in the Outcomes section in the BPMN Inspector panel.
You can create outcomes using Outcomes editor, set its id, caption, and icon:
Later you can edit outcomes directly in the BPMN Inspector panel:
In the Web BPM Modeler, you can see outcomes in the properties panel:
To create or edit the outcome, use Outcome editor:
XML representation
When outcomes are used with the input dialog form, a special jmix:formOutcomes section is added. Here you can see your outcomes with jmix:formOutcome attributes.
<userTask id="Activity_0cu0xtq" name="User task" camunda:candidateUsers="bob, peter" camunda:candidateGroups="accountants, sales" jmix:candidateGroupsValue="accountants, sales" jmix:candidateUsersValue="bob, peter">
<extensionElements>
<jmix:formData type="input-dialog" openMode="DIALOG">
<jmix:formOutcomes> (1)
<jmix:formOutcome id="approve" caption="Approve" icon="CHECK" /> (2)
<jmix:formOutcome id="reject" caption="Reject" icon="BAN" /> (3)
</jmix:formOutcomes>
</jmix:formData>
</extensionElements>
</userTask>
1 | — outcomes section |
2 | — "approve" outcome |
3 | — "reject" outcome |
Outcomes in Jmix View Forms
For Jmix screen forms, outcomes are defined in the screen controller.
However, in the Studio you can see outcomes in the Form section just for reference — it helps to design the process without looking in the Jmix view controller code.
How to create and use outcomes in Jmix views, see in the corresponding section.
Using Outcomes
When the user clicks one of the outcome buttons, the task is completed
and the decision is written to a special process variable which name is built according to the following name pattern:
<user-task-id>_result
.
You can find it in the list of variables in the Process instance edit view.
It has type OutcomesContainer
that contains a list of Outcome
objets for the case when the given user task is multi-instanced.
You can access outcomes container programmatically:
String outcomeContainerName = taskIdValue + "_result"; (1)
OutcomesContainer outcomesContainer = (OutcomesContainer) execution
.getVariable(outcomeContainerName); (2)
1 | — Generate a name of the outcomes container. |
2 | — Get the outcomes container, that is a list of outcomes. |
This variable value holds information about the users (if many) that completed the task and outcomes they selected. Yuo can see it in the Process variable editor window.
Outcome-Based Conditions
After you set outcomes for the task, you need to specify conditions for sequence flows after the exclusive gateway element. You can write a condition expression or select an outcome from the drop-down list.
Let’s look at the example of configuring a sequence flow using outcome-based conditions. Here is a fragment of the process with user task and exclusive gateway having two outgoing sequence flows.
To specify conditions for the approved
sequence flow, select it on the canvas and configure its properties.
Change the Condition source to the User task outcome and select the task and its outcome in the drop-down lists.
Outcome-Based Conditions in Multi-Instance Mode
User tasks can be multi-instanced. See details on this mode in the Multi-Instance section. Here we look at only multi-instance mode affects outcome-based conditions.
In this example, the Approve invoice
task is multi-instance.
It means there is a collection of users performing this task, and each of them works with his or her own instance.
So, regarding this document, there will be made as many distinct decisions as there are users in the collection. But all their decisions will be accumulated in the one outcome container.
Therefore, we can specify an additional parameter – Condition type, that may have the following values:
-
Anyone completed with the outcome
-
Everyone completed with the outcome
-
No one completed the outcome
Thus, you can organize some kind of voting using this feature.
XML representation
<sequenceFlow id="Flow_15f0sh3" name="Approved" sourceRef="Gateway_1kb7ltq" targetRef="Activity_0xl938c">
<extensionElements>
<jmix:conditionDetails
conditionSource="userTaskOutcome" (1)
conditionType="anyoneCompleted" (2)
userTaskId="approve-invoice" (3)
userTaskOutcome="approve" /> (4)
</extensionElements>
<conditionExpression xsi:type="tFormalExpression">${execution.getVariable('approve-invoice_result') != null && bpm_UserTaskResults.containsOutcome(execution.getVariable('approve-invoice_result'), 'approve')}</conditionExpression>
</sequenceFlow>
1 | — Condition source selected. |
2 | — Condition type, by default equals anyoneCompleted even for not multi-instance tasks. In this case, it is hidden from the properties panel. |
3 | — Reference to the user task. |
4 | — The outcome selected. |
Setting Task Listeners
User tasks in Jmix BPM support the use of task listeners to execute custom logic in response to specific events. Task listeners allow you to define Java classes or expressions that will be triggered when certain events occur related to the user task.
Available events for task listeners on user tasks include:
-
create: Triggered when the user task is created
-
assignment: Triggered when the user task is assigned to a user or group
-
complete: Triggered when the user task is completed
-
delete: Triggered when the user task is deleted
To configure a task listener for a user task, you can use the flowable:taskListener
extension element in the BPMN XML
or the addTaskListener
method in the Java API.
Task listeners provide a powerful mechanism to extend the behavior of user tasks and integrate custom logic into your processes. They allow you to perform actions such as sending notifications, updating external systems, or performing additional validations based on the events that occur during the lifecycle of a user task.
XML representation
<userTask id="approve-invoice" name="Approve invoice" jmix:assigneeSource="expression">
<extensionElements>
. . .
<flowable:taskListener class="com.company.demo.listener.ApproverAssignment" (1)
event="assignment" /> (2)
</extensionElements>
. . .
</userTask>
1 | — Task listener class |
2 | — Task event |
See details in the Task Listeners section.
Task Documentation (Description)
To provide user with additional information, we have parameter documentation like it named in BPMN, or description as it is named in API. It can be no more than 4000 characters long.
Originally documentation field was intended to document a process model by analytics. But in the case of User task it can be considered as instruction for user, explaining what to do.
You can find this field at the very end of the properties panel.
You can update the documentation field every time you change your process. Thus, it’s the easiest and effective way to provide users with actual information. |