Table of Contents
This document is the user manual for the CUBA Platform business process management subsystem.
This manual is intended for developers who use the CUBA platform to create applications with business processes management functionality. It is assumed that the reader is familiar with the Developer’s Manual, which is available at https://www.cuba-platform.com/manual.
This manual, as well as other documentation on the CUBA platform, are available at https://www.cuba-platform.com/manual.
CUBA business process management subsystem is based on the Activiti framework, therefore general knowledge on the framework is beneficial. See http://www.activiti.org to learn more about the Activity framework.
An executable process description employs the BPMN 2.0 notation. Consequently, it is assumed that the reader is familiar with the notation. More information about BPMN 2.0 specification can be found at http://www.bpmn.org.
If you have any suggestions for improving this manual, please contact Technical Support at http://www.cuba-platform.com/support/topics.
When reporting errors in the documentation, please indicate the chapter and surrounding text to point the error.
In this chapter, we will create a small project to demonstrate how to use the business processes subsystem. As an illustration we will implement a contract approval process software.
Commonly an approval process involve the following steps:
Controller
role receives the task to validate an attached contract.Manager
role assigned, otherwise the process will be terminated with Not valid
state.Approved
or Not approved
state.Create a new project in Cuba Studio:
bpm-demo
demo
com.company.demo
Go to the Entities tab and press New entity. The class name is Contract
.
Create the following entity attributes:
number
(String
type)date
(Date
type)state
(String
type)Go to the Instance name tab. In the Name pattern field enter the value Contract %s
and add the number
attribute to Name pattern attributes.
Press the OK button to save the entity.
In the Entities section of navigator panel select the Contract
entity and click the Generate standard screens button. Default values of the screen creating window suits us, so just click Create.
The updateState()
method of the ApprovalHelper
bean will be invoked from the contract approval process for setting a contract state.
Method parameters:
entityId
- contract entity identifierstate
- contract stateOpen the project in an IDE. A simple way to do it is to use an IDE button from any section of the Studio navigator, e.g. Project properties.
Create a package com.company.demo.core
in the core
module. Create ApprovalHelper
class in this package.
ApprovalHelper.java.
package com.company.demo.core; import com.company.demo.entity.Contract; import com.haulmont.cuba.core.EntityManager; import com.haulmont.cuba.core.Persistence; import com.haulmont.cuba.core.Transaction; import javax.annotation.ManagedBean; import javax.inject.Inject; import java.util.UUID; @ManagedBean("demo_ApprovalHelper") public class ApprovalHelper { @Inject private Persistence persistence; public void updateState(UUID entityId, String state) { Transaction tx = persistence.getTransaction(); try { EntityManager em = persistence.getEntityManager(); Contract contract = em.find(Contract.class, entityId); if (contract != null) { contract.setState(state); } tx.commit(); } finally { tx.end(); } } }
Press the Generate DB scripts button of the Entities navigator section. In the database manager window press the Create database button.
Start the server with Run → Start application server command.
Open the application in a browser at http://localhost:8080/app or just click the link in the bottom of Studio navigator panel.
The final version of process model will look like this:
Let’s look at the sequence of steps to create the model.
Open the screen BPM → Process models in the running application web interface and press Create. Enter the model name Contract approval
and press OK. A new browser tab Model editor will be opened.
Select the Process roles property in the model properties panel. The process roles edit window will be opened.
There are 2 types of actors participate in the process: a manager and a controller. Create 2 roles: Controller
and Manager
.
Drag and drop the Start event node from the Start Events group to the workspace. We need to display a form to select the process actors when the process starts. Select the start event node. Select the Start form in its properties panel - a form selection window will be opened. Select Standard form
in the Form name field. Then add 2 form parameters:
procActorsVisible
with true
value indicates that a table for process actors selection will be displayed on the formattachmentsVisible
with true
value indicates that a table for attachments upload will be displayed on the formAdd the User task node from an Activities group to the model. Name it Validation
.
Select this node and assign the controller
value to the Process role property at the properties panel. This is how we defined that the task will be assigned to a process actor with controller
role.
Next select the Task outcomes property. The window for task outcomes edit will be opened. Outcomes define possible users actions when users receive tasks. Create 2 outcomes: Valid
and Not valid
. Define the Standard form
for both outcomes. Add form parameter commentRequired=true
for the Not valid
outcome, because we want to make a user add a comment in case of invalid contract.
Depending on the controller’s decision we have to send the contract to managers approval or to finish the process with the Not valid
state. The Exclusive gateway node from the Gateways group is used to control the process flow. Add it to the workspace and then add 2 more elements: Script task with Set 'Not valid' state
name and User task with Approval
name. Name the flow to the Script task as Not valid
and the flow to the User task should be named Valid
.
Select the Not valid
flow. Expand the dropdown list Flow outcome from the properties panel. It shows outcomes from the tasks before the gateway. Select the Not valid
value.
Now, if the Not valid
outcome is selected, a transition to this flow will be performed.
The Valid
flow should be marked as the default flow (if no other flows condition are true). Select the Valid
flow and tick the Default flow property.
Next select the Exclusive gateway and open its Flow order property editor. Make sure that the Not valid
flow goes on the first place in a list. If it is not true then change the flows sequence.
Let’s move to the Set 'Not valid' state
node. We need to set the state
property of the Contract entity to the Not valid
value. Select the node. Set the Script format property value to groovy
. Click on the Script property field - the script editor will be opened. Copy and paste the following code there:
import com.company.demo.entity.Contract def em = persistence.getEntityManager() def contract = em.find(Contract.class, entityId) contract.setState('Not valid')
You are allowed to use the process variables and platform objects persistence
and metadata
(see CUBA Platform. Developer’s Manual) in scripts. An entityId
variable is created on process start and stores an identifier of the linked entity.
After the contract state is changed, the process should be finished. Let’s add an End event node from the End events group to the workspace and link the node with the Set 'Not valid' state
.
Let’s go back to the Approval
task. Define the manager
process role for it like we did for the first task. In order the task to be assigned to many managers simultaneously set its Multi-instance type property to Parallel
.
Create 2 task outcomes: Approve
and Reject
(Task outcomes property). For both outcomes set the Standard form
form and set commentRequired
parameter to true
for the Reject
outcome.
After the approval is completed, or Approved
either Not approved
status should be assigned to the contract depending on the approval result. Add an Exclusive gateway node after the Approval task
. Add 2 Service task after the exclusive gateway: Set 'Approved' state
and Set 'Not approved' state
. They will do the same thing as the Script task we added earlier, but in another way. They will invoke a Spring bean method. Name the flow to the Set 'Approved' state
as Approved
, and name the flow to the Set 'Not approved' state
as Not approved
.
Select the Not approved
flow node and select the Reject
value in the Flow outcome list. Now if at least one of the managers performs the Reject
action then this outcome will be initiated. Select the Approved
flow node and check the Default flow checkbox. This means that if no other flow is initiated then this flow will be used.
Set the flow order for the Exclusive gateway like we did for the previous one. Select the Exclusive gateway and open the Flow order property editor. Not approved
should be processed first.
Let’s go back to the Service task. Select the Set 'Approved' state
node and set its Expression property to the following value:
${demo_ApprovalHelper.updateState(entityId, 'Approved')}
Apply the following script for the Set 'Not approved' state
:
${demo_ApprovalHelper.updateState(entityId, 'Not approved')}
Activiti engine is integrated with the String framework, so we can access Spring managed beans by their names. entityId
is a process variable that stores an identifier of the contract which is linked to the process. Its value is set on a process start.
Link both Service tasks with the End event and press the save model button. The model is ready and we can move to the model deployment.
The model deployment process consists of the following steps:
Select the model in the list on the Process models screen. Press the Deploy button. The model deployment window will be displayed. The model is deployed for the first time, so the Create new process option is selected. You will be able to deploy the model to existing processes for further model changes. Click OK. The process definition is created.
Open the screen BPM → Process Definitions. Open the 'Contract approval' item for editing. Change the Code field value to contractApproval
. We will search the process definition object by this code later in this chapter.
In this section, we will add an ability to work with the contract approval process to the contract editor screen.
Find the contract-edit.xml
screen in the Screens panel in Studio and open the screen for editing. Go to the XML tab and completely replace its content with the following code:
contract-edit.xml.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <window xmlns="http://schemas.haulmont.com/cuba/window.xsd" caption="msg://editCaption" class="com.company.demo.gui.contract.ContractEdit" datasource="contractDs" focusComponent="fieldGroup" messagesPack="com.company.demo.gui.contract"> <dsContext> <datasource id="contractDs" class="com.company.demo.entity.Contract" view="_local"/> <collectionDatasource id="procAttachmentsDs" class="com.haulmont.bpm.entity.ProcAttachment" view="procAttachment-browse"> <query><![CDATA[select a from bpm$ProcAttachment a where a.procInstance.entityId = :ds$contractDs order by a.createTs]]></query> </collectionDatasource> </dsContext> <layout expand="windowActions" spacing="true"> <fieldGroup id="fieldGroup" datasource="contractDs"> <column width="250px"> <field id="number"/> <field id="date"/> <field id="state" editable="false"/> </column> </fieldGroup> <groupBox id="procActionsBox" caption="msg://process" orientation="vertical" spacing="true" width="AUTO"> <iframe id="procActionsFrame" screen="procActionsFrame"/> </groupBox> <groupBox caption="msg://attachments" width="700px" height="300px"> <table id="attachmentsTable" height="100%" width="100%"> <columns> <column id="file.name"/> <column id="author"/> <column id="type"/> <column id="comment" maxTextLength="50"/> </columns> <rows datasource="procAttachmentsDs"/> </table> </groupBox> <iframe id="windowActions" screen="extendedEditWindowActions"/> </layout> </window>
Go to the Layout tab. The resulting screen layout is shown below:
The screen contains a FieldGroup for contract editing, a frame for displaying process actions, and a table with process attachments.
Go to the Controller tab and replace its content with the following code:
ContractEdit.java.
package com.company.demo.gui.contract; import com.haulmont.bpm.entity.ProcDefinition; import com.haulmont.bpm.entity.ProcInstance; import com.haulmont.bpm.gui.action.ProcAction; import com.haulmont.bpm.gui.procactions.ProcActionsFrame; import com.haulmont.cuba.core.global.*; import com.haulmont.cuba.gui.WindowManager; import com.haulmont.cuba.gui.app.core.file.FileDownloadHelper; import com.haulmont.cuba.gui.components.*; import com.company.demo.entity.Contract; import com.haulmont.cuba.gui.components.actions.BaseAction; import com.haulmont.cuba.gui.data.DsContext; import com.haulmont.cuba.gui.xml.layout.ComponentsFactory; import javax.annotation.Nullable; import javax.inject.Inject; import java.util.Map; public class ContractEdit extends AbstractEditor<Contract> { private static final String PROCESS_CODE = "contractApproval"; @Inject private DataManager dataManager; private ProcDefinition procDefinition; private ProcInstance procInstance; @Inject private ProcActionsFrame procActionsFrame; @Inject private GroupBoxLayout procActionsBox; @Inject private ComponentsFactory componentsFactory; @Inject private Table attachmentsTable; @Inject private Metadata metadata; @Override protected void postInit() { super.postInit(); procDefinition = findProcDefinition(); if (procDefinition != null) { procInstance = findProcInstance(); if (procInstance == null) { procInstance = metadata.create(ProcInstance.class); procInstance.setProcDefinition(procDefinition); procInstance.setEntityName("demo$Contract"); procInstance.setEntityId(getItem().getId()); } initProcActionsFrame(); } getDsContext().addListener(new DsContext.CommitListenerAdapter() { @Override public void beforeCommit(CommitContext context) { if (procInstance != null && PersistenceHelper.isNew(procInstance)) { context.getCommitInstances().add(procInstance); } } }); FileDownloadHelper.initGeneratedColumn(attachmentsTable, "file"); } private void initProcActionsFrame() { procActionsFrame.setBeforeStartProcessPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { if (PersistenceHelper.isNew(getItem())) { showNotification(getMessage("saveContract"), NotificationType.WARNING); return false; } return true; } }); procActionsFrame.setAfterStartProcessListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("processStarted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setBeforeCompleteTaskPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { return commit(); } }); procActionsFrame.setAfterCompleteTaskListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("taskCompleted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setCancelProcessEnabled(false); procActionsFrame.init(procInstance); } @Nullable private ProcDefinition findProcDefinition() { LoadContext ctx = new LoadContext(ProcDefinition.class); ctx.setQueryString("select pd from bpm$ProcDefinition pd where pd.code = :code") .setParameter("code", PROCESS_CODE); return dataManager.load(ctx); } @Nullable private ProcInstance findProcInstance() { LoadContext ctx = new LoadContext(ProcInstance.class).setView("procInstance-start"); ctx.setQueryString("select pi from bpm$ProcInstance pi where pi.procDefinition.id = :procDefinition and pi.entityId = :entityId") .setParameter("procDefinition", procDefinition) .setParameter("entityId", getItem()); return dataManager.load(ctx); } }
Press OK to save the changes.
Let’s examine the controller code in details.
To start the process, we have to create an instance of the process (ProcInstance object), link it to a process definition (ProcDefinition object), and perform start. The process instance can be started both without a link to any project entity and with this link. In our case a link to the contract is mandatory.
In the beginning of the postInit()
method an instance of contract approval process is searched by findProcDefinition()
method, which searches for a process definition with the contractApproval
code. Next, there is a check whether a ProcInstance object linked with the contract exists in the database (findProcInstance()
method). If the process instance object doesn’t exist, then it is created, the relation to ProcDefinition is set, and a linked entity name and identifier are filled.
if (procInstance == null) { procInstance = metadata.create(ProcInstance.class); procInstance.setProcDefinition(procDefinition); procInstance.setEntityName("demo$Contract"); procInstance.setEntityId(getItem().getId()); }
CommitListener
adds the created ProcInstance object to the list of entities
that will be sent to the middleware for be committed.
getDsContext().addListener(new DsContext.CommitListenerAdapter() { @Override public void beforeCommit(CommitContext context) { if (procInstance != null && PersistenceHelper.isNew(procInstance)) { context.getCommitInstances().add(procInstance); } } });
Next, go to the initProcActionsFrame()
method.
A ProcActionsFrame
is a standard frame displaying the buttons with available process actions. ProcActionsFrame
is linked with a ProcInstance
instance. If the process is not started yet, the frame will display the start process button. If the process is started and there are active tasks for the current user, then the frame will display buttons for task completion according to the task outcomes defined in the process model. For the detailed information about ProcActionsFrame see Section 6.1, “ProcActionsFrame”.
private void initProcActionsFrame() { procActionsFrame.setBeforeStartProcessPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { if (PersistenceHelper.isNew(getItem())) { showNotification(getMessage("saveContract"), NotificationType.WARNING); return false; } return true; } }); procActionsFrame.setAfterStartProcessListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("processStarted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setBeforeCompleteTaskPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { return commit(); } }); procActionsFrame.setAfterCompleteTaskListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("taskCompleted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setCancelProcessEnabled(false); procActionsFrame.init(procInstance); }
The procActionsFrame.setBeforeStartProcessPredicate()
method adds the check that is performed before the process start. If the contract is not saved yet, the process will not start and the warning message will be shown.
The procActionsFrame.setBeforeCompleteTaskPredicate()
method invokes an editor commit and allows to complete a process action only if the editor commit was successful.
setAfterProcessStartListener
and setAfterCompleteTaskListener
methods will be invoked after corresponding events. They will show the notification and close the contract editor.
After all necessary listeners and predicates are set up, the initialization frame is invoked.
procActionsFrame.init(procInstance);
UI components are created during the frame initialization.
In Studio, open the messages.properties
file from a package with contract screens. Replace its content with the following text:
messages.properties browseCaption = Contract browser editCaption = Contract editor attachments = Attachments process = Contract approval saveContract = Save the contract before starting a process processStarted = Process started taskCompleted = Task completed
Hot deploy mechanism is enabled in Studio by default, so all changes in screens should be already sent to the application server. If Hot Deploy is disabled then restart the server in Studio with the Run → Restart application server command.
We have to create test users for the process demonstration. Open the Administration → Users screen and create 3 users:
norman
, First name: Tommy
, Last name: Norman
, Full name: Tommy Norman
roberts
, First name: Casey
, Last name: Roberts
, Full name: Casey Roberts
pierce
, First name: Walter
, Last name: Pierce
, Full name: Walter Pierce
Standard form
with attributes procActorsVisible=true
and attachmentsVisible=true
for the Start event node. That’s why now we see the form with the process actors and attachments tables.norman
and the 2 managers are pierce
and roberts
.Log in as norman
.
When a process reaches the User task node, a ProcTask object is created. This object is linked to the particular process actor. The BPM subsystem has a screen for displaying the uncompleted tasks for the current user. Open it: BPM → Process tasks.
Wee see that the user norman
has one uncompleted task Validation
of the Contract approval
process. Select it and click the Open process instance button. The following screen will appear:
It displays the information about the process start time, initiator, attachments list, actors list, process instance tasks list. The screen also allows you to open the linked entity editor and execute a process action. We will complete a process task in another way - using procActionsFrame
that we added earlier to the contract editor.
Close the Process Instance Edit screen and open the contract instance.
The current user (norman
) has an uncompleted task (ProcTask), so the procActionsFrame
displays available process actions. When we were defining the Validation
UserTask node, we set 2 possible outcomes: Valid
and Not valid
. That’s why 2 buttons are added to the procActionsFrame
.
Click the Valid button. In the opened window enter the following comment:
Click OK.
After the successful validation the contract should go to managers parallel approval.
Log in as the pierce
user.
Open the current task list BPM → Process tasks. There is the Approval
task there.
Open the Process Instance Editor.
Pay attention to the Tasks table. The previous task Validation
has been completed with the Valid
outcome, and 2 new Approval
tasks were created for managers pierce
and roberts
.
Approve the contract pressing the Approve button.
Then log in as roberts
. Open the contract from the list Application → Contracts.
User roberts
has an uncompleted task, so the procActionsFrame
displays Approve and Reject actions. Click the Reject button.
When we were defining the Reject
outcome in the model designer, we set a commentRequired
form parameter to true
, therefore you see that the comment is required in the task complete form. Enter the comment and press OK.
One of the managers has rejected the contract, so the Not approved
state should be assigned to the contract. Let’s check it. Open the contract.
The approval process is completed with the Not approved
state.
Attributes which names start with *act prefix are references to the Activiti identifiers.
ProcModel - the process model. Model attributes:
ProcDefinition - the process definition. Entity attributes:
ProcRole - the process role. Objects of this type are created automatically on process deployment. ProcRole defines a process actor type. Entity attributes:
ProcInstance - the process instance. ProcInstance can be started both with a link to a project entity and without a link. For example, the contract approval process instance can be linked with a contract entity. Entity attributes:
ProcActor - the process participant. The entity defines an executor with a particular role for a process instance. Entity attributes:
ProcTask - the process task. Objects of this type are automatically created when a process reaches the User task node. Entity attributes:
id
attribute of the UserTask element. It is used for building a name of a variable that stores the task result ([task_id]_result
). See Section 4.6, “Transitions Depending on Task Outcomes”.ProcAttachment - the process attachment. Entity attributes:
ProcAttachmentType - the attachment type. Entity attributes:
The BPM subsystem employs the Activiti Engine for business processes execution. The modified editor from Activiti Explorer is used to model processes using BPMN 2.0 notation. In addition to Activiti framework capabilities, the BPM subsystem provides additional functionality which is described in this section. A description of the Activiti framework is out of this manual scope and can be found at http://www.activiti.org/userguide.
The BpmActivitiListener
event listener is automatically added to the process when a model is created. BpmActivitiListener
implements the ActivitiEventListener
interface (see http://www.activiti.org/userguide/#eventDispatcher). The listener is responsible for creating and modifying BPM entities when some process events occur (e.g. a user task entering, process cancelation, task completion, etc). This is the listener that creates ProcTasks objects and sets the endDate
value for a ProcInstance.
Process roles define process actor types, e.g. operator or manager. To open the process roles editor select the Process roles property in the model properties panel. Information about the roles will be written to the process XML (extensionElements
section of the process
element) during the model deployment.
Process roles definition in a process XML.
<process id="testProcess" name="Test process"> <extensionElements> <cuba:procRoles> <cuba:procRole name="Manager" code="manager"/> <cuba:procRole name="Operator" code="operator"/> </cuba:procRoles> </extensionElements> </process>
To define a form that will be displayed on the process start, use the Start form property of the Start event node. Read mode about forms at the Section 6.2, “Process forms” section.
Process start form definition in a process XML.
<startEvent id="startEvent"> <extensionElements> <cuba:form name="standardProcForm"> <cuba:param name="procActorsVisible" value="true"></cuba:param> </cuba:form> </extensionElements> </startEvent>
To define the task assignee, select one of the process roles in the Process role property of the User task node. When a process reaches the User task, process actors with the given role will be found among all the process actors, and the task will be assigned to them.
Process role form a task in a process XML.
<userTask id="managerApproval" name="Manager approval"> <extensionElements> <cuba:procRole>manager</cuba:procRole> </extensionElements> </process>
If you want the task to be assigned to multiple users, then set Parallel
or Sequential
value to the Multi-instance type property of the User task node.
Set the Claim allowed property if you don’t want the task to be immediately assigned to the particular user, but to appear in the list of available tasks for the group of users. Then, one of the candidates will be able to claim the task. Task candidates are defined amongst process actors with the corresponding Process role property.
A task without an explicit executor in a process XML.
<userTask id="managerApproval" name="Manager approval"> <extensionElements> <cuba:claimAllowed>true</cuba:claimAllowed> </extensionElements> </process>
Commonly, a user is expected to make a decision on the task, e.g. to approve or to reject the contract. The next route through the process depends on this decision. The Task outcomes property of the User task node is used to define the list of outcomes. The name and from, that should be displayed when an outcome is selected, can be defined for each outcome spearately. The parameters that should be passed to the form can be defined as well (see Section 6.2, “Process forms”).
Task outcomes in XML.
<userTask id="managerApproval" name="Manager approval"> <extensionElements> <cuba:outcomes> <cuba:outcome name="approve"> <cuba:form name="standardProcessForm"> <cuba:param name="commentRequired">true</cuba:param> <cuba:param name="attachmentsVisible">true</cuba:param> </cuba:form> </cuba:outcome> <cuba:outcome name="reject"> <cuba:form name="someOtherProcessForm"> </cuba:form> </cuba:outcome> </cuba:outcomes> </extensionElements> </process>
Unlike jBPM, BPMN 2.0 notation doesn’t provide the way to define multiple outcomes for a User task. To make a process to be continued on a required flow node, the Exclusive gateway is used. Its outgoing flows have conditions that operate with the results of the preceding task. When a user completes the task, its result is written to the process variable with the name generated as [taskId]_result
. The variable type is ProcTaskResult
.
Methods of ProcTaskResult
class:
int count(String outcomeName)
- returns the number of users who completed the task with the given outcome.boolean exists(String outcomeName)
- returns true
if there are users who completed the task with a given outcome.The resultant object of the task completion is used in the Flow condition expression of gateway outgoing flows.
Example:
Let’s suppose that the approval
task was assigned to multiple uses in parallel. There are 2 outcomes defined for the task: approve
and reject
. When all users have completed the task, the process goes to the exclusive gateway. We want to implement the following behavior: if anyone choses the reject
option then go to the Rejected
flow; if everyone approved the task then go to the Approved
flow.
Defining a Condition in a Flow Outcome Field
The simplest way to define the flow condition is to select the name of the previous task outcome in the Flow outcome property of the flow node. The flow will be activated if there was at least one task completion with the selected outcome.
Defining a Complex Condition for the Flow Node
If you need to implement more complex condition for the outcome, you can define it in the Flow condition field. For example, "More than 5 users selected the Reject option" condition looks like following:
${approval_result.count('reject') > 5}
The Script task node is used to evaluate a script. The system analyzes the content of the Script property value. If the value is a valid file path and the file exists, then the script from the file will be executed, otherwise the Script field will be evaluated.
Note that you are allowed to use persistence
and metadata
objects for scripting.
The Service task node is used to invoke a service method. Activiti engine is integrated with the Spring framework, so you can access middleware beans by their names. To invoke a managed bean method put the following expression to the Expression field:
${beanName.methodName(processVarName, 'someStringParam')}
To complete a task after a certain time interval, you should:
PT15M
is an expression for 15 minutes interval.Defining an outcome for the timer.
<boundaryEvent id="managerApprovalTimer" cancelActivity="true" attachedToRef="managerApproval"> <extensionElements> <cuba:outcome>approve</cuba:outcome> </extensionElements> </boundaryEvent>
By default, the Job executor which processes timers is disabled. To enable it, set an application property bpm.activiti.asyncExecutorEnabled = true
.
A process may contain localized messages that are used to display task or outcomes in the user interface.
To open the localized messages editor, select the Localization property in the model properties panel.
To localize the task name, create a record with the task id as a key.
To localize the task outcome name, create a record with an expression like TASK_ID.OUTCOME_NAME
as a key.
To localize the process role name, create a record with a role code as a key.
Localizaed messages in XML.
<process id="testProcess" name="Test process"> <extensionElements> <cuba:localizations> <cuba:localization lang="en"> <cuba:msg key="key1" value="value1"/> <cuba:msg key="key2" value="value2"/> </cuba:localization> <cuba:localization lang="ru"> <cuba:msg key="key1" value="value1"/> <cuba:msg key="key2" value="value2"/> </cuba:localization> </cuba:localizations> </extensionElements> </process>
The chapter contains only general description of the services. Detailed service methods description is available in Java classes documentation.
It serves to work with process definitions. The service is used to:
To access the service functionality on middleware layer use the ProcessRepositoryManager
bean.
It serves to work with process instances. The service methods allows to:
To access the service functionality on middleware layer use the ProcessRuntimeManager
bean.
The service is used to provide information about:
To access the service functionality on middleware layer use the ProcessFormManager
bean.
The service is used to access the localized messages which are defined in the process.
To access the service functionality on middleware layer use the ProcessMessagesManager
bean.
The ProcActionsFrame
can be embedded to application screens. If the frame is linked with the process instance, the following components will be automatically displayed:
The predicative listener can be assigned to each of the process actions in order to check if the action can be performed (e.g. predicate commits an editor and if the commit failed, a process action is not performed). The post-action listener can also be defined (e.g. listener will close the editor and show the notification).
The sequence of steps to initialize the frame in the screen controller code:
init()
method with the procInstance
argumentWhen you declare user task outcomes or the start event node in the model editor it is possible to set a form that will be displayed to the user. The form should implement the ProcForm
interface.
The methods of the ProcForm
interface:
String getComment()
- returns the value that will be written to the comment
field of the ProcTask object or to the startComment
field of the ProcInstance if the form is displayed on a process start.Map<String, Object> getFormResult()
- returns a list of objects that will be added to process variables after the form commit.A list of forms available in a process model designer is built according to the configuration files that are defined in a bpm.formsConfig
application property.
bpm-forms.xml example.
<?xml version="1.0" encoding="UTF-8"?> <forms xmlns="http://schemas.haulmont.com/cuba/5.5/bpm-forms.xsd"> <form name="standardProcForm" default="true"> <param name="commentRequired" value="true"/> <param name="procActorsVisible" value="true"/> <param name="attachmentsVisible" value="true"/> </form> <form name="otherForm"> <param name="someParam" value="hello"/> </form> </forms>
The above also describes available form parameters with their names and default values.
A form with a default="true"
attribute will be used as the default form in the model.