OSWorkFlow 学习

Posted dy9776

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OSWorkFlow 学习相关的知识,希望对你有一定的参考价值。

1.OSWorkFlow基本概念

 


    在商用和开源世界里,OSWorkflow 都不同于这些已有的工作流系统。最大不同在于 OSWorkflow 有着非常优秀的灵活性。在开始 接触 OSWorkflow 时可能较难掌握(有人说不适合工作流新手入门),比如,OSWorkflow 不要求图形化工具来开发工作流,而推荐手工编 写 xml 格式的工作流程描述符。它能为应用程序开发者提供集成,也能与现有的代码和数据库进行集成。这一切似乎给正在寻找快速“即插即用”工作流解决 方案的人制造了麻烦,但研究发现,那些“即插即用”方案也不能在一个成熟的应用程序中提供足够的灵活性来实现所有需求。


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 文件解释工 作流业务流程。

3.    OSWorkFlow核心概念

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(结果)。


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)


3.3.1.    无条件结果(Unconditional Result)
对于每一个动作来讲,必须存在一个Unconditional Result。一个result是一系列指令,这些指令将告诉OSWorkFlow下一个任务要做什么。这包括使工作流从一个状态切换到另一个状态。

 

3.3.2.    有条件结果(Conditional Result)
Conditional Result是Unconditional Result的一个扩展。它需要一个或多个Condition子标签。第一个为 true的Conditional(使用AND或OR类型),会指明发生切换的步骤,这个切换步骤的发生是由于某个用户执行了某个动作的结果导致的。


3.3.3.    三种不同的Results(conditional or unconditional)
一个新的、单一的步骤和状态的组合。
一个分裂成两个或多个步骤和状态的组合。
将这个和其他的切换组合成一个新的单一的步骤和状态的组合。
每种不同的result对应了不同的xml描述,你可以阅读http://www.opensymphony.com/osworkflow/workflow_2_7.dtd,获取更多的信息。
注意:通常,一个split或一个join不会再导致一个split 或 join的发生。

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 在实际开发中很少使用。

[java] view plain copy
 
 print?
  1. public void setWorkflow(int userId) {  
  2. Workflow workflow = new BasicWorkflow(Integer.toString(userId));  
  3. }  



4.3.    com.opensymphony.workflow.config
该包有一个接口和两个该接口的实现类。在 OSWorkflow 2.7 以前,状态由多个地方的静态字段维护,这种方式很方便,但是有很多缺陷和约束。 最主要的缺点是无法通过不同配置运行多个 OSWorkflow 实例。实现类 DefaultConfiguration 用于一般的配置文件载入。 而 SpringConfiguration 则是让 Spring 容器管理配置信息。

[java] view plain copy
 
 print?
  1. public void setWorkflow(int userId) {  
  2. Workflow workflow = new BasicWorkflow(Integer.toString(userId));  
  3. }  

 


4.4.    com.opensymphony.workflow.ejb
该包有两个接口 WorkflowHome 和 WorkflowRemote。该包的若干类中,最重要的是 EJBWorkflow,该类 和 BasicWorkflow 的作用一样,是 OSWorkflow 的核心,并利用 EJB 容器管理事务,也作为工作 流 session bean 的包装器。


4.5.    com.opensymphony.workflow.loader
该包有若干类,用得最多的是 XxxxDescriptor,如果在工作流引擎运行时需要了解指定的动作、步骤的状态、名字,等信息时,这些描述符会起到很大作用。

[java] view plain copy
 
 print?
  1. public String findNameByStepId(int stepId,String wfName) {  
  2. WorkflowDescriptor wd = workflow.getWorkflowDescriptor(wfName);  
  3. StepDescriptor stepDes = wd.getStep(stepId);  
  4. return stepDes.getName();  
  5. }  

 


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 方法来得到最终查询 结果。

 

[java] view plain copy
 
 print?
  1. public List queryDepAdmin(int userId,int type) {  
  2. int[] arr = getSubPerson(userId,type);  
  3.   
  4. //构造表达式  
  5. Expression[] expressions = new Expression[1 + arr.length];  
  6. Expression expStatus = new FieldExpression(FieldExpression.STATUS,  
  7. FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, "Queued");  
  8. expressions[0] = expStatus;  
  9.   
  10. for (int i = 0; i < arr.length; i++) {  
  11. Expression expOwner = new FieldExpression(FieldExpression.OWNER,  
  12. FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS,  
  13. Integer.toString(arr[i]));  
  14. expressions[i + 1] = expOwner;  
  15. }  
  16.   
  17. //查询未完成流编号  
  18. List wfIdList = null;  
  19. try {  
  20. WorkflowExpressionQuery query = new WorkflowExpressionQuery(  
  21. new NestedExpression(expressions, NestedExpression.AND));  
  22. wfIdList = workflow.query(query);  
  23. catch (Exception e) {  
  24. e.printStackTrace();  
  25. }  
  26. }  

 

 

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。

  • 得到工作流流程实例。
  • 得到工作流实例的定义。
  • 得到工作流实例的PropertySet。
  • 得到工作流的当前Step。
  • 产生TransientVars。
  • 得到Global Actions。
  • 判断可以执行的Global Action增加到可执行Action列表中。
  • 获得当前Steps中的可执行Action并添加到可执行Action列表中。
  • 返回可执行Actions。

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)

判断工作流是不是可以转换到指定状态。

  • 不可以转换到CREATED状态。
  • CREATED,SUSPENDED可以转换到ACTIVATED状态。
  • ACTIVATED可以转换到SUSPENDED状态。
  • CREATED,ACTIVATED,SUSPENDED 可以转换到KILLED状态。

15.public void changeEntryState(long id, int newState) throws WorkflowException

转换工作流状态。

16.public void doAction(long id, int actionId, Map inputs) throws WorkflowException

执行Action。

  • 获得工作流store,和流程实例entry。
  • 判断是不是活动的工作流,不是就返回。
  • 获得工作流的定义。
  • 获得工作流当前所再Steps。
  • 获得工作流PropertySet。
  • 生成transientVars。
  • 从GlobalActions中和当前Steps的普通Actions中判断执行的Action是否试可执行的。
  • 完成Action的Transition。

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。

  • 从resulte中获得nextStep,如果为-1,nextStep为当前Step。
  • 获得定义中的owner,oldStatus,status。
  • 完成当前Step,并且将当前Step保存到历史库中。
  • 生成新的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。

DefaultConfiguration是Configuration接口的默认实现,用于初始化系统的基本配置信息。
1.public WorkflowDescriptor getWorkflow(String name) throws FactoryException
根据工作流的定义名获得工作流的定义。
2.public WorkflowStore getWorkflowStore() throws StoreException
获得配置的持久化类Store。
3.public void load(URL url) throws FactoryException
装载配置信息。
  • 得到配置文件流,并解析。
  • 获得持久化信息,包括持久化类的路径和持久化类初始化参数。
  • 获得工作流信息解析类路径,并初始化。

4. public WorkflowStore getWorkflowStore() throws StoreException

获得工作流初始化类。

XMLWorkflowFactory用于解析工作流定义xml文件,获得工作流信息。
1.public WorkflowDescriptor getWorkflow(String name) throws FactoryException
根据工作流定义名获得工作流定义。
2.public String[] getWorkflowNames()
得到所有已经定义的工作流名称。
3.public void initDone() throws FactoryException
初始化workflows.xml文件中列出的工作流定义文件信息。
osworkflow概念

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,改为

    

[xhtml] view plain copy
 
 print?
  1. <persistence class="com.opensymphony.workflow.spi.hibernate.HibernateWorkflowStore">  
  2. lt;/persistence>  

 

2.将下面的Hibernate.cfg.xml加到WEB-INF/classes/下面,这里使用mysql数据库。

 

[xhtml] view plain copy
 
 print?
  1. <?xml version=\'1.0\' encoding=\'utf-8\'?>  
  2. <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">  
  3. <hibernate-configuration>  
  4. <session-factory>  
  5. <!-- properties -->  
  6. <property name="connection.driver_class">org.gjt.mm.mysql.Driver</property>  
  7. <property name="connection.url">jdbc:mysql://redhat:3306/osworkflow</property>  
  8. <property name="connection.username">redhat</property>  
  9. <property name="connection.password">redhat</property>  
  10.   
  11.  <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>  
  12. <property name="show_sql">true</property>  
  13. <property name="use_outer_join">true</property>  
  14.   
  15.  <property name="connection.pool_size">10</property>  
  16. <property name="statement_cache.size">25</property>  
  17.   
  18.  <property name="hibernate.hbm2ddl.auto">update</property>  
  19.   
  20.  <mapping resource="com/opensymphony/workflow/spi/hibernate/HibernateCurrentStep.hbm.xml"></mapping>  
  21. <mapping resource="com/opensymphony/workflow/spi/hibernate/HibernateHistoryStep.hbm.xml"></mapping>  
  22. <mapping resource="com/opensymphony/workflow/spi/hibernate/HibernateWorkflowEntry.hbm.xml"></mapping>  
  23. <mapping resource="com/opensymphony/module/propertyset/hibernate/PropertySetItemImpl.hbm.xml"></mapping>  
  24.   
  25. </session-factory>  
  26. </hibernate-configuration>  

 

3.把hibernate的jar及hibernate所有要到的jar,到WEB-INF/lib/
4.OSWorkflow要求客户端提供SessionFactory,自主控制session和transaction。在容器里可以直接生成 SessionFactory然后注入到workflow中。这里只是演示,所以直接修改.jsp文件,生成SessionFactory,传入 workflow中。

 

[java] view plain copy
 
 print?
  1. Workflow wf = new BasicWorkflow((String) session.getAttribute("username"));  
  2.   
  3. // osworkflow和hibernate竟然都是通过Configuration类来进行配置的,没办法,谁让大家都需要进行配置而就那么几个单词呢  
  4. com.opensymphony.workflow.config.Configuration conf = new DefaultConfiguration();  
  5.   
  6.  SessionFactory sessionFactory = new net.sf.hibernate.cfg.Configuration().configure().buildSessionFactory();  
  7. conf.getPersistenceArgs().put("sessionFactory", sessionFactory);  
  8. wf.setConfiguration(conf);  

 

5.基本搞定。

 

 

OsWorkFlow工作流学习笔记

osworkflow学习笔记

 

     接口选择:
  osworkflow提供几种实现com.opensymphony.workflow.Workflow接口的类。
   
  BasicWorkflow:
  不提供事务支持,你可以通过持久层来实现事务处理。
  Workflow wf = new BasicWorkflow(username)
  这里的username是用来关联当前请求的用户。
   
  EJBWorkflow:
  用ejb容器来管理事务。在ejb-jar.xml中进行配置。
  Workflow wf = new EJBWorkflow()
  这里没有必要想basicworkflow和ofbizworkflow那样给出username。因为ejb容器已经校验过的。
   
  Ofbizworkflow:
  与basicworkflow比较相似,不同只在于需要事务支持的方法由ofbiz TransactionUtil calls来包装。
   
  创建新的工作流实例:
  这里是以basicworkflow为例子
   

  Workflow wf = new BasicWorkflow(username);
  HashMap inputs = new HashMap();
  inputs.put("docTitle", request.getParameter("title");
  wf.initialize("workflowName", 1, inputs);


   
  执行action:

  Workflow wf = new BasicWorkflow(username);
  HashMap inputs = new HashMap();
  inputs.put("docTitle", request.getParameter("title");
  long id = Long.parseLong(request.getParameter("workflowId");
  wf.doAction(id, 1, inputs);


  查询:
  值得注意的是:并不是所有的 workflow stores支持查询。当前的hibernate,jdbc和内存工作流存储支持查询。Hibernate存储不支持mixed-type查询(如,一个查询使用到了历史和当前step contexts)。为了执行一个查询,需要构造出一个WorkflowExpressionQuery对象。查询方法是在这个对象上被调用的。
  简单查询、嵌套查询、mixed-context查询(不支持hibernate工作流存储)在docs文档的5.4部分都有。
   
Step
大致相当于流程所在的位置。譬如企业年检,年检报告书在企业端算一个step,在工商局算第二个step,在复核窗口算第三个step。每个step可以有多种状态(status)和多个动作(action),用Workflow.getCurrentSteps()可以获得所有当前的step(如果有并列流程,则可能同时有多个step,例如一次年检可能同时位于“初审”step和“广告经营资格审查”step)。
 
Status
流程在某个step中的状态。很容易理解,譬如“待认领”、“审核不通过”之类的。OSWorkflow中的状态完全是由开发者自定义的,状态判别纯粹是字符串比对,灵活性相当强,而且可以把定义文件做得很好看。
 
Action
导致流程状态变迁的动作。一个action典型地由两部分组成:可以执行此动作的条件(conditions),以及执行此动作的结果(results)。条件可以用BeanShell脚本来判断,因此具有很大的灵活性,几乎任何与流程相关的东西都可以用来做判断。
 
Result
执行动作后的结果。这是个比较重要的概念。result分为两种,conditional-result和unconditional-result。执行一个动作之后,首先判断所有conditional-result的条件是否满足,满足则使用该结果;如果没有任何contidional-result满足条件,则使用unconditional-result。unconditional-result需要指定两部分信息:old-status,表示“当前step的状态变成什么”;后续状态,可能是用step+status指定一个新状态,也可能进入split或者join。
 
conditional-result非常有用。还是以年检为例,同样是提交年检报告书,“未提交”和“被退回”是不同的状态,在这两个状态基础上执行“提交”动作,结果分别是“初次提交”和“退回之后再次提交”。这时可以考虑在“提交”动作上用conditional-result。
 
Split/Join
流程的切分和融合。很简单的概念,split提供多个result;join则判断多个current step的状态,提供一个result。
 
*     *     *
 
熟悉这些概念,在流程定义中尽量使用中文,可以给业务代码和表现层带来很多方便。

 

目的
这篇指导资料的目的是介绍OSWorkflow的所有概念,指导你如何使用它,并且保证你逐步理解OSWorkflow的关键内容。

本指导资料假定你已经部署OSWorkflow的范例应用在你的container上。范例应用部署是使用基于内存的数据存储,这样你不需要担心如何配置其他持久化的例子。范例应用的目的是为了说明如何应用OSWorkflow,一旦你精通了OSWorkflow的流程定义描述符概念和要素,应该能通过阅读这些流程定义文件而了解实际的流程。

本指导资料目前有3部分:
1. 你的第一个工作流
2. 测试你的工作流
3. 更多的流程定义描述符概念


1. Your first workflow 
创建描述符
首先,让我们来定义工作流。你可以使用任何名字来命名工作流。一个工作流对应一个XML格式的定义文件。让我们来开始新建一个“myworkflow.xml”的文件,这是样板文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE workflow PUBLIC 
  "-//OpenSymphony Group//DTD OSWorkflow 2.7//EN"
  "http://www.opensymphony.com/osworkflow/workflow_2_7.dtd"> 
<workflow>
  <initial-actions>
    ...
  </initial-actions>
  <steps>
    ...
  </steps>
</workflow>
首先是标准的XML头部,要注意的是OSWorkflow将会通过这些指定的DTD来验证XML内容的合法性。你可以使用绝大多数的XML编辑工具来编辑它,并且可以highlight相应的错误。

步骤和动作
接下来我们来定义初始化动作和步骤。首先需要理解的OSWorkflow重要概念是steps (步骤) 和 actions (动作)。一个步骤是工作流所处的位置,比如一个简单的工作流过程,它可能从一个步骤流转到另外一个步骤(或者有时候还是停留在一样的步骤)。举例来说,一个文档管理系统的流程,它的步骤名称可能有“First Draft - 草案初稿”,“Edit Stage -编辑阶段”,“At publisher - 出版商”等。

动作指定了可能发生在步骤内的转变,通常会导致步骤的变更。在我们的文件管理系统中,在“草案初稿”这个步骤可能有“start first draft - 开始草案初稿”和“complete first draft - 完成草案初稿”这样2个动作。

简单的说,步骤是“在哪里”,动作是“可以去哪里”。

初始化步骤是一种特殊类型的步骤,它用来启动工作流。在一个工作流程开始前,它是没有状态,不处在任何一个步骤,用户必须采取某些动作才能开始这个流程。这些特殊步骤被定义在 <initial-actions>。

在我们的例子里面,假定只有一个简单的初始化步骤:“Start Workflow”,它的定义在里面
<initial-actions>:

<action id="1" name="Start Workflow">
  <results>
    <unconditional-result old-status="Finished" status="Queued" step="1"/>
  </results>
</action>
这个动作是最简单的类型,只是简单地指明了下一个我们要去的步骤和状态。

工作流状态
工作流状态是一个用来描述工作流程中具体步骤状态的字符串。在我们的文档管理系统中,在“草案初稿”这个步骤可能有2个不同的状态:“Underway - 进行中”和“Queued - 等候处理中”

我们使用“Queued”指明这个条目已经被排入“First Draft”步骤的队列。比如说某人请求编写某篇文档,但是还没有指定作者,那么这个文档在“First Draft”步骤的状态就是“Queued”。“Underway”状态被用来指明一个作者已经挑选了一篇文档开始撰写,而且可能正在锁定这篇文档。

第一个步骤
让我们来看第一个步骤是怎样被定义在<steps>元素中的。我们有2个动作:第一个动作是保持当前步骤不变,只是改变了状态到“Underway”,第二个动作是移动到工作流的下一步骤。我们来添加如下的内容到<steps>元素:

<step id="1" name="First Draft">
  <actions>
    <action id="1" name="Start First Draft">
      <results>
        <unconditional-result old-status="Finished"
        status="Underway" step="1"/>
      </results>
    </action>
    <action id="2" name="Finish First Draft">
      <results>
        <unconditional-result old-status="Finished"
        status="Queued" step="2"/>
      </results>
    </action>
  </actions>
</step>
<step id="2" name="finished" />这样我们就定义了2个动作,old-status属性是用来指明当前步骤完成以后的状态是什么,在大多数的应用中,通常用"Finished"表示。

上面定义的这2个动作是没有任何限制的。比如,一个用户可以调用action 2而不用先调用action 1。很明显的,我们如果没有开始撰写草稿,是不可能去完成一个草稿的。同样的,上面的定义也允许你开始撰写草稿多次,这也是毫无意义的。我们也没有做任何的处理去限制其他用户完成别人的草稿。这些都应该需要想办法避免。

让我们来一次解决这些问题。首先,我们需要指定只有工作流的状态为“Queued”的时候,一个caller (调用者)才能开始撰写草稿的动作。这样就可以阻止其他用户多次调用开始撰写草稿的动作。我们需要指定动作的约束,约束是由Condition(条件)组成。

条件
OSWorkflow 有很多有用的内置条件可以使用。在此相关的条件是“StatusCondition - 状态条件”。 条件也可以接受参数,参数的名称通常被定义在javadocs里(如果是使用Java Class实现的条件的话)。在这个例子里面,状态条件接受一个名为“status”的参数,指明了需要检查的状态条件。我们可以从下面的xml定义里面清楚的理解:

<action id="1" name="Start First Draft">
  <restrict-to>
    <conditions>
      <condition type="class">
        <arg name="class.name">
          com.opensymphony.workflow.util.StatusCondition</arg>
        <arg name="status">Queued</arg>
      </condition>
    </conditions>
  </restrict-to>
  <results>
以上是关于OSWorkFlow 学习的主要内容,如果未能解决你的问题,请参考以下文章

哪个开源工作流引擎更好?Flowable or Camunda ?

哪个开源工作流引擎更好?Flowable or Camunda ?

Java三大主流开源工作流引擎技术分析。

Java三大主流开源工作流引擎技术分析

提高阅读源代码的效率 转

camunda区分不同类型待办