Activiti 7 Tutorial
Table of Contents
-
- Activiti Environment Setup
-
- IDE Plugin Installation
-
- Database Configuration
-
- Creating a Maven Project
-
- Activiti Fundamentals
-
- Process Definition Deployment
-
- Process Execution, Task Query, and Task Completion
-
- ZIP-Based Deployment
-
- Process Query and Deletion
-
- Process Resource Download
-
- Viewing Historical Data
-
- Task Suspension and Activation
-
- Using UEL Expressions for Assignee Assignment
-
- Using Task Listeners for Assignee Assignment
-
- Conditional Branching
-
- Group Tasks
-
- Exclusive Gateway
-
- Parallel Gateway
-
- Inclusive Gateway
- Activiti Environment Setup
2. IDE Plugin Installation
BPMN diagrams are represented as XML files (BPMN files can be viewed in any text editor). To install the Activiti plugin in IntelliJ IDEA:
- Navigate to File | Settings | Plugins
- Search for actiBPM (Activiti BPMN visualizer)
- Install and restart IDEA
3. Database Support
Activiti supports various databases including MySQL, PostgreSQL, Oracle, and more. For MySQL:
- Create a new database:
CREATE DATABASE activiti DEFAULT CHARACTER SET utf8; - Ensure the database user has appropriate permissions
- Configure the connection in the Activiti configuration file
4. Creating a Maven Project
Add the following dependencies to your pom.xml:
<properties>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<activiti.version>7.0.0.Beta1</activiti.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
Create log4j.properties in src/main/resources:
log4j.rootCategory=debug, CONSOLE, LOGFILE
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m%n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m%n
Create activiti.cfg.xml in src/main/resources:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///activiti"/>
<property name="jdbcUsername" value="root"/>
<property name="jdbcPassword" value="password"/>
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
Test database table creation:
public class ActivitiInitializationTest {
@Test
public void initializeDatabase() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println("Process Engine: " + processEngine);
}
}
Activiti Database Tables Overview
| Category | Table Name | Description |
|---|---|---|
| General Data | ||
| ACT_GE_BYTEARRAY | General process definitions and resources | |
| ACT_GE_PROPERTY | System-related properties | |
| Process History | ||
| ACT_HI_ACTINST | Historical process instances | |
| ACT_HI_ATTACHMENT | Historical process attachments | |
| ACT_HI_COMMENT | Historical comments | |
| ACT_HI_DETAIL | Historical process run details | |
| ACT_HI_IDENTITYLINK | Historical user relationships | |
| ACT_HI_PROCINST | Historical process instances | |
| ACT_HI_TASKINST | Historical task instances | |
| ACT_HI_VARINST | Historical process variables | |
| Process Definition | ||
| ACT_RE_DEPLOYMENT | Deployment information | |
| ACT_RE_MODEL | Model information | |
| ACT_RE_PROCDEF | Deployed process definitions | |
| Runtime Data | ||
| ACT_RU_EVENT_SUBSCR | Runtime events | |
| ACT_RU_EXECUTION | Runtime process executions | |
| ACT_RU_IDENTITYLINK | Runtime user relationships | |
| ACT_RU_JOB | Runtime jobs | |
| ACT_RU_TASK | Runtime tasks | |
| ACT_RU_VARIABLE | Runtime variables |
Core Activiti Services
| Service | Purpose |
|---|---|
| RepositoryService | Manages process definitions and resources |
| RuntimeService | Manages process execution |
| TaskService | Manages tasks |
| HistoryService | Manages historical data |
| ManagementService | Engine management operations |
- Activiti Fundamentals
BPMN Process Symbols
- Events
- Start Event
- Intermediate Event
- End Event
- Activities
- User Task
- Service Task
- Subprocess
- Gateways
- Exclusive Gateway (X)
- Parallel Gateway (+)
- Inclusive Gateway
- Event Gateway
- Flows
- Sequence Flow
- Message Flow
- Association
- Data Association
Using the Process Designer
- Right-click on project → New → New Activiti 6.x BPMN 2.0 File
- Right-click on XML editor → View BPMN (Activiti) Diagram
- Right-click on canvas:
- Connection: Create flows between elements
- Event: Add events (start, end, intermediate)
- Task: Add task types
- Gateway: Add gateways
- Container: Add containers
- Boundary Event: Add boundary events
- Intermediate Event: Add intermediate events
- Process Definition Deployment
public class ProcessDeploymentExample {
@Test
public void deployProcessDefinition() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("Business Trip Request")
.addClasspathResource("bpmn/travel-request.bpmn20.xml")
.addClasspathResource("bpmn/travel-request.png")
.deploy();
System.out.println("Deployment ID: " + deployment.getId());
System.out.println("Deployment Name: " + deployment.getName());
}
}
- Process Execution, Task Query, and Task Completion
public class ProcessExecutionExample {
@Test
public void startProcessInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService.startProcessInstanceByKey("travelRequest");
System.out.println("Process Definition ID: " + instance.getProcessDefinitionId());
System.out.println("Process Instance ID: " + instance.getId());
System.out.println("Activity ID: " + instance.getActivityId());
}
@Test
public void queryTasks() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService
.createTaskQuery()
.processDefinitionKey("travelRequest")
.taskAssignee("alice")
.list();
for (Task task : tasks) {
System.out.println("Process Instance ID: " + task.getProcessInstanceId());
System.out.println("Task ID: " + task.getId());
System.out.println("Assignee: " + task.getAssignee());
System.out.println("Task Name: " + task.getName());
}
}
@Test
public void completeTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService
.createTaskQuery()
.processDefinitionKey("travelRequest")
.taskAssignee("bob")
.singleResult();
if (task != null) {
System.out.println("Task ID: " + task.getId());
System.out.println("Assignee: " + task.getAssignee());
taskService.complete(task.getId());
}
}
}
- ZIP-Based Deployment
public class ZipDeploymentExample {
@Test
public void deployFromZip() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("bpmn/process-bundle.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deployment = repositoryService
.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("Deployment ID: " + deployment.getId());
System.out.println("Deployment Name: " + deployment.getName());
}
}
- Process Query and Deletion
public class ProcessManagementExample {
@Test
public void queryProcessDefinitions() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
List<ProcessDefinition> definitions = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey("myProcess")
.orderByProcessDefinitionVersion()
.desc()
.list();
for (ProcessDefinition definition : definitions) {
System.out.println("Definition ID: " + definition.getId());
System.out.println("Definition Name: " + definition.getName());
System.out.println("Definition Key: " + definition.getKey());
System.out.println("Version: " + definition.getVersion());
System.out.println("Deployment ID: " + definition.getDeploymentId());
}
}
@Test
public void deleteDeployment() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
String deploymentId = "1001";
repositoryService.deleteDeployment(deploymentId, true);
}
}
- Process Resource Download
public class ResourceDownloadExample {
@Test
public void downloadProcessResources() throws IOException {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey("myProcess")
.singleResult();
String deploymentId = processDefinition.getDeploymentId();
String diagramName = processDefinition.getDiagramResourceName();
String bpmnName = processDefinition.getResourceName();
InputStream diagramStream = repositoryService.getResourceAsStream(deploymentId, diagramName);
InputStream bpmnStream = repositoryService.getResourceAsStream(deploymentId, bpmnName);
File diagramFile = new File("output/diagram.png");
File bpmnFile = new File("output/process.bpmn20.xml");
FileOutputStream diagramOut = new FileOutputStream(diagramFile);
FileOutputStream bpmnOut = new FileOutputStream(bpmnFile);
IOUtils.copy(diagramStream, diagramOut);
IOUtils.copy(bpmnStream, bpmnOut);
diagramOut.close();
bpmnOut.close();
diagramStream.close();
bpmnStream.close();
}
}
- Viewing Historical Data
public class HistoryQueryExample {
@Test
public void queryHistoricalData() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> activities = historyService
.createHistoricActivityInstanceQuery()
.processDefinitionId("myProcess:1:10004")
.orderByHistoricActivityInstanceStartTime()
.asc()
.list();
for (HistoricActivityInstance activity : activities) {
System.out.println("Activity ID: " + activity.getActivityId());
System.out.println("Activity Name: " + activity.getActivityName());
System.out.println("Process Definition ID: " + activity.getProcessDefinitionId());
System.out.println("Process Instance ID: " + activity.getProcessInstanceId());
System.out.println("=========================");
}
}
}
- Task Suspension and Activation
public class SuspensionExample {
@Test
public void addBusinessKey() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("travelRequest", "ORDER-001");
System.out.println("Business Key: " + instance.getBusinessKey());
}
@Test
public void suspendProcessDefinition() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition definition = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey("travelRequest")
.singleResult();
boolean isSuspended = definition.isSuspended();
String definitionId = definition.getId();
if (isSuspended) {
repositoryService.activateProcessDefinitionById(definitionId, true, null);
System.out.println("Process definition activated: " + definitionId);
} else {
repositoryService.suspendProcessDefinitionById(definitionId, true, null);
System.out.println("Process definition suspended: " + definitionId);
}
}
@Test
public void suspendProcessInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService
.createProcessInstanceQuery()
.processInstanceId("15001")
.singleResult();
boolean isSuspended = instance.isSuspended();
String instanceId = instance.getId();
if (isSuspended) {
runtimeService.activateProcessInstanceById(instanceId);
System.out.println("Process instance activated: " + instanceId);
} else {
runtimeService.suspendProcessInstanceById(instanceId);
System.out.println("Process instance suspended: " + instanceId);
}
}
}
- Using UEL Expressions for Assignee Assignment
BPMN process with UEL expressions:
<process id="travelRequestUel" name="Travel Request - UEL" isExecutable="true">
<startEvent id="startEvent"/>
<userTask id="createTask" name="Create Request"
activiti:assignee="${initiator}"/>
<userTask id="managerApproval" name="Manager Approval"
activiti:assignee="${manager}"/>
<userTask id="directorApproval" name="Director Approval"
activiti:assignee="${director}"/>
<userTask id="financeApproval" name="Finance Approval"
activiti:assignee="${finance}"/>
<endEvent id="endEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="createTask"/>
<sequenceFlow sourceRef="createTask" targetRef="managerApproval"/>
<sequenceFlow sourceRef="managerApproval" targetRef="directorApproval"/>
<sequenceFlow sourceRef="directorApproval" targetRef="financeApproval"/>
<sequenceFlow sourceRef="financeApproval" targetRef="endEvent"/>
</process>
public class UelAssignmentExample {
@Test
public void deployWithUel() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("Travel Request - UEL")
.addClasspathResource("bpmn/travel-uel.bpmn20.xml")
.deploy();
System.out.println("Deployment ID: " + deployment.getId());
}
@Test
public void startWithUelVariables() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> variables = new HashMap<>();
variables.put("initiator", "Alice");
variables.put("manager", "Bob Manager");
variables.put("director", "Carol Director");
variables.put("finance", "Dave Finance");
runtimeService.startProcessInstanceByKey("travelRequestUel", variables);
}
}
- Using Task Listeners for Assignee Assigment
BPMN process with task listener:
<process id="listenerProcess" name="Process with Listener" isExecutable="true">
<startEvent id="start"/>
<userTask id="createRequest" name="Create Request">
<extensionElements>
<activiti:taskListener event="all"
class="com.example.listener.CustomTaskListener"/>
</extensionElements>
</userTask>
<userTask id="reviewRequest" name="Review Request"/>
<endEvent id="end"/>
<sequenceFlow sourceRef="start" targetRef="createRequest"/>
<sequenceFlow sourceRef="createRequest" targetRef="reviewRequest"/>
<sequenceFlow sourceRef="reviewRequest" targetRef="end"/>
</process>
public class CustomTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
if ("Create Request".equals(delegateTask.getName())
&& "create".equals(delegateTask.getEventName())) {
delegateTask.setAssignee("SystemUser");
}
}
}
public class ListenerExample {
@Test
public void deployWithListener() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("Process with Listener")
.addClasspathResource("bpmn/listener-process.bpmn20.xml")
.deploy();
System.out.println("Deployment ID: " + deployment.getId());
}
@Test
public void startWithListener() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey("listenerProcess");
}
}
- Conditional Branching
Process with conditional flows:
<process id="travelWithCondition" isExecutable="true">
<startEvent id="start"/>
<userTask id="createTask" name="Create Request"
activiti:assignee="${assignee0}"/>
<userTask id="deptApproval" name="Department Approval"
activiti:assignee="${assignee1}"/>
<userTask id="directorApproval" name="Director Approval"
activiti:assignee="${assignee2}"/>
<userTask id="financeApproval" name="Finance Approval"
activiti:assignee="${assignee3}"/>
<endEvent id="end"/>
<sequenceFlow sourceRef="start" targetRef="createTask"/>
<sequenceFlow sourceRef="createTask" targetRef="deptApproval"/>
<sequenceFlow sourceRef="deptApproval" targetRef="directorApproval">
<conditionExpression><![CDATA[${travelRequest.days < 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="deptApproval" targetRef="financeApproval">
<conditionExpression><![CDATA[${travelRequest.days >= 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="directorApproval" targetRef="financeApproval"/>
<sequenceFlow sourceRef="financeApproval" targetRef="end"/>
</process>
public class ConditionalFlowExample {
@Test
public void deployConditionalProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("Conditional Process")
.addClasspathResource("bpmn/conditional-process.bpmn20.xml")
.deploy();
}
@Test
public void startWithVariables() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> variables = new HashMap<>();
variables.put("assignee0", "User1");
variables.put("assignee1", "Manager1");
variables.put("assignee2", "Director1");
variables.put("assignee3", "Finance1");
runtimeService.startProcessInstanceByKey("travelWithCondition", variables);
}
@Test
public void completeWithCondition() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
TravelRequest request = new TravelRequest();
request.setDays(2);
Map<String, Object> variables = new HashMap<>();
variables.put("travelRequest", request);
Task task = taskService
.createTaskQuery()
.processDefinitionKey("travelWithCondition")
.taskAssignee("Manager1")
.singleResult();
if (task != null) {
taskService.complete(task.getId(), variables);
}
}
}
- Group Tasks
Process with candidate users:
<process id="groupTaskProcess" name="Group Task Process" isExecutable="true">
<startEvent id="start"/>
<userTask id="createTask" name="Create Request"
activiti:assignee="alice"/>
<userTask id="groupApproval" name="Group Approval"
activiti:candidateUsers="user1,user2"/>
<userTask id="managerApproval" name="Manager Approval"
activiti:assignee="bob"/>
<userTask id="financeApproval" name="Finance Approval"
activiti:assignee="charlie"/>
<endEvent id="end"/>
<sequenceFlow sourceRef="start" targetRef="createTask"/>
<sequenceFlow sourceRef="createTask" targetRef="groupApproval"/>
<sequenceFlow sourceRef="groupApproval" targetRef="managerApproval"/>
<sequenceFlow sourceRef="managerApproval" targetRef="financeApproval"/>
<sequenceFlow sourceRef="financeApproval" targetRef="end"/>
</process>
public class GroupTaskExample {
@Test
public void deployGroupTaskProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("Group Task Process")
.addClasspathResource("bpmn/group-task.bpmn20.xml")
.deploy();
}
@Test
public void startGroupProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey("groupTaskProcess");
}
@Test
public void queryGroupTasks() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService
.createTaskQuery()
.processDefinitionKey("groupTaskProcess")
.taskCandidateUser("user2")
.list();
for (Task task : tasks) {
System.out.println("Task ID: " + task.getId());
System.out.println("Process Instance ID: " + task.getProcessInstanceId());
}
}
@Test
public void claimGroupTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String taskId = "40001";
String candidateUser = "user1";
Task task = taskService
.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(candidateUser)
.singleResult();
if (task != null) {
taskService.claim(taskId, candidateUser);
}
}
@Test
public void returnToGroup() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String taskId = "40001";
taskService.setAssignee(taskId, null);
}
@Test
public void transferToUser() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String taskId = "40001";
String newAssignee = "user2";
taskService.setAssignee(taskId, newAssignee);
}
}
- Exclusive Gateway
Process with exclusive gateway for conditional routing:
<process id="exclusiveGatewayProcess" name="Exclusive Gateway Process"
isExecutable="true">
<startEvent id="start"/>
<userTask id="fillForm" name="Fill Form"
activiti:assignee="employee"/>
<userTask id="deptReview" name="Department Review"
activiti:assignee="deptManager"/>
<userTask id="directorReview" name="Director Review"
activiti:assignee="director"/>
<userTask id="financeReview" name="Finance Review"
activiti:assignee="finance"/>
<endEvent id="end"/>
<exclusiveGateway id="decisionGateway" name="Days Decision"/>
<sequenceFlow sourceRef="start" targetRef="fillForm"/>
<sequenceFlow sourceRef="fillForm" targetRef="deptReview"/>
<sequenceFlow sourceRef="deptReview" targetRef="decisionGateway"/>
<sequenceFlow sourceRef="decisionGateway" targetRef="directorReview">
<conditionExpression><![CDATA[${request.days >= 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decisionGateway" targetRef="financeReview">
<conditionExpression><![CDATA[${request.days < 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="directorReview" targetRef="financeReview"/>
<sequenceFlow sourceRef="financeReview" targetRef="end"/>
</process>
public class ExclusiveGatewayExample {
@Test
public void deployExclusiveGateway() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService
.createDeployment()
.addClasspathResource("bpmn/exclusive-gateway.bpmn20.xml")
.name("Exclusive Gateway Process")
.deploy();
}
@Test
public void startWithCondition() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
BusinessRequest request = new BusinessRequest();
request.setDays(2);
Map<String, Object> variables = new HashMap<>();
variables.put("request", request);
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("exclusiveGatewayProcess", variables);
System.out.println("Process Instance ID: " + instance.getId());
}
}
- Parallel Gateway
Process with parallel gateway for concurrent execution:
<process id="parallelGatewayProcess" name="Parallel Gateway Process"
isExecutable="true">
<startEvent id="start"/>
<userTask id="createTask" name="Create Request"
activiti:assignee="employee"/>
<parallelGateway id="splitGateway" name="Parallel Split"/>
<userTask id="techReview" name="Technical Review"
activiti:assignee="techLead"/>
<userTask id="projectReview" name="Project Review"
activiti:assignee="projectMgr"/>
<parallelGateway id="joinGateway" name="Parallel Join"/>
<exclusiveGateway id="decisionGate" name="Decision"/>
<userTask id="finalApproval" name="Final Approval"
activiti:assignee="executive"/>
<endEvent id="end"/>
<sequenceFlow sourceRef="start" targetRef="createTask"/>
<sequenceFlow sourceRef="createTask" targetRef="splitGateway"/>
<sequenceFlow sourceRef="splitGateway" targetRef="techReview">
<conditionExpression><![CDATA[${request.days >= 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="splitGateway" targetRef="projectReview">
<conditionExpression><![CDATA[${request.days < 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="techReview" targetRef="joinGateway"/>
<sequenceFlow sourceRef="projectReview" targetRef="joinGateway"/>
<sequenceFlow sourceRef="joinGateway" targetRef="decisionGate"/>
<sequenceFlow sourceRef="decisionGate" targetRef="finalApproval">
<conditionExpression><![CDATA[${request.days >= 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decisionGate" targetRef="end">
<conditionExpression><![CDATA[${request.days < 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="finalApproval" targetRef="end"/>
</process>
public class ParallelGatewayExample {
@Test
public void deployParallelGateway() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService
.createDeployment()
.addClasspathResource("bpmn/parallel-gateway.bpmn20.xml")
.name("Parallel Gateway Process")
.deploy();
}
@Test
public void startParallelProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
BusinessRequest request = new BusinessRequest();
request.setDays(4);
Map<String, Object> variables = new HashMap<>();
variables.put("request", request);
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("parallelGatewayProcess", variables);
System.out.println("Process Definition ID: " + instance.getProcessDefinitionId());
System.out.println("Process Instance ID: " + instance.getId());
}
}
- Inclusive Gateway
Process with inclusive gateway for complex conditional branching:
<process id="inclusiveGatewayProcess" name="Inclusive Gateway Process"
isExecutable="true">
<startEvent id="start"/>
<userTask id="submitRequest" name="Submit Request"
activiti:assignee="employee"/>
<inclusiveGateway id="splitInclusive"/>
<userTask id="techTask" name="Technical Review"
activiti:assignee="techLead"/>
<userTask id="hrTask" name="HR Review"
activiti:assignee="hrManager"/>
<userTask id="projectTask" name="Project Review"
activiti:assignee="projectMgr"/>
<inclusiveGateway id="joinInclusive"/>
<exclusiveGateway id="finalDecision"/>
<userTask id="executiveTask" name="Executive Approval"
activiti:assignee="executive"/>
<endEvent id="end"/>
<sequenceFlow sourceRef="start" targetRef="submitRequest"/>
<sequenceFlow sourceRef="submitRequest" targetRef="splitInclusive"/>
<sequenceFlow sourceRef="splitInclusive" targetRef="techTask">
<conditionExpression><![CDATA[${request.days < 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="splitInclusive" targetRef="hrTask"/>
<sequenceFlow sourceRef="splitInclusive" targetRef="projectTask">
<conditionExpression><![CDATA[${request.days >= 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="techTask" targetRef="joinInclusive"/>
<sequenceFlow sourceRef="hrTask" targetRef="joinInclusive"/>
<sequenceFlow sourceRef="projectTask" targetRef="joinInclusive"/>
<sequenceFlow sourceRef="joinInclusive" targetRef="finalDecision"/>
<sequenceFlow sourceRef="finalDecision" targetRef="executiveTask">
<conditionExpression><![CDATA[${request.days >= 3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="finalDecision" targetRef="end"/>
<sequenceFlow sourceRef="executiveTask" targetRef="end"/>
</process>
public class InclusiveGatewayExample {
@Test
public void deployInclusiveGateway() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService
.createDeployment()
.addClasspathResource("bpmn/inclusive-gateway.bpmn20.xml")
.name("Inclusive Gateway Process")
.deploy();
}
@Test
public void startInclusiveProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
BusinessRequest request = new BusinessRequest();
request.setDays(4);
Map<String, Object> variables = new HashMap<>();
variables.put("request", request);
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("inclusiveGatewayProcess", variables);
System.out.println("Process Definition ID: " + instance.getProcessDefinitionId());
}
@Test
public void completeTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService
.createTaskQuery()
.processDefinitionKey("inclusiveGatewayProcess")
.taskAssignee("projectMgr")
.singleResult();
if (task != null) {
taskService.complete(task.getId());
}
}
}