BPMN 2.0 is introduced
- BusinessProcess Modeling Notation – BPMN is a standard graphical Notation for BusinessProcess models. This standard is maintained by the Object Management Group (OMG)
- Version 2.0 of the BPMN specification allows precise technical details to be added to BPMN graphics and elements, as well as the implementation syntax of BPMN elements. By using the XML language to specify the executable syntax of business processes, the BPMN specification has evolved into a business process language that can be executed in any BPMN2-compliant process engine while still using powerful graphical annotations
- Simply put,BPMN is a combination of ICONS and labels
Define a process
- Create a new XML file and name it, making sure the file suffix is.bpmn20.xml or.bpmn, otherwise the engine cannot publish
- The BPMN 2.0 root node is a Definitions node. Multiple process definitions can be defined in this element (although it is recommended to include only one process definition per file to simplify maintenance during development)
- An empty process definition looks like this:Note that the definitions element should at least contain declarations for XMLNS and targetNamespace
- TargetNamespace can be any value and is used to classify process instances
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples">
<process id="myProcess" name="My First Process">.</process>
</definitions>
Copy the code
- Optionally add BPMN 2.0 format locations on line:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL
http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd
Copy the code
- The ==process element has two attributes :==
- Id: this property is a must, corresponds to the Activiti ProcessDefinition key attributes of objects. The id can be used to start the process definition process instance, through RuntimeService startProcessInstanceByKey method
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
Copy the code
Note: This is different from the startProcessInstanceById method: this method expects to use the ID automatically generated by the Activiti engine at publish time. This value can be obtained by calling the processDefinition.getid () method. The generated ID is of the form key:version and is limited to 64 characters in length. If a ActivitiException is thrown at startup: The generated ID is too long. You need to limit the length of the key in the process
- Name: This property is optional and corresponds to the Name property of ProcessDefinition. This property is not used by the engine itself, but is used to display easy-to-read names in the user interface
BPMN process example premise
- You have Activiti installed and can run Activiti Demo
- A standalone H2 server was used
- Modify the db. The properties, set the JDBC url = JDBC: h2: TCP: / / localhost/activiti, then start independent server
The target
- Learn Activiti and some basic BPMN 2.0 concepts
- The end result is a simple Java SE program that publishes process definitions and manipulates the process through the Activiti engine API
- Build your own business process Web application using some activiti-related tools
Use cases
- Every month, a financial statement should be presented to the head of the company, and the accounting department is responsible for it
- When the report is complete, one superior needs to approve the document before it can be sent to all leaders
The flow chart
- Graphical BPMN 2.0 markup for a process:
Empty start event (left circle), followed by two user tasks: making monthly statement and validating monthly statement, and finally empty end event (right bold circle)
The XML content
- It’s easy to find in the XML of the business processKey elements of the process:
- The (empty) start event is the entry point to the process
- A user task is an operator related task statement in a process:
- The first task is assigned to the Accountancy group
- The second task is assigned to the Management group
- The event ends when the process reaches null termination
- These elements are connected using wires that have source and target attributes that define the direction of the wire
<definitions id="definitions"
targetNamespace="http://activiti.org/bpmn20"
xmlns:activiti="http://activiti.org/bpmn"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">
<process id="financialReport" name="Monthly financial report reminder process">
<startEvent id="theStart" />
<sequenceFlow id='flow1' sourceRef='theStart' targetRef='writeReportTask' />
<userTask id="writeReportTask" name="Write monthly financial report" >
<documentation>
Write monthly financial report for publication to shareholders.
</documentation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>accountancy</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id='flow2' sourceRef='writeReportTask' targetRef='verifyReportTask' />
<userTask id="verifyReportTask" name="Verify monthly financial report" >
<documentation>Verify monthly financial report composed by the accountancy department. This financial report is going to be sent to all the company shareholders.</documentation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>management</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id='flow3' sourceRef='verifyReportTask' targetRef='theEnd' />
<endEvent id="theEnd" />
</process>
</definitions>
Copy the code
Start a process instance
- Once you have created the process definition for the business process, you can create the process instance
- One process instance corresponds to the creation and approval of a specific monthly financial statement, and all process instances share the same process definition
- To create a process instance using a process definition, first publish the business process:
- Process definitions are saved to persistent datastries and are specifically configured for the Activiti engine. So the business process is deployed and the process definition can still be found after the engine is restarted
- BPMN 2.0 process files are parsed into an in-memory object model that can be manipulated through the Activiti API
- All interactions with the Activiti engine are through Services through the API publishing process below
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("FinancialReportProcess.bpmn20.xml")
.deploy();
Copy the code
- Start a new process instance with the ID we defined in the process definition (corresponding to the process element in the XML file).== Note that the id here for Activiti should be called key==. The id normally used in the process model is key in Activiti: for example, the task ID
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport");
Copy the code
- Create a process instance like this:
- Start with the start event
- Once the event is started, it runs along all outgoing wires to the first task (” Produce monthly report “)
- Activiti saves a task to a database. At this point, the user or group assigned to the task is resolved and saved to the database
- Note that the Activiti engine continues to execute parts of the process unless a wait state, such as a user task, is encountered
- In the wait state, the state of the current process instance is saved to the database. This state cannot be changed until the user decides to complete the task
- At this point, the engine continues execution until the next wait state is reached, or the process ends
- If the intermediate engine restarts or crashes, the process state is safely stored in the database
- Task creation, startProcessInstanceByKey will arrive in the user task will return after the wait state. At this point, the task is assigned to a group, which means that this group is a candidate group to perform the task
- Now put everything together to create a simple Java program:
- Create a Java project and place the Activiti JARS and dependencies in your classpath: these can be found in the Libs directory of the Activiti distribution
- Before invoking the Activiti service, we must construct a ProcessEngine that will give us access to the service
- Here we use the [Run alone] configuration, which uses the database from the demo installation to build ProcessEngine
public static void main(String[] args) {
// Create Activiti process engine
ProcessEngine processEngine = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration()
.buildProcessEngine();
// Get Activiti services
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
// Deploy the process definition
repositoryService.createDeployment()
.addClasspathResource("FinancialReportProcess.bpmn20.xml")
.deploy();
// Start a process instance
runtimeService.startProcessInstanceByKey("financialReport");
}
Copy the code
The task list
- To get the task, use TaskService to add the following logic:
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();
Copy the code
- Note that the incoming user must be a member of the Accountancy group corresponding to the process definition:
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>accountancy</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
Copy the code
- You can also use the group name to obtain relevant results through the task query API. Add the following logic to your code:
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
Copy the code
- Because ProcessEngine is configured to use the same data as demo, you can log in to Activiti Explorer. By default, there is no one in the Accountancy group:
- The login
- Click on the group
- Create a new group
- Click on the user
- Allocate the ingredients to Fozzie
- Log in with fozzie/fozzie
- To start our business Processes, select the Processes page and click Start Processes in the Operations column of Monthly Financial Statement.
- The process executes to the first user task. Since we logged in as Kermit, after starting the process instance, we can see that we have a new task to claim. Select the Tasks page to view the new task. Note that even if the process is started by someone else, the task is still seen as a candidate task by everyone in the accounting group
Get the task
- Now an accountant wants to claim the job
- Once claimed, the user becomes the executor of the task, and the task disappears from the task list of the other members of the accounting group. Claim task code:
taskService.claim(task.getId(), "fozzie");
Copy the code
- Quests go to the person who claims them:
List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
Copy the code
- In the Activiti Explorer UI, clicking the claim button performs the same action. Tasks are moved to the logged-in user’s personal task list. You will also see that the person performing the task has become the user currently logged in:
To complete the task
- Now the accountant can begin the work of the financial statement
- After the report is completed, he can complete the task, which means that all the work required for the task has been done
taskService.complete(task.getId());
Copy the code
- For the Activiti engine:
- An external message is required to allow the process instance to continue execution
- Tasks remove themselves from the runtime
- The process is executed along a single outgoing line, moving to the second task (approve report)
- The same mechanism as the first task is used for the second task, except that the task is assigned to the Management group
- In the demo:
- Tasks are completed by clicking the Finish button in the task list
- Since Fozzie is not an accountant, we will log off from Activiti Explorer
- Then log in using Kermit (manager) and the second task goes to the list of unassigned tasks
The end of the process
- The approval task queries and retrieves as before.
- Completing the second task takes the process to the end event, which terminates the process instance
- The process instance and all associated running data are removed from the database
- To verify this, log in to Activiti Explorer and you can see that there is no more data in the table that holds the process running data:
- You can use historyService to determine if the process has ended:
HistoryService historyService = processEngine.getHistoryService();
HistoricProcessInstance historicProcessInstance =
historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
Copy the code
The source code
- Consider that you might start some process instances in the Activiti Explorer UI, so that it gets multiple tasks instead of one, so the code will always work fine:
public class TenMinuteTutorial {
public static void main(String[] args) {
// Create Activiti process engine
ProcessEngine processEngine = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration()
.buildProcessEngine();
// Get Activiti services
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
// Deploy the process definition
repositoryService.createDeployment()
.addClasspathResource("FinancialReportProcess.bpmn20.xml")
.deploy();
// Start a process instance
String procId = runtimeService.startProcessInstanceByKey("financialReport").getId();
// Get the first task
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
for (Task task : tasks) {
System.out.println("Following task is available for accountancy group: " + task.getName());
// claim it
taskService.claim(task.getId(), "fozzie");
}
// Verify Fozzie can now retrieve the task
tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
for (Task task : tasks) {
System.out.println("Task for fozzie: " + task.getName());
// Complete the task
taskService.complete(task.getId());
}
System.out.println("Number of tasks for fozzie: "
+ taskService.createTaskQuery().taskAssignee("fozzie").count());
// Retrieve and claim the second task
tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for (Task task : tasks) {
System.out.println("Following task is available for accountancy group: " + task.getName());
taskService.claim(task.getId(), "kermit");
}
// Completing the second task ends the process
for (Task task : tasks) {
taskService.complete(task.getId());
}
// verify that the process is actually finished
HistoryService historyService = processEngine.getHistoryService();
HistoricProcessInstance historicProcessInstance =
historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
System.out.println("Process instance end time: "+ historicProcessInstance.getEndTime()); }}Copy the code
conclusion
- You can use the BPMN 2.0 structure in Activiti to do the following for business processes:
- Define gateways to implement decision making: the manager can reject the statement and re-create a task for the accountant
- Consider using variables: you can save or reference the report and display it in a form
- Add service tasks at the end of the process: send reports to each leader