1.OSWorkFlow基本概念html
在商用和开源世界里,OSWorkflow 都不一样于这些已有的工做流系统。最大不一样在于 OSWorkflow 有着很是优秀的灵活性。在开始 接触 OSWorkflow 时可能较难掌握(有人说不适合工做流新手入门),好比,OSWorkflow 不要求图形化工具来开发工做流,而推荐手工编 写 xml 格式的工做流程描述符。它能为应用程序开发者提供集成,也能与现有的代码和数据库进行集成。这一切彷佛给正在寻找快速“即插即用”工做流解决 方案的人制造了麻烦,但研究发现,那些“即插即用”方案也不能在一个成熟的应用程序中提供足够的灵活性来实现全部需求。java
2. OSWorkFlow主要优点
OSWorkflow 给你绝对的灵活性。OSWorkflow 被认为是一种“低级别”工做流实现。与其余工做流系统能用图标表现“Loops(回 路)”和“Conditions(条件)”相比,OSWorkflow 只是手工“编码(Coded)”来实现的。但这并不能说实际的代码是须要彻底手工 编码的,脚本语言能胜任这种情形。OSWorkflow 不但愿一个非技术用户修改工做流程,虽然一些其余工做流系统提供了简单的 GUI 用于工做流编 辑,但像这样改变工做流,一般会破坏这些应用。因此,进行工做流调整的最佳人选是开发人员,他们知道该怎么改变。不过,在最新的版本 中,OSWorkflow 也提供了 GUI 设计器来协助工做流的编辑。
OSWorkflow 基于有限状态机概念。每一个 state 由 step ID 和 status 联合表现(可简单理解为 step 及 其 status 表示有限状态机的 state)。一个 state 到另外一 state 的 transition 依赖于 action 的发生, 在工做流生命期内有至少一个或多个活动的 state。这些简单概念展示了 OSWorkflow 引擎的核心思想,并容许一个简单 XML 文件解释工 做流业务流程。mysql
3. OSWorkFlow核心概念web
3.1. 概念定义
步骤(Step)
一个 Step 描述的是工做流所处的位置。可能从一个 Step Transtion(流转)到另一个 Step,或者也能够在同一个 Step 内流转(由于 Step 能够通 Status 来细分,造成多个State)。一个流程里面能够多个Step。
状态(Status)
工做流 Status 是用来描述工做流程中具体Step(步骤)状态的字符串。OSWorkflow 的有 Underway(进行中)、 Queued(等候处理中)、Finished(完成)三种 Status。一个实际State(状态)真正是由两部分组 成:State = (Step + Status) 。
流转(Transtion)
一个State到另外一个State的转移。
动做(Action)
Action 触发了发生在 Step 内或 Step 间的流转,或者说是基于 State 的流转。一个 step 里面能够有多个 Action。Action 和Step 之间的关系是,Step 说明“在哪里”,Action 说明“去哪里”。 一个 Action 典型地由两部 分组成:能够执行此Action(动做)的
Condition(条件),以及执行此动做后的 Result(结果)。
条件(Condition)
相似于逻辑判断,可包含“AND”和“OR”逻辑。好比一个请假流程中的“本部门审批阶段”,该阶段利用“AND”逻辑,判断流程状态是否为等候处理中,以及审批者是否为本部门主管。
结果(Result)
Result 表明执行Action(动做)后的结果,指向新的 Step 及其 Step Status,也可能进入 Split 或者 Join。 Result 分为两种, Contidional-Result (有条件结果),只有条件为真时才使用该结果,和 Unconditional- Result(无条件结果),当条件不知足或没有条件时使用该结果。
分离/链接(Split/Join)
流程的切分和融合。很简单的概念,Split 能够提供多个 Result(结果);Join 则判断多个 Current Step 的态提供一个 Result(结果)。sql
3.2. 步骤、状态和动做(Step, Status, and Action)
工做流要描述步骤(Step)、步骤的状态(Status)、各个步骤之间的关系以及执行各个步骤的条件和权限,每一个步骤中能够含有一个或多个动做(Action),动做将会使一个步骤的状态发生改变。
对于一个执行的工做流来说,步骤的切换是不可避免的。一个工做流在某一时刻会有一个或多个当前步骤,每一个当前步骤都有一个状态值,当前步骤的状态值组成了 工做流实例的状态值。一旦完成了一个步骤,那么这个步骤将再也不是当前步骤(而是切换到一个新的步骤),一般一个新的当前步骤将随之创建起来,以保证工做流 继续执行。完成了的步骤的最终状态值是用Old-Status属性指定的,这个状态值的设定将发生在切换到其余步骤以前。Old-Status的值能够是 任意的,但在通常状况下,咱们设置为Finished。
切换自己是一个动做(Action)的执行结果。每一个步骤能够含有多个动做,究竟要载入哪一个动做是由最终用户、外部事件或者Tiggerd的自动调用决定 的。随着动做的完成,一个特定的步骤切换也将发生。动做能够被限制在用户、用户组或当前状态。每个动做都必须包含一个 Unconditional Result和0个或多个Conditional Results。
因此,整体来讲,一个工做流由多个步骤组成。每一个步骤有一个当前状态(例如:Queued, Underway or Finished),一个步骤包含 多个动做。每一个步骤含有多个能够执行的动做。每一个动做都有执行的条件,也有要执行的函数。动做包含有能够改变状态和当前工做流步骤的results。
3.3. 结果、分支和链接(Results, Joins, and Splits)shell
3.3.1. 无条件结果(Unconditional Result)
对于每个动做来说,必须存在一个Unconditional Result。一个result是一系列指令,这些指令将告诉OSWorkFlow下一个任务要作什么。这包括使工做流从一个状态切换到另外一个状态。数据库
3.3.2. 有条件结果(Conditional Result)
Conditional Result是Unconditional Result的一个扩展。它须要一个或多个Condition子标签。第一个为 true的Conditional(使用AND或OR类型),会指明发生切换的步骤,这个切换步骤的发生是因为某个用户执行了某个动做的结果致使的。express
3.3.3. 三种不一样的Results(conditional or unconditional)
一个新的、单一的步骤和状态的组合。
一个分裂成两个或多个步骤和状态的组合。
将这个和其余的切换组合成一个新的单一的步骤和状态的组合。
每种不一样的result对应了不一样的xml描述,你能够阅读http://www.opensymphony.com/osworkflow/workflow_2_7.dtd,获取更多的信息。
注意:一般,一个split或一个join不会再致使一个split 或 join的发生。apache
3.4. 自动步骤(Auto actions)
有的时候,咱们须要一些动做能够基于一些条件自动地执行。为了达到这个目的,你能够在action中加入auto="true"属性。流程将考察这个动做 的条件和限制,若是条件符合,那么将执行这个动做。 Auto action是由当前的调用者执行的,因此将对该动做的调用者执行权限检查。数组
3.5. 整合抽象实例(Integrating with Abstract Entities)
建议在你的核心实体中,例如"Document" 或 "Order",在内部建立一个新的属性:workflowId。这样,当新 的"Document" 或 "Order"被建立的时候,它可以和一个workflow实例关联起来。那么,你的代码能够经过 OSWorkflow API查找到这个workflow实例而且获得这个workflow的信息和动做。
3.6. 工做流实例状态(Workflow Instance State)
有的时候,为整个workflow实例指定一个状态是颇有帮助的,它独立于流程的执行步骤。OSWorkflow提供一些workflow实例中能够包含 的"meta-states"。这些"meta-states"能够是 CREATED, ACTIVATED, SUSPENDED, KILLED 和 COMPLETED。当一个工做流实例被建立的时候,它将处于 CREATED状态。而后,只要一个动做被执行,它就会自动的变成ACTIVATED状态。若是调用者没有明确地改变实例的状态,工做流将一直保持这个状 态直到工做流结束。当工做流不可能再执行任何其余的动做的时候,工做流将自动的变成COMPLETED状态。
然而,当工做流处于ACTIVATED状态的时候,调用者能够终止或挂起这个工做流(设置工做流的状态为KILLED 或 SUSPENDED)。一个终 止了的工做流将不能再执行任何动做,并且将永远保持着终止状态。一个被挂起了的工做流会被冻结,他也不能执行任何的动做,除非它的状态再变成 ACTIVATED。
4. OSWorkFlow包用途分析及代码片段
4.1. com.opensymphony.workflow
该包为整个OSWorkflow 引擎提供核心接口。例如 com.opensymphony.workflow.Workflow 接口,能够说,实际 开发中的大部分工做都是围绕该接口展开的,该接口有 BasicWorkflow、EJBWorkflow、OfbizWorkflow 三个实现类。
4.2. com.opensymphony.workflow.basic
该包有两个类,BasicWorkflow 与 BasicWorkflowContext。BasicWorkflow 不支持事务,尽管依赖持久实现,事务也不能包裹它。BasicWorkflowContext 在实际开发中不多使用。
4.3. com.opensymphony.workflow.config
该包有一个接口和两个该接口的实现类。在 OSWorkflow 2.7 之前,状态由多个地方的静态字段维护,这种方式很方便,可是有不少缺陷和约束。 最主要的缺点是没法经过不一样配置运行多个 OSWorkflow 实例。实现类 DefaultConfiguration 用于通常的配置文件载入。 而 SpringConfiguration 则是让 Spring 容器管理配置信息。
4.4. com.opensymphony.workflow.ejb
该包有两个接口 WorkflowHome 和 WorkflowRemote。该包的若干类中,最重要的是 EJBWorkflow,该类 和 BasicWorkflow 的做用同样,是 OSWorkflow 的核心,并利用 EJB 容器管理事务,也做为工做 流 session bean 的包装器。
4.5. com.opensymphony.workflow.loader
该包有若干类,用得最多的是 XxxxDescriptor,若是在工做流引擎运行时须要了解指定的动做、步骤的状态、名字,等信息时,这些描述符会起到很大做用。
4.6. com.opensymphony.workflow.ofbiz
OfbizWorkflow 和 BasicWorkflow 在不少方面很是类似,除了须要调用 ofbiz 的 TransactionUtil 来包装事务。
4.7. com.opensymphony.workflow.query
该包主要为查询而设计,但不是全部的工做流存储都支持查询。一般,Hibernate 和 JDBC 都支持,而内存工做流存储不支持。值得注意的 是 Hibernate 存储不支持混合型查询(例如,一个查询同时包含了 history step 上下文和 current step 上下文)。 执行一个查询,须要建立 WorkflowExpressionQuery 实例,接着调用 Workflow 对象的 query 方法来获得最终查询 结果。
4.8. com.opensymphony.workflow.soap
OSWorkflow 经过 SOAP 来支持远端调用。这种调用借助 WebMethods 实现。
4.9. com.opensymphony.workflow.spi
该包能够说是 OSWorkflow 与持久层打交道的途径,如当前工做流的实体,其中包括:EJB、Hibernate、JDBC、Memory、Ofbiz、OJB、Prevayler。
HibernateWorkflowEntry hwfe = (HibernateWorkflowEntry) getHibernateTemplate()
.find("from HibernateWorkflowEntry where Id="
+ wfIdList.get(i)).get(0);
4.10. com.opensymphony.workflow.util
该包是 OSWorkflow 的工具包,包括了对 BeanShell、BSF、EJB Local、EJB Remote、JNDI 的支持。
5. OSWorkFlow表结构分析
5.1. OS_WFENTRY
工做流主表,存放工做流名称和状态
字段名 数据类型 说明
ID NUMBER 自动编号
NAME VARCHAR2(20) 工做流名称
STATE NUMBER 工做流状态
5.2. OS_CURRENTSTEP
当前步骤表,存放当前正在进行步骤的数据
字段名 数据类型 说明
ID NUMBER 自动编号
ENTRY_ID NUMBER 工做流编号
STEP_ID NUMBER 步骤编号
ACTION_ID NUMBER 动做编号
OWNER VARCHAR2(20) 步骤的全部者
START_DATE DATE 开始时间
FINISH_DATE DATE 结束时间
DUE_DATE DATE 受权时间
STATUS VARCHAR2(20) 状态
CALLER VARCHAR2(20) 操做人员的账号名称
5.3. OS_CURRENTSTEP_PREV
前步骤表,存放当前步骤和上一个步骤的关联数据
字段名 数据类型 说明
ID NUMBER 当前步骤编号
PREVIOUS NUMBER 前步骤编号
5.4. OS_HISTORYSTEP
历史步骤表,存放当前正在进行步骤的数据
字段名 数据类型 说明
ID NUMBER 自动编号
ENTRY_ID NUMBER 工做流编号
STEP_ID NUMBER 步骤编号
ACTION_ID NUMBER 动做编号
OWNER VARCHAR2(20) 步骤的全部者
START_DATE DATE 开始时间
FINISH_DATE DATE 结束时间
DUE_DATE DATE 受权时间
STATUS VARCHAR2(20) 状态
CALLER VARCHAR2(20) 操做人员的账号名称
5.5. OS_HISTORYSTEP_PREV
前历史步骤表,存放历史步骤和上一个步骤的关联数据
字段名 数据类型 说明
ID NUMBER 当前历史步骤编号
PREVIOUS NUMBER 前历史步骤编号
5.6. OS_PROPERTYENTRY
属性表,存放临时变量
字段名 数据类型 说明
GLOBAL_KEY VARCHAR2(255) 全局关键字
ITEM_KEY VARCHAR2(255) 条目关键字
ITEM_TYPE NUMBER 条目类型
STRING_VALUE VARCHAR2(255) 字符值
DATE_VALUE DATE 日期值
DATA_VALUE BLOB 数据值
FLOAT_VALUE FLOAT 浮点值
osworkflow代码分析
1.com.opensymphony.workflow.Workflow 工做流的用户接口。
主要定义了用户对工做流的操做方法和用户得到工做流信息的方法。如doAction(long id, int actionId, Map inputs)方法能够执行工做流的Action并产生transaction;用户调用getAvailableActions(long id, Map inputs)能够得到知道工做流实例中符合条件的能够执行的Action。
2.com.opensymphony.workflow.WorkflowContext 工做流的Context接口。
只有两个方法,其中getCaller()得到调用者,setRollbackOnly()能够回滚Action形成的transaction。
setRollbackOnly()方法很是重要,能够在此方法中实现工做流数据与业务数据的事务处理。因为工做流引擎将流程数据与业务数据分离开管理, 因此工做流数据与业务数据之间的事务处理每每比较困难,甚至有不少商业的工做流引擎都没有解决这个问题,形成软件上的漏洞。惋惜在 BasicWorkflowContext中并无实现回滚时的事务处理,但实现起来应该不会很困难,在之后会单独考虑。
3.com.opensymphony.workflow.spi.WorkflowEntry 工做流实例的接口。
定义了得到工做流实例信息的方法。
4.com.opensymphony.workflow.config.Configuration 工做流配置接口。
得到osworkflw的配置信息和流程的定义信息, osworkflow中的例子就是使用此接口的默认实现。若是想让osworkflw与本身的系统更好的整合,这个接口须要本身实现。
5.com.opensymphony.workflow.loader.AbstractWorkflowFactory 流程定义的解析器。
osworkflow中提供了此抽象类的3种实现,最经常使用的是XMLWorkflowFactory,能够对编写的工做流定义xml文件进行解析。
6.com.opensymphony.workflow.spi.WorkflowStore 工做流存储接口。
实现此接口能够实现用多种途径保存工做流信息,jdbc,hibernate,ejb,memory.........
AbstractWorkflow类是workflow接口的最基本的实现。
1.public int[] getAvailableActions(long id, Map inputs)方法:
返回当前能够执行的Ation。
2. public void setConfiguration(Configuration configuration)方法:
设置工做流配置方法。
3.public Configuration getConfiguration()方法:
返回工做流配置方法,若是没有得到配置信息,初始化配置信息。
4.public List getCurrentSteps(long id):
得到工做流当前所在步骤。
5.public int getEntryState(long id):
得到工做流的状态。
6.public List getHistorySteps(long id)
得到工做流的历史步骤。
7. public Properties getPersistenceProperties()
得到设置的持久化参数。
8.public PropertySet getPropertySet(long id)
获得工做流的PropertySet,调用store中的方法。
9.public List getSecurityPermissions(long id)
获得工做流当前Step的permissions。
10.public WorkflowDescriptor getWorkflowDescriptor(String workflowName)
获得工做流的定义。
11.public String getWorkflowName(long id)
根据工做流实例返回工做流定义名。
12. public String[] getWorkflowNames()
返回系统中配置的全部工做流的名字。
13.public boolean canInitialize(String workflowName, int initialAction),public boolean canInitialize(String workflowName, int initialAction, Map inputs),private boolean canInitialize(String workflowName, int initialAction, Map transientVars, PropertySet ps) throws WorkflowException
判断指定的工做流初始化Action是否是能够执行。
14.public boolean canModifyEntryState(long id, int newState)
判断工做流是否是能够转换到指定状态。
15.public void changeEntryState(long id, int newState) throws WorkflowException
转换工做流状态。
16.public void doAction(long id, int actionId, Map inputs) throws WorkflowException
执行Action。
17.public void executeTriggerFunction(long id, int triggerId) throws WorkflowException
调用工做流的Trigger Function
18.public long initialize(String workflowName, int initialAction, Map inputs) throws InvalidRoleException, InvalidInputException, WorkflowException
初始化一个新的流程实例。返回流程实例id。
19.public List query(WorkflowQuery query),public List query(WorkflowExpressionQuery query)
查询流程实例。
20.public boolean removeWorkflowDescriptor(String workflowName) throws FactoryException
删除已经配置的工做流定义。
21.public boolean saveWorkflowDescriptor(String workflowName, WorkflowDescriptor descriptor, boolean replace) throws FactoryException
保存工做流定义。
22.protected List getAvailableActionsForStep(WorkflowDescriptor wf, Step step, Map transientVars, PropertySet ps) throws WorkflowException
得到指定步骤的可用Actions。
23.protected int[] getAvailableAutoActions(long id, Map inputs)
返回可执行的AutoActions。
24.protected List getAvailableAutoActionsForStep(WorkflowDescriptor wf, Step step, Map transientVars, PropertySet ps) throws WorkflowException
返回指定Step中可执行的AutoActions。
25.protected WorkflowStore getPersistence() throws StoreException
返回配置的store。
26.protected void checkImplicitFinish(long id) throws WorkflowException
判断工做流是否是还有可执行的Action,若是没有,完成此工做流实例。
27.protected void completeEntry(long id, Collection currentSteps) throws StoreException
结束工做流实例,就是把改变流程实例的状态并把当前的Steps都放入到历史表中。
28.protected boolean passesCondition(ConditionDescriptor conditionDesc, Map transientVars, PropertySet ps, int currentStepId) throws WorkflowException
29.protected boolean passesCondition(ConditionDescriptor conditionDesc, Map transientVars, PropertySet ps, int currentStepId) throws WorkflowException,protected boolean passesConditions(String conditionType, List conditions, Map transientVars, PropertySet ps, int currentStepId) throws WorkflowException
判断条件是否是符合。
30.protected void populateTransientMap(WorkflowEntry entry, Map transientVars, List registers, Integer actionId, Collection currentSteps) throws WorkflowException
产生临时变量transientVars,包含context,entry,store,descriptor,actionId,currentSteps,以及定义的register和用户的输入变量。
31.protected void verifyInputs(WorkflowEntry entry, List validators, Map transientVars, PropertySet ps) throws WorkflowException
验证用户的输入。
32.private boolean isActionAvailable(ActionDescriptor action, Map transientVars, PropertySet ps, int stepId) throws WorkflowException
判断Action是否可用。
33.private Step getCurrentStep(WorkflowDescriptor wfDesc, int actionId, List currentSteps, Map transientVars, PropertySet ps) throws WorkflowException
得到Action所在Step。
34.private boolean canInitialize(String workflowName, int initialAction, Map transientVars, PropertySet ps) throws WorkflowException
判断工做流是否是能够实例化。
35.private Step createNewCurrentStep(ResultDescriptor theResult, WorkflowEntry entry, WorkflowStore store, int actionId, Step currentStep, long[] previousIds, Map transientVars, PropertySet ps) throws WorkflowException
产生新的当前Step。
36.private void executeFunction(FunctionDescriptor function, Map transientVars, PropertySet ps) throws WorkflowException
执行Function。
37.private boolean transitionWorkflow(WorkflowEntry entry, List currentSteps, WorkflowStore store, WorkflowDescriptor wf, ActionDescriptor action, Map transientVars, Map inputs, PropertySet ps) throws WorkflowException
完成工做流的transation。
4. public WorkflowStore getWorkflowStore() throws StoreException
得到工做流初始化类。
1. Step:工做流所在的位置,整个工做流的步骤,也能够是一系列工做中的某个工做,好比某个审批流程中的文件交到某个领导处审批,此过程可能包括接收秘书 交来的文件、而后阅读、提出本身的意见、签字、叫给秘书继续处理,这整个过程能够是一个Step。但并非FSM中的Status。
2. Status:某个Step的状态,每一个Step能够有多个Status。好比上例中阅读,等待提意见,等待签字,等待交秘书处理,都是Step的状态。 Step+Status共同组成了工做流的状态,也就实现了FSM中的Status。Step的Status在OSWorkflow中就是一段文本,状态 的判断其实就是自定义的一段文本的比较,很是灵活。
3. Action:形成工做流状态转换的动做,好比”阅读文件“动做,形成了工做流状态从”领导审批+等待阅读"转换成“领导审批+等待提出意见”。因为工做流的状态是Step+Status,因此Action能够形成Stats的变化,也能够形成Step的变化。
4. Result:工做流状态的转换,也就是Action形成的结果。也就是FSM中的Transition。每一个Action中至少包含一个 unconditional result和包含0或多个conditional result,Result的优先级顺序是 第一个符合条件的conditional result > 其余符合条件的conditional result > unconditional result。
5.Split/Join:字面意思就能够解释。Split能够产生多个unconditional result;而Join能够判断多个Step的状态,若是都知足条件的时候,Join产生一个unconditional result。能够用来实现其余工做流产品定义中的同步区的做用,好比一个投标文件的评标过程,分别要在技术方面和商务方面对标书进行评分,这样就可使 用Split将工做流分开进入商务评标组和技术评标组分别进行评标,当两个评标过程都完成后使用Join将两个流程合并,并对两个评标作的评分进行汇总。
6.External Functions:执行的功能和动做。任何的工做流引擎都要与实际的业务操做相结合,External Functions就是OSWorkflow中执行业务操做的部分,好比审批流程中,领导填写意见后将领导的意见更新到业务数据库中的过程。 Functions有两种类型,pre step function和post step function,分别发生转移前和发生转移后执行。Functions能够被定义到Step中和Action中。
7.Trigger Functions,一种不是定义在Action中的Function,依靠计划自动执行。
8.Validators:用来检验用户输入是否符合条件,只有符合条件,Action对应的转移才能执行,若是不符合条件,返回InvalidInputException异常。
配置OSWorkFlow经过Hibernate持久化
1.修改WEB-INF/classes/目录下的osworkflow.xml,改成
2.将下面的Hibernate.cfg.xml加到WEB-INF/classes/下面,这里使用mysql数据库。
3.把hibernate的jar及hibernate全部要到的jar,到WEB-INF/lib/
4.OSWorkflow要求客户端提供SessionFactory,自主控制session和transaction。在容器里能够直接生成 SessionFactory而后注入到workflow中。这里只是演示,因此直接修改.jsp文件,生成SessionFactory,传入 workflow中。
5.基本搞定。