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>