// VacationRequest.java
/**
 * author : 冯孟活 ^_^ 
 * dates : 2015年9月1日 下午10:32:58 
 * class : 演示简单的公司请假流程
 * 
 * 		一个简单的流程分三个步骤:
 * 				1、发布流程(部署流程定义)
 * 				2、启动流程实例
 * 				3、完成任务(先查询任务,后完成任务)
 * 				4、挂起、激活一个流程实例(可选)
 */
public class VacationRequest {
	public static void main(String[] args) {

		/**
		 *  第一步:发布流程
		 */
		ProcessEngine processEngine = ProcessEngineConfiguration // 通过流程引擎配置类来创建流程引擎
				.createProcessEngineConfigurationFromResource("activiti.cfg.xml").buildProcessEngine();
		RepositoryService repositoryService = processEngine.getRepositoryService(); // 通过流程引擎来得到知识库服务
		repositoryService.createDeployment().addClasspathResource("VacationRequest.bpmn").deploy(); // 通过只是库部署流程定义
		System.out.println("流程定义的个数="+repositoryService.createDeploymentQuery().count()); // 查询所有发布的流程定义的个数

		/**
		 *  第二步:启动一个流程实例
		 */
		/*定义Map来存放流程变量:流程变量经常会被用到,因为他们赋予来自同一个流程定义的不同流程实例
		   的特别含义,简单来说,流程变量是区分流程实例的关键
		*/
		Map<String, Object> variables = new HashMap<>(); // 定义一个Map来存放流程变量
		variables.put("employeeName","Kermit");
		variables.put("numberOfDays",new Integer(4));
		variables.put("vacationMotivation","I'm really tired!");
		RuntimeService runtimeService = processEngine.getRuntimeService(); // 获取运行服务
		runtimeService.startProcessInstanceByKey("vacationRequest",variables); // 通过运行服务来启动流程实例,并且设置流程变量(通过key 或者 id 部署都可以)
		System.out.println("流程实例的个数="+runtimeService.createProcessInstanceQuery().count()); // 通过运行服务来查询所有的流程实例的个数

		/**
		 *  第三部:完成任务
		 */
		TaskService taskService = processEngine.getTaskService(); // 通过流程引擎获取任务服务
		List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list(); // 通过任务服务来查询任务候选组(这是通过组来分区)
		for (Task task : tasks) { // 遍历打印任务
			System.err.println("能找到的任务="+task.getName());
		}
		Task task = tasks.get(0); // 获取第一个任务
		Map<String,Object> taskVariables = new HashMap<>(); // 定义一个Map来存放任务变量
		taskVariables.put("vacationApproved","false");
		taskVariables.put("managerMotivation","We have a tight deadline!");
		taskService.complete(task.getId(),taskVariables); // 根据Id来完成任务

		/**
		 *  挂起,激活一个流程
		 */
		/*
		 * 我们可以挂起一个流程定义。当挂起流程定义时, 就不能创建新流程了(会抛出一个异常)。 
		 * 可以通过RepositoryService挂起一个流程:
		 */
		//repositoryService.suspendProcessDefinitionByKey("vacationRequest"); // 挂起一个流程定义
		//try{
			//runtimeService.startProcessInstanceByKey("vacationRequest"); // 启动一个流程实例
		//}catch(ActivitiException e){ // 这里会抛出一个Activiti自定义异常
			//e.printStackTrace();
		//}

		/*
		 * 备注下:
		 * 		也可以挂起一个流程实例。挂起时,流程不能继续执行(比如,完成任务会抛出异常),
		 * 异步操作(比如定时器)也不会执行。 挂起流程实例可以调用 runtimeService.suspendProcessInstance方法。 
		 * 激活流程实例可以调用runtimeService.activateProcessInstanceXXX方法。
		 */
	}
}


<!-- activiti.cfg.xml -->
 <?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="databaseSchemaUpdate" value="update"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti?useUnicode=true&characterEncoding=utf-8"/>
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUsername" value="root"/>
        <property name="jdbcPassword" value="root"/>
        <property name="jobExecutorActivate" value="true"/>
    </bean>

</beans>


 <!-- VacationRequest.bpmn -->

 <?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:xsd="http://www.w3.org/2001/XMLSchema" 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://activiti.org/bpmn20" id="definitions">
  <process id="vacationRequest" name="Vacation request" isExecutable="true">
    <startEvent id="request" activiti:initiator="employeeName">
      <extensionElements>
        <activiti:formProperty id="numberOfDays" name="Number of days" type="long" required="true"></activiti:formProperty>
        <activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" type="date" datePattern="dd-MM-yyyy hh:mm" required="true"></activiti:formProperty>
        <activiti:formProperty id="vacationMotivation" name="Motivation" type="string"></activiti:formProperty>
      </extensionElements>
    </startEvent>
    <sequenceFlow id="flow1" sourceRef="request" targetRef="handleRequest"></sequenceFlow>
    <userTask id="handleRequest" name="Handle vacation request" activiti:candidateGroups="management">
      <documentation>${employeeName} would like to take ${numberOfDays} day(s) of vacation (Motivation: ${vacationMotivation}).</documentation>
      <extensionElements>
        <activiti:formProperty id="vacationApproved" name="Do you approve this vacation" type="enum" required="true">
          <activiti:value id="true" name="Approve"></activiti:value>
          <activiti:value id="false" name="Reject"></activiti:value>
        </activiti:formProperty>
        <activiti:formProperty id="managerMotivation" name="Motivation" type="string"></activiti:formProperty>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow2" sourceRef="handleRequest" targetRef="requestApprovedDecision"></sequenceFlow>
    <exclusiveGateway id="requestApprovedDecision" name="Request approved?"></exclusiveGateway>
    <sequenceFlow id="flow3" sourceRef="requestApprovedDecision" targetRef="sendApprovalMail">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${vacationApproved == 'true'}]]></conditionExpression>
    </sequenceFlow>
    <manualTask id="sendApprovalMail" name="Send confirmation e-mail"></manualTask>
    <sequenceFlow id="flow4" sourceRef="sendApprovalMail" targetRef="theEnd1"></sequenceFlow>
    <endEvent id="theEnd1"></endEvent>
    <sequenceFlow id="flow5" sourceRef="requestApprovedDecision" targetRef="adjustVacationRequestTask">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${vacationApproved == 'false'}]]></conditionExpression>
    </sequenceFlow>
    <userTask id="adjustVacationRequestTask" name="Adjust vacation request" activiti:assignee="${employeeName}">
      <documentation>Your manager has disapproved your vacation request for ${numberOfDays} days.
        Reason: ${managerMotivation}</documentation>
      <extensionElements>
        <activiti:formProperty id="numberOfDays" name="Number of days" type="long" required="true"></activiti:formProperty>
        <activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" type="date" datePattern="dd-MM-yyyy hh:mm" required="true"></activiti:formProperty>
        <activiti:formProperty id="vacationMotivation" name="Motivation" type="string"></activiti:formProperty>
        <activiti:formProperty id="resendRequest" name="Resend vacation request to manager?" type="enum" required="true">
          <activiti:value id="true" name="Yes"></activiti:value>
          <activiti:value id="false" name="No"></activiti:value>
        </activiti:formProperty>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow6" sourceRef="adjustVacationRequestTask" targetRef="resendRequestDecision"></sequenceFlow>
    <exclusiveGateway id="resendRequestDecision" name="Resend request?"></exclusiveGateway>
    <sequenceFlow id="flow7" sourceRef="resendRequestDecision" targetRef="handleRequest">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${resendRequest == 'true'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow8" sourceRef="resendRequestDecision" targetRef="theEnd2">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${resendRequest == 'false'}]]></conditionExpression>
    </sequenceFlow>
    <endEvent id="theEnd2"></endEvent>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_vacationRequest">
    <bpmndi:BPMNPlane bpmnElement="vacationRequest" id="BPMNPlane_vacationRequest">
      <bpmndi:BPMNShape bpmnElement="request" id="BPMNShape_request">
        <omgdc:Bounds height="35.0" width="35.0" x="0.0" y="178.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="handleRequest" id="BPMNShape_handleRequest">
        <omgdc:Bounds height="60.0" width="100.0" x="80.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="requestApprovedDecision" id="BPMNShape_requestApprovedDecision">
        <omgdc:Bounds height="40.0" width="40.0" x="230.0" y="114.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sendApprovalMail" id="BPMNShape_sendApprovalMail">
        <omgdc:Bounds height="60.0" width="100.0" x="320.0" y="0.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="theEnd1" id="BPMNShape_theEnd1">
        <omgdc:Bounds height="35.0" width="35.0" x="480.0" y="12.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="adjustVacationRequestTask" id="BPMNShape_adjustVacationRequestTask">
        <omgdc:Bounds height="60.0" width="100.0" x="320.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="resendRequestDecision" id="BPMNShape_resendRequestDecision">
        <omgdc:Bounds height="40.0" width="40.0" x="280.0" y="272.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="theEnd2" id="BPMNShape_theEnd2">
        <omgdc:Bounds height="35.0" width="35.0" x="283.0" y="370.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="35.0" y="195.0"></omgdi:waypoint>
        <omgdi:waypoint x="80.0" y="193.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="180.0" y="193.0"></omgdi:waypoint>
        <omgdi:waypoint x="192.0" y="180.0"></omgdi:waypoint>
        <omgdi:waypoint x="192.0" y="134.0"></omgdi:waypoint>
        <omgdi:waypoint x="230.0" y="134.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="270.0" y="134.0"></omgdi:waypoint>
        <omgdi:waypoint x="282.0" y="134.0"></omgdi:waypoint>
        <omgdi:waypoint x="282.0" y="30.0"></omgdi:waypoint>
        <omgdi:waypoint x="320.0" y="30.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="420.0" y="30.0"></omgdi:waypoint>
        <omgdi:waypoint x="432.0" y="30.0"></omgdi:waypoint>
        <omgdi:waypoint x="432.0" y="30.0"></omgdi:waypoint>
        <omgdi:waypoint x="480.0" y="29.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
        <omgdi:waypoint x="270.0" y="134.0"></omgdi:waypoint>
        <omgdi:waypoint x="282.0" y="134.0"></omgdi:waypoint>
        <omgdi:waypoint x="282.0" y="190.0"></omgdi:waypoint>
        <omgdi:waypoint x="320.0" y="190.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
        <omgdi:waypoint x="370.0" y="220.0"></omgdi:waypoint>
        <omgdi:waypoint x="370.0" y="265.0"></omgdi:waypoint>
        <omgdi:waypoint x="370.0" y="292.0"></omgdi:waypoint>
        <omgdi:waypoint x="320.0" y="292.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="280.0" y="292.0"></omgdi:waypoint>
        <omgdi:waypoint x="130.0" y="291.0"></omgdi:waypoint>
        <omgdi:waypoint x="130.0" y="253.0"></omgdi:waypoint>
        <omgdi:waypoint x="130.0" y="223.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
        <omgdi:waypoint x="300.0" y="312.0"></omgdi:waypoint>
        <omgdi:waypoint x="300.0" y="370.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>