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来解析xmlin = 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>