zoukankan      html  css  js  c++  java
  • 开源工作流Fireflow源码分析之流程文件解析

        Java要解析xml并不困难,fireflow的作者是采用dom4j来解析.具体解析的类为:Dom4JPDLParser,另外还有一个类Dom4JFPDLSerializer,它的作用是将工作流模型写成Xml.

       1):如何配置xml解析器的,作者提供了两个模式,一个是开发阶段用的definitionService4FileSystem,一个是实施阶段的definitionService4DBMS 

      

     <bean id="definitionService4FileSystem"
    		class="org.fireflow.engine.definition.DefinitionService4FileSystem">
            <property name="definitionFiles">
                <list>
                    <value>
    	      /process_definition/LeaveApplicationProcess.xml
                    </value>
                </list>
            </property>
    </bean>
    
        <bean id="runtimeContext"
              class="org.fireflow.engine.RuntimeContext"
              init-method="initialize">
          …… 
     <property name="definitionService">
                <ref local="definitionService4FileSystem"/>
            </property>
          ……
        </bean>
    

         2):如果是开发阶段,系统启动的时候会自动解析xml,并进行缓存.如果是实施阶段,启动的时候不会解析,只要第一次用到,系统进行解析.

    注意,开发阶段缓存workflowProcess的作用就是加快测试的过程,没有什么其它的意义,作者真正缓存的对象是工作流网实例,这是后话。

         

    //开发阶段的definitionService4FileSystem:如果配置了xml就进行解析.
    public void setDefinitionFiles(List<String> workflowProcessFileNames)
                throws IOException, FPDLParserException,EngineException {
            if (workflowProcessFileNames != null) {
                Dom4JFPDLParser parser = new Dom4JFPDLParser();
                for (int i = 0; i < workflowProcessFileNames.size(); i++) {
                    InputStream inStream = this.getClass().getResourceAsStream(
                            workflowProcessFileNames.get(i).trim());
                    if (inStream == null) {
                        throw new IOException("没有找到名称为" + workflowProcessFileNames.get(i) + "的流程定义文件");
                    }
                    
                    WorkflowProcess workflowProcess = parser.parse(inStream);
    
                    WorkflowDefinition workflowDef = new WorkflowDefinition();
                    workflowDef.setVersion(new Integer(1));
    
                    workflowDef.setWorkflowProcess(workflowProcess);
    
                    String latestVersionKey = workflowProcess.getId() + "_V_" + workflowDef.getVersion();
                    workflowDefinitionMap.put(latestVersionKey, workflowDef);
                    latestVersionKeyMap.put(workflowProcess.getId(), latestVersionKey);
    
                }
            }
    
    //实施阶段如何处理的呢, definitionService4DBMS处理的就是从数据库里得到xml定义的字符串
    //通过流程ID从数据库里得到流程定义的字符串
        public WorkflowDefinition getWorkflowDefinitionByProcessIdAndVersionNumber(String id, Integer version) {
            return rtCtx.getPersistenceService().findWorkflowDefinitionByProcessIdAndVersionNumber(id, version);
        }
    真正的读操作在流程定义对象(WorkflowDefinition)的getWorkflowprocess方法
    
    //WorkflowDefinition.java,得到工作流模型
    public WorkflowProcess getWorkflowProcess() throws RuntimeException{
            if (workflowProcess == null) {
                if (this.processContent != null && !this.processContent.trim().equals("")) {
    
                    ByteArrayInputStream in = null;
                    try {
                        Dom4JFPDLParser parser = new Dom4JFPDLParser();//采用dom4j来解析xml
                        in = new ByteArrayInputStream(this.processContent.getBytes("utf-8"));
                        this.workflowProcess = parser.parse(in);
    
                    } catch (UnsupportedEncodingException ex) {
                        Logger.getLogger(WorkflowDefinition.class.getName()).log(Level.SEVERE, null, ex);
                        throw new RuntimeException(ex.getMessage());
                    } catch (IOException ex) {
                        Logger.getLogger(WorkflowDefinition.class.getName()).log(Level.SEVERE, null, ex);
                        throw new RuntimeException(ex.getMessage());
                    } 
                    catch(FPDLParserException ex){
                        Logger.getLogger(WorkflowDefinition.class.getName()).log(Level.SEVERE, null, ex);
                        throw new RuntimeException(ex.getMessage());
                    } finally {
                        try {
                            in.close();
                        } catch (IOException ex) {
                            Logger.getLogger(WorkflowDefinition.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
    
                }
            }
            return workflowProcess;
        }
    

          3):弄清楚工作流模型和xml之间的对应关系。这个比较简单,只要看一下WorkflowProcess.java文件,和一个xml例子,就一目了然,

    作者的源文件上解释很全

          

    public class WorkflowProcess extends AbstractWFElement {
    
    	/**
    	 * 流程数据项,运行时转换为流程变量进行存储。
    	 */
    	private List<DataField> dataFields = new ArrayList<DataField>();
    
    	/**
    	 * 全局Task
    	 */
    	private List<Task> tasks = new ArrayList<Task>();
    
    	/**
    	 * 流程环节
    	 */
    	private List<Activity> activities = new ArrayList<Activity>();
    
    	/**
    	 * 转移
    	 */
    	private List<Transition> transitions = new ArrayList<Transition>();
    
    	/**
    	 * 循环
    	 */
    	private List<Loop> loops = new ArrayList<Loop>();
    
    	/**
    	 * 同步器
    	 */
    	private List<Synchronizer> synchronizers = new ArrayList<Synchronizer>();
    
    	/**
    	 * 开始节点
    	 */
    	private StartNode startNode = null;
    
    	/**
    	 * 结束节点
    	 */
    	private List<EndNode> endNodes = new ArrayList<EndNode>();
    
    	// 其他属性
    	/**
    	 * 资源文件(在1.0中暂时未使用)
    	 */
    	private String resourceFile = null;
    
    	/**
    	 * 资源管理器(在1.0中暂时未使用)
    	 */
    	private String resourceManager = null;
    
    	/**
    	 * 本流程全局的任务实例创建器。 如果没有设置,引擎将使用DefaultTaskInstanceCreator来创建TaskInstance。
    	 */
    	protected String taskInstanceCreator = null;
    
    	/**
    	 * 本流程全局的FormTask
    	 * Instance运行器。如果没有设置,引擎将使用DefaultFormTaskInstanceRunner来运行TaskInstance。
    	 */
    	protected String formTaskInstanceRunner = null;
    
    	/**
    	 * 本流程全局的ToolTask
    	 * Instance运行器。如果没有设置,引擎将使用DefaultToolTaskInstanceRunner来运行TaskInstance。
    	 */
    	protected String toolTaskInstanceRunner = null;
    
    	/**
    	 * 本流程全局的SubflowTask
    	 * Instance运行器。如果没有设置,引擎将使用DefaultSubflowTaskInstanceRunner来运行TaskInstance。
    	 */
    	protected String subflowTaskInstanceRunner = null;
    
    	/**
    	 * 本流程全局的FormTask Instance 终结评价器,用于告诉引擎该实例是否可以结束。<br/>
    	 * 如果没有设置,引擎使用缺省实现DefaultFormTaskInstanceCompletionEvaluator。
    	 */
    	protected String formTaskInstanceCompletionEvaluator = null;
    
    	/**
    	 * 本流程全局的ToolTask Instance 终结评价器,用于告诉引擎该实例是否可以结束。<br/>
    	 * 如果没有设置,引擎使用缺省实现DefaultToolTaskInstanceCompletionEvaluator。
    	 */
    	protected String toolTaskInstanceCompletionEvaluator = null;
    
    	/**
    	 * 本流程全局的SubflowTask Instance 终结评价器,用于告诉引擎该实例是否可以结束。<br/>
    	 * 如果没有设置,引擎使用缺省实现DefaultSubflowTaskInstanceCompletionEvaluator。
    	 */
    	protected String subflowTaskInstanceCompletionEvaluator = null;
     …….
    }
    
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE fpdl:WorkflowProcess PUBLIC "-//Nieyun Chen//ProcessDefinition//CN" "FireFlow_Process_Definition_Language.dtd">
    <fpdl:WorkflowProcess DisplayName="LeaveApplicationProcess" Id="LeaveApplicationProcess" Name="LeaveApplicationProcess" ResourceFile="" ResourceManager="" xmlns:fpdl="http://www.fireflow.org/Fireflow_Process_Definition_Language">
      <fpdl:DataFields>
        <fpdl:DataField DataType="INTEGER" DisplayName="请假天数" Id="LeaveApplicationProcess.leaveDays" InitialValue="1" Name="leaveDays"/>
        <fpdl:DataField DataType="BOOLEAN" DisplayName="审批意见" Id="LeaveApplicationProcess.approvalFlag" InitialValue="false" Name="approvalFlag"/>
      </fpdl:DataFields>
      <fpdl:StartNode DisplayName="" Id="LeaveApplicationProcess.START_NODE" Name="START_NODE">
        <fpdl:ExtendedAttributes>
          <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.height" Value="20"/>
          <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.width" Value="20"/>
          <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.x" Value="18"/>
          <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.y" Value="86"/>
        </fpdl:ExtendedAttributes>
      </fpdl:StartNode>
      <fpdl:Tasks/>
      <fpdl:Activities>
        <fpdl:Activity CompletionStrategy="ALL" DisplayName="申请" Id="LeaveApplicationProcess.Fulfill_The_ApplicationForm_Activity" Name="Fulfill_The_ApplicationForm_Activity">
          <fpdl:ExtendedAttributes>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.height" Value="60"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.width" Value="100"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.x" Value="97"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.y" Value="65"/>
          </fpdl:ExtendedAttributes>
          <fpdl:Tasks>
            <fpdl:Task CompletionStrategy="ANY" DefaultView="EDITFORM" DisplayName="填写请假单" Id="LeaveApplicationProcess.Fulfill_The_ApplicationForm_Activity.Fulfill_The_ApplicationForm_Task" LoopStrategy="REDO" Name="Fulfill_The_ApplicationForm_Task" Priority="1" Type="FORM">
              <fpdl:Performer DisplayName="当前用户" Name="Self">
                <fpdl:Description/>
                <fpdl:AssignmentHandler>org.fireflow.example.leaveapplication.workflowextension.CurrentUserAssignmentHandler</fpdl:AssignmentHandler>
              </fpdl:Performer>
              <fpdl:EditForm DisplayName="请假申请表" Name="ApplicationForm">
                <fpdl:Description/>
                <fpdl:Uri>/org/fireflow/example/leaveapplication/bizpages/SubmitApplication.jsp</fpdl:Uri>
              </fpdl:EditForm>
            </fpdl:Task>
          </fpdl:Tasks>
          <fpdl:TaskRefs/>
        </fpdl:Activity>
        <fpdl:Activity CompletionStrategy="ALL" DisplayName="部门经理审批" Id="LeaveApplicationProcess.DepartmentManager_Approve_Activity" Name="DepartmentManager_Approve_Activity">
          <fpdl:ExtendedAttributes>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.height" Value="60"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.width" Value="100"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.x" Value="279"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.y" Value="66"/>
          </fpdl:ExtendedAttributes>
          <fpdl:Tasks>
            <fpdl:Task CompletionStrategy="ANY" DefaultView="EDITFORM" DisplayName="审批请假单" Id="LeaveApplicationProcess.DepartmentManager_Approve_Activity.Approval_Task" LoopStrategy="REDO" Name="Approval_Task" Priority="1" Type="FORM">
              <fpdl:Performer DisplayName="部门经理" Name="DepartmentManager">
                <fpdl:Description/>
                <fpdl:AssignmentHandler>org.fireflow.example.leaveapplication.workflowextension.RoleDepartmentBasedAssignmentHandler</fpdl:AssignmentHandler>
              </fpdl:Performer>
              <fpdl:EditForm DisplayName="请假审批表单" Name="ApprovalForm">
                <fpdl:Description/>
                <fpdl:Uri>/org/fireflow/example/leaveapplication/bizpages/ApproveLeaveApplication.jsp</fpdl:Uri>
              </fpdl:EditForm>
            </fpdl:Task>
          </fpdl:Tasks>
          <fpdl:TaskRefs/>
        </fpdl:Activity>
        <fpdl:Activity CompletionStrategy="ALL" DisplayName="发送邮件" Id="LeaveApplicationProcess.Send_Email_Activity" Name="Send_Email_Activity">
          <fpdl:ExtendedAttributes>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.height" Value="60"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.width" Value="204"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.x" Value="540"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.y" Value="65"/>
          </fpdl:ExtendedAttributes>
          <fpdl:Tasks>
            <fpdl:Task DisplayName="邮件通知申请人审批结果" Execution="SYNCHR" Id="LeaveApplicationProcess.Send_Email_Activity.Send_Email_Task" LoopStrategy="REDO" Name="Send_Email_Task" Priority="1" Type="TOOL">
              <fpdl:Application DisplayName="邮件发送接口程序" Name="EmailSender">
                <fpdl:Description/>
                <fpdl:Handler>org.fireflow.example.leaveapplication.workflowextension.EmailSender</fpdl:Handler>
              </fpdl:Application>
            </fpdl:Task>
          </fpdl:Tasks>
          <fpdl:TaskRefs/>
        </fpdl:Activity>
      </fpdl:Activities>
      <fpdl:Synchronizers>
        <fpdl:Synchronizer DisplayName="" Id="LeaveApplicationProcess.Synchronizer1" Name="Synchronizer1">
          <fpdl:ExtendedAttributes>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.height" Value="20"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.width" Value="20"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.x" Value="228"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.y" Value="85"/>
          </fpdl:ExtendedAttributes>
        </fpdl:Synchronizer>
        <fpdl:Synchronizer DisplayName="" Id="LeaveApplicationProcess.Synchronizer2" Name="Synchronizer2">
          <fpdl:ExtendedAttributes>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.height" Value="20"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.width" Value="20"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.x" Value="450"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.y" Value="86"/>
          </fpdl:ExtendedAttributes>
        </fpdl:Synchronizer>
      </fpdl:Synchronizers>
      <fpdl:EndNodes>
        <fpdl:EndNode DisplayName="" Id="LeaveApplicationProcess.EndNode1" Name="EndNode1">
          <fpdl:ExtendedAttributes>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.height" Value="20"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.width" Value="20"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.x" Value="814"/>
            <fpdl:ExtendedAttribute Name="FIRE_FLOW.bounds.y" Value="85"/>
          </fpdl:ExtendedAttributes>
        </fpdl:EndNode>
      </fpdl:EndNodes>
      <fpdl:Transitions>
        <fpdl:Transition DisplayName="" From="LeaveApplicationProcess.START_NODE" Id="LeaveApplicationProcess.Transition1" Name="Transition1" To="LeaveApplicationProcess.Fulfill_The_ApplicationForm_Activity">
          <fpdl:Condition/>
        </fpdl:Transition>
        <fpdl:Transition DisplayName="" From="LeaveApplicationProcess.Fulfill_The_ApplicationForm_Activity" Id="LeaveApplicationProcess.Transition2" Name="Transition2" To="LeaveApplicationProcess.Synchronizer1">
          <fpdl:Condition/>
        </fpdl:Transition>
        <fpdl:Transition DisplayName="" From="LeaveApplicationProcess.Synchronizer1" Id="LeaveApplicationProcess.Transition3" Name="Transition3" To="LeaveApplicationProcess.DepartmentManager_Approve_Activity">
          <fpdl:Condition/>
        </fpdl:Transition>
        <fpdl:Transition DisplayName="" From="LeaveApplicationProcess.DepartmentManager_Approve_Activity" Id="LeaveApplicationProcess.Transition4" Name="Transition4" To="LeaveApplicationProcess.Synchronizer2">
          <fpdl:Condition/>
        </fpdl:Transition>
        <fpdl:Transition DisplayName="" From="LeaveApplicationProcess.Send_Email_Activity" Id="LeaveApplicationProcess.Transition11" Name="Transition11" To="LeaveApplicationProcess.EndNode1">
          <fpdl:Condition/>
        </fpdl:Transition>
        <fpdl:Transition DisplayName="" From="LeaveApplicationProcess.Synchronizer2" Id="LeaveApplicationProcess.Transition6" Name="Transition6" To="LeaveApplicationProcess.Send_Email_Activity">
          <fpdl:Condition/>
        </fpdl:Transition>
      </fpdl:Transitions>
    </fpdl:WorkflowProcess>
    
  • 相关阅读:
    Conference deadlines
    waiting list
    BDA3 Chapter 1 Probability and inference
    PP: Articial Intelligence—TheRevolution Hasn’t HappenedYet
    兼容ie9文件上传,及现代浏览器实现进度条
    input 打开文件夹事件委托
    前端构建工具gulpjs的使用介绍及技巧
    如何编写兼容各主流邮箱的HTML邮件
    前端通用框架可行性研究报告之弹窗
    切换tab键,不聚焦a标签
  • 原文地址:https://www.cnblogs.com/mzhanker/p/2072667.html
Copyright © 2011-2022 走看看