Expense Process Diagram
Expense Process BPMN20
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <process id="expenseProcess" name="The new and shiny expense process" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="Request Refund" activiti:assignee="kermit"> <documentation>[Employee:${employee}, Amount: ${amount}]</documentation> </userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <userTask id="usertask2" name="Handle Request" activiti:candidateGroups="accountancy"> <documentation>${employee} has requested a refund amount ${amount}</documentation> </userTask> <userTask id="usertask3" name="Handle Request" activiti:candidateGroups="management"> <documentation>${employee} has requested a refund of ${amount}</documentation> </userTask> <serviceTask id="mailtask1" name="Mail Task" activiti:type="mail"> <extensionElements> <activiti:field name="to"> <activiti:string><![CDATA[thysmichels@gmail.com]]></activiti:string> </activiti:field> <activiti:field name="from"> <activiti:string><![CDATA[lc@lc.com]]></activiti:string> </activiti:field> <activiti:field name="subject"> <activiti:string><![CDATA[Activity Mail]]></activiti:string> </activiti:field> <activiti:field name="html"> <activiti:expression>${employee} has requested refund</activiti:expression> </activiti:field> </extensionElements> </serviceTask> <sequenceFlow id="flow6" sourceRef="mailtask1" targetRef="usertask3"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway> <exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway"></exclusiveGateway> <sequenceFlow id="flow7" sourceRef="usertask3" targetRef="exclusivegateway2"></sequenceFlow> <sequenceFlow id="flow8" sourceRef="usertask2" targetRef="exclusivegateway2"></sequenceFlow> <sequenceFlow id="flow9" sourceRef="exclusivegateway2" targetRef="endevent1"></sequenceFlow> <sequenceFlow id="flow10" sourceRef="usertask1" targetRef="exclusivegateway1"></sequenceFlow> <sequenceFlow id="flow11" name="${employeeVerification=="true"}" sourceRef="exclusivegateway1" targetRef="mailtask1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${employeeVerification=="true"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow12" name="${employeeVerification=="false"}" sourceRef="exclusivegateway1" targetRef="usertask2"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${employeeVerification=="false"}]]></conditionExpression> </sequenceFlow> <boundaryEvent id="boundarytimer1" name="Timer" attachedToRef="usertask2" cancelActivity="true"> <timerEventDefinition> <timeDuration>PT1S</timeDuration> </timerEventDefinition> </boundaryEvent> <sequenceFlow id="flow15" sourceRef="boundarytimer1" targetRef="startevent1"></sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_expenseProcess"> <bpmndi:BPMNPlane bpmnElement="expenseProcess" id="BPMNPlane_expenseProcess"> <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> <omgdc:Bounds height="35.0" width="35.0" x="132.0" y="290.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"> <omgdc:Bounds height="55.0" width="105.0" x="240.0" y="280.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"> <omgdc:Bounds height="55.0" width="105.0" x="462.0" y="390.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="boundarytimer1" id="BPMNShape_boundarytimer1"> <omgdc:Bounds height="30.0" width="30.0" x="500.0" y="430.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"> <omgdc:Bounds height="55.0" width="105.0" x="640.0" y="180.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="mailtask1" id="BPMNShape_mailtask1"> <omgdc:Bounds height="55.0" width="105.0" x="450.0" y="180.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"> <omgdc:Bounds height="35.0" width="35.0" x="890.0" y="297.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1"> <omgdc:Bounds height="40.0" width="40.0" x="413.0" y="287.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="exclusivegateway2" id="BPMNShape_exclusivegateway2"> <omgdc:Bounds height="40.0" width="40.0" x="810.0" y="294.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> <omgdi:waypoint x="167.0" y="307.0"></omgdi:waypoint> <omgdi:waypoint x="240.0" y="307.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"> <omgdi:waypoint x="555.0" y="207.0"></omgdi:waypoint> <omgdi:waypoint x="640.0" y="207.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7"> <omgdi:waypoint x="745.0" y="207.0"></omgdi:waypoint> <omgdi:waypoint x="830.0" y="207.0"></omgdi:waypoint> <omgdi:waypoint x="830.0" y="294.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8"> <omgdi:waypoint x="567.0" y="417.0"></omgdi:waypoint> <omgdi:waypoint x="830.0" y="417.0"></omgdi:waypoint> <omgdi:waypoint x="830.0" y="334.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9"> <omgdi:waypoint x="850.0" y="314.0"></omgdi:waypoint> <omgdi:waypoint x="890.0" y="314.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10"> <omgdi:waypoint x="345.0" y="307.0"></omgdi:waypoint> <omgdi:waypoint x="413.0" y="307.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11"> <omgdi:waypoint x="433.0" y="287.0"></omgdi:waypoint> <omgdi:waypoint x="432.0" y="225.0"></omgdi:waypoint> <omgdi:waypoint x="450.0" y="207.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="36.0" width="100.0" x="443.0" y="287.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12"> <omgdi:waypoint x="433.0" y="327.0"></omgdi:waypoint> <omgdi:waypoint x="433.0" y="417.0"></omgdi:waypoint> <omgdi:waypoint x="462.0" y="417.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="36.0" width="100.0" x="443.0" y="327.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15"> <omgdi:waypoint x="500.0" y="445.0"></omgdi:waypoint> <omgdi:waypoint x="149.0" y="444.0"></omgdi:waypoint> <omgdi:waypoint x="149.0" y="325.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
Expense Process Test
package org.activiti.designer.test; import static org.junit.Assert.*; import java.util.HashMap; import java.util.List; import java.util.Map; import java.io.FileInputStream; import org.activiti.engine.HistoryService; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngineConfiguration; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.activiti.engine.test.ActivitiRule; import org.junit.Rule; import org.junit.Test; public class ProcessTestExpenseProcess { private String filename = "/Users/tmichels/Documents/workspace-sts-3.5.0.M21/nucleus-business-process/src/main/resources/diagrams/expense_process.bpmn"; @Rule public ActivitiRule activitiRule = new ActivitiRule(); @Test public void startProcess() throws Exception { ProcessEngine processEngine = ProcessEngineConfiguration .createStandaloneInMemProcessEngineConfiguration() .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE) .setMailServerHost("smtp.gmail.com") .setMailServerPort(587) .setMailServerUsername("youremail@gmail.com") .setMailServerPassword("password") .setMailServerUseSSL(true) .setMailServerUseTLS(true) .buildProcessEngine(); RuntimeService runtimeService = activitiRule.getRuntimeService(); RepositoryService repositoryService = activitiRule.getRepositoryService(); repositoryService.createDeployment().addInputStream("expense_process.bpmn", new FileInputStream(filename)).deploy(); Map<String, Object> variableMap1 = new HashMap<String, Object>(); variableMap1.put("employee", "Jack"); variableMap1.put("amount", 111); Map<String, Object> variableMap2 = new HashMap<String, Object>(); variableMap2.put("employee", "Jonny"); variableMap2.put("amount", 222); Map<String, Object> variableMap3 = new HashMap<String, Object>(); variableMap3.put("employee", "Pete"); variableMap3.put("amount", 333); ProcessInstance processInstance1 = runtimeService.startProcessInstanceByKey("expenseProcess", variableMap1); ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("expenseProcess", variableMap2); ProcessInstance processInstance3 = runtimeService.startProcessInstanceByKey("expenseProcess", variableMap3); System.out.println("**** ProcessInstance1 ID *** " + processInstance1.getId()); assertNotNull(processInstance1.getId()); assertNotNull(processInstance2.getId()); assertNotNull(processInstance3.getId()); Map<String, Object> processVariables = runtimeService.getVariables(processInstance1.getId()); for (String processVariable : processVariables.keySet()){ System.out.println("PROCESS KEY : " + processVariable + " VALUE: " + processVariables.get(processVariable)); } TaskService taskService = processEngine.getTaskService(); //Query Task Available for Kermit List<Task> availableTasksForKermit = taskService.createTaskQuery().taskAssignee("kermit").list(); for (Task task : availableTasksForKermit) { System.out.println(" *******AVAILABLE TASK**********" + "\n" + " Task Name: " + task.getName() + "\n Owner: " + task.getOwner() + "\n" + " Assignee: " + task.getAssignee() +"\n "+ "Description: " + task.getDescription()); } List<Task> tasks = activitiRule.getTaskService().createTaskQuery().list(); for (Task task : tasks){ System.out.println("*******LIST TASKS************" + "\n" + "Get Task:" + task.getAssignee()); } List<Task> kermitTasks = taskService.createTaskQuery() .taskAssignee("kermit") .processVariableValueEquals("amount", 111) .orderByDueDate().asc() .list(); for (Task kermitTask: kermitTasks){ System.out.println("*******QUERY FOR ASSIGNEE TASKS************" + "\n" + kermitTask.getAssignee()); } //Can't Claim Task as this task already has an assignee if (availableTasksForKermit.get(0).getAssignee()==null) taskService.claim(availableTasksForKermit.get(0).getId(), "rocky"); //Verify Task - No Tasks for Rocky cause Kermit has it tasks = taskService.createTaskQuery().taskAssignee("rocky").list(); for (Task task : tasks) { System.out.println("Task for rocky: " + task.getName()); } //Ok kermit claims a tasks taskService.claim(availableTasksForKermit.get(0).getId(), "kermit"); List<Task> claimedTasks = taskService.createTaskQuery().taskCandidateOrAssigned("kermit").list(); for (Task claimedTask : claimedTasks){ System.out.println("Task claimed by Kermit: " + claimedTask.getDescription()); } Map<String, Object> taskCompleteVariables = new HashMap<String, Object>(); taskCompleteVariables.put("employeeVerification", false); taskCompleteVariables.put("amountVerificaion", true); taskService.complete(availableTasksForKermit.get(0).getId(),taskCompleteVariables); System.out.println("Number of tasks for kermit: " + taskService.createTaskQuery().taskAssignee("kermit").count()); List<Task> accountancyTasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list(); for (Task accountancyTask : accountancyTasks){ System.out.println("Accountancy Task: " +accountancyTask.getDescription()); } taskService.claim(accountancyTasks.get(0).getId(), "sandy"); System.out.println("Number of tasks for Sandy: " + taskService.createTaskQuery().taskAssignee("sandy").count()); System.out.println("BreakPoint Timeout"); System.out.println("Number of tasks for Sandy: " + taskService.createTaskQuery().taskAssignee("sandy").count()); //Query Task Available for Kermit List<Task> availableTasksForKermit2 = taskService.createTaskQuery().taskAssignee("kermit").list(); for (Task task : availableTasksForKermit2) { System.out.println(" *******AVAILABLE TASK**********" + "\n" + " Task Name: " + task.getName() + "\n Owner: " + task.getOwner() + "\n" + " Assignee: " + task.getAssignee() +"\n "+ "Description: " + task.getDescription()); } taskService.claim(accountancyTasks.get(0).getId(), "sandy"); taskService.complete(accountancyTasks.get(0).getId()); HistoryService historyService = processEngine.getHistoryService(); HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstance1.getId()).singleResult(); System.out.println("Process instance end time: " + historicProcessInstance.getEndTime()); } }
Output
SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/Users/tmichels/.m2/repository/org/slf4j/slf4j-log4j12/1.7.7/slf4j-log4j12-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/Users/tmichels/.m2/repository/org/slf4j/slf4j-jdk14/1.7.2/slf4j-jdk14-1.7.2.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory] 23 May 2014 09:08:57,461 [main] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [activiti.cfg.xml] 23 May 2014 09:08:59,874 [main] INFO org.activiti.engine.impl.db.DbSqlSession:975 - performing create on engine with resource org/activiti/db/create/activiti.h2.create.engine.sql 23 May 2014 09:08:59,955 [main] INFO org.activiti.engine.impl.db.DbSqlSession:975 - performing create on history with resource org/activiti/db/create/activiti.h2.create.history.sql 23 May 2014 09:08:59,973 [main] INFO org.activiti.engine.impl.db.DbSqlSession:975 - performing create on identity with resource org/activiti/db/create/activiti.h2.create.identity.sql 23 May 2014 09:08:59,986 [main] INFO org.activiti.engine.impl.ProcessEngineImpl:79 - ProcessEngine default created 23 May 2014 09:08:59,989 [main] INFO org.activiti.engine.impl.jobexecutor.JobExecutor:76 - Starting up the JobExecutor[org.activiti.engine.impl.jobexecutor.DefaultJobExecutor]. 23 May 2014 09:08:59,994 [Thread-1] INFO org.activiti.engine.impl.jobexecutor.AcquireJobsRunnable:51 - JobExecutor[org.activiti.engine.impl.jobexecutor.DefaultJobExecutor] starting to acquire jobs 23 May 2014 09:09:00,847 [main] INFO org.activiti.engine.impl.ProcessEngineImpl:79 - ProcessEngine default created 23 May 2014 09:09:00,853 [main] INFO org.activiti.engine.impl.bpmn.deployer.BpmnDeployer:81 - Processing resource expense_process.bpmn **** ProcessInstance1 ID *** 5 PROCESS KEY : amount VALUE: 111 PROCESS KEY : employee VALUE: Jack *******AVAILABLE TASK********** Task Name: Request Refund Owner: null Assignee: kermit Description: [Employee:Jack, Amount: 111] *******AVAILABLE TASK********** Task Name: Request Refund Owner: null Assignee: kermit Description: [Employee:Jonny, Amount: 222] *******AVAILABLE TASK********** Task Name: Request Refund Owner: null Assignee: kermit Description: [Employee:Pete, Amount: 333] *******LIST TASKS************ Get Task:kermit *******LIST TASKS************ Get Task:kermit *******LIST TASKS************ Get Task:kermit *******QUERY FOR ASSIGNEE TASKS************ kermit 23 May 2014 09:09:02,320 [main] INFO org.activiti.engine.impl.bpmn.deployer.BpmnDeployer:81 - Processing resource expense_process.bpmn 23 May 2014 09:09:02,442 [main] INFO org.activiti.engine.impl.bpmn.deployer.BpmnDeployer:81 - Processing resource expense_process.expenseProcess.png Number of tasks for kermit: 2 Accountancy Task: Jack has requested a refund amount 111 Number of tasks for Sandy: 1 BreakPoint Timeout Number of tasks for Sandy: 1 *******AVAILABLE TASK********** Task Name: Request Refund Owner: null Assignee: kermit Description: [Employee:Jonny, Amount: 222] *******AVAILABLE TASK********** Task Name: Request Refund Owner: null Assignee: kermit Description: [Employee:Pete, Amount: 333] Process instance end time: Fri May 23 09:09:02 PDT 2014
Your title is misleading – this is not a tutorial !