1.OSWorkFlow基本概念
在商用和开源世界里,OSWorkflow都不同于这些已有的工作流系统。最大不同在于OSWorkflow有着非常优秀的灵活性。在开始接触OSWorkflow时可能较难掌握(有人说不适合工作流新手入门),比如,OSWorkflow不要求图形化工具来开发工作流,而推荐手工编写xml格式的工作流程描述符。它能为应用程序开发者提供集成,也能与现有的代码和数据库进行集成。这一切似乎给正在寻找快速“即插即用”工作流解决方案的人制造了麻烦,但研究发现,那些“即插即用”方案也不能在一个成熟的应用程序中提供足够的灵活性来实现所有需求。
2.OSWorkFlow主要优势
OSWorkflow给你绝对的灵活性。OSWorkflow被认为是一种“低级别”工作流实现。与其他工作流系统能用图标表现“Loops(回路)”和“Conditions(条件)”相比,OSWorkflow只是手工“编码(Coded)”来实现的。但这并不能说实际的代码是需要完全手工编码的,脚本语言能胜任这种情形。OSWorkflow不希望一个非技术用户修改工作流程,虽然一些其他工作流系统提供了简单的GUI用于工作流编辑,但像这样改变工作流,通常会破坏这些应用。所以,进行工作流调整的最佳人选是开发人员,他们知道该怎么改变。不过,在最新的版本中,OSWorkflow也提供了GUI设计器来协助工作流的编辑。

OSWorkflow基于有限状态机概念。每个state由stepID和status联合表现(可简单理解为step及其status表示有限状态机的state)。一个state到另一state的transition依赖于action的发生,在工作流生命期内有至少一个或多个活动的state。这些简单概念展现了OSWorkflow引擎的核心思想,并允许一个简单XML文件解释工作流业务流程。
3.OSWorkFlow核心概念
3.1.概念定义

步骤(Step)
一个Step描述的是工作流所处的位置。可能从一个StepTranstion(流转)到另外一个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及其StepStatus,也可能进入Split或者Join。Result分为两种,Contidional-Result(有条件结果),只有条件为真时才使用该结果,和Unconditional-Result(无条件结果),当条件不满足或没有条件时使用该结果。

分离/连接(Split/Join)
流程的切分和融合。很简单的概念,Split可以提供多个Result(结果);Join则判断多个CurrentStep的态提供一个Result(结果)。
3.2.步骤、状态和动作(Step,Status,andAction)
工作流要描述步骤(Step)、步骤的状态(Status)、各个步骤之间的关系以及执行各个步骤的条件和权限,每个步骤中可以含有一个或多个动作(Action),动作将会使一个步骤的状态发生改变。

对于一个执行的工作流来讲,步骤的切换是不可避免的。一个工作流在某一时刻会有一个或多个当前步骤,每个当前步骤都有一个状态值,当前步骤的状态值组成了工作流实例的状态值。一旦完成了一个步骤,那么这个步骤将不再是当前步骤(而是切换到一个新的步骤),通常一个新的当前步骤将随之建立起来,以保证工作流继续执行。完成了的步骤的最终状态值是用Old-Status属性指定的,这个状态值的设定将发生在切换到其他步骤之前。Old-Status的值可以是任意的,但在一般情况下,我们设置为Finished。

切换本身是一个动作(Action)的执行结果。每个步骤可以含有多个动作,究竟要载入哪个动作是由最终用户、外部事件或者Tiggerd的自动调用决定的。随着动作的完成,一个特定的步骤切换也将发生。动作可以被限制在用户、用户组或当前状态。每一个动作都必须包含一个UnconditionalResult和0个或多个ConditionalResults。

所以,总体来说,一个工作流由多个步骤组成。每个步骤有一个当前状态(例如:Queued,UnderwayorFinished),一个步骤包含多个动作。每个步骤含有多个可以执行的动作。每个动作都有执行的条件,也有要执行的函数。动作包含有可以改变状态和当前工作流步骤的results。
3.3.结果、分支和连接(Results,Joins,andSplits)
3.3.1.无条件结果(UnconditionalResult)
对于每一个动作来讲,必须存在一个UnconditionalResult。一个result是一系列指令,这些指令将告诉OSWorkFlow下一个任务要做什么。这包括使工作流从一个状态切换到另一个状态。
3.3.2.有条件结果(ConditionalResult)
ConditionalResult是UnconditionalResult的一个扩展。它需要一个或多个Condition子标签。第一个为true的Conditional(使用AND或OR类型),会指明发生切换的步骤,这个切换步骤的发生是由于某个用户执行了某个动作的结果导致的。
3.3.3.三种不同的Results(conditionalorunconditional)
一个新的、单一的步骤和状态的组合。
一个分裂成两个或多个步骤和状态的组合。
将这个和其他的切换组合成一个新的单一的步骤和状态的组合。
每种不同的result对应了不同的xml描述,你可以阅读
http://www.opensymphony.com/osworkflow/workflow_2_7.dtd,获取更多的信息。
注意:通常,一个split或一个join不会再导致一个split或join的发生。
3.4.自动步骤(Autoactions)
有的时候,我们需要一些动作可以基于一些条件自动地执行。为了达到这个目的,你可以在action中加入auto="true"属性。流程将考察这个动作的条件和限制,如果条件符合,那么将执行这个动作。Autoaction是由当前的调用者执行的,所以将对该动作的调用者执行权限检查。
3.5.整合抽象实例(IntegratingwithAbstractEntities)
建议在你的核心实体中,例如"Document"或"Order",在内部创建一个新的属性:workflowId。这样,当新的"Document"或"Order"被创建的时候,它能够和一个workflow实例关联起来。那么,你的代码可以通过OSWorkflowAPI查找到这个workflow实例并且得到这个workflow的信息和动作。
3.6.工作流实例状态(WorkflowInstanceState)
有的时候,为整个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在实际开发中很少使用。

publicvoidsetWorkflow(intuserId){
Workflowworkflow=newBasicWorkflow(Integer.toString(userId));
}

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

publicvoidsetWorkflow(intuserId){
Workflowworkflow=newBasicWorkflow(Integer.toString(userId));
}
4.4.com.opensymphony.workflow.ejb
该包有两个接口WorkflowHome和WorkflowRemote。该包的若干类中,最重要的是EJBWorkflow,该类和BasicWorkflow的作用一样,是OSWorkflow的核心,并利用EJB容器管理事务,也作为工作流sessionbean的包装器。
4.5.com.opensymphony.workflow.loader
该包有若干类,用得最多的是XxxxDescriptor,如果在工作流引擎运行时需要了解指定的动作、步骤的状态、名字,等信息时,这些描述符会起到很大作用。

publicStringfindNameByStepId(intstepId,StringwfName){
WorkflowDescriptorwd=workflow.getWorkflowDescriptor(wfName);
StepDescriptorstepDes=wd.getStep(stepId);
returnstepDes.getName();
}
4.6.com.opensymphony.workflow.ofbiz
OfbizWorkflow和BasicWorkflow在很多方面非常相似,除了需要调用ofbiz的TransactionUtil来包装事务。
4.7.com.opensymphony.workflow.query
该包主要为查询而设计,但不是所有的工作流存储都支持查询。通常,Hibernate和JDBC都支持,而内存工作流存储不支持。值得注意的是Hibernate存储不支持混合型查询(例如,一个查询同时包含了historystep上下文和currentstep上下文)。执行一个查询,需要创建WorkflowExpressionQuery实例,接着调用Workflow对象的query方法来得到最终查询结果。

publicListqueryDepAdmin(intuserId,inttype){
int[]arr=getSubPerson(userId,type);

//构造表达式
Expression[]expressions=newExpression[1+arr.length];
ExpressionexpStatus=newFieldExpression(FieldExpression.STATUS,
FieldExpression.CURRENT_STEPS,FieldExpression.EQUALS,"Queued");
expressions[0]=expStatus;

for(inti=0;i<arr.length;i++){
ExpressionexpOwner=newFieldExpression(FieldExpression.OWNER,
FieldExpression.CURRENT_STEPS,FieldExpression.EQUALS,
Integer.toString(arr[i]));
expressions[i+1]=expOwner;
}

//查询未完成流编号
ListwfIdList=null;
try{
WorkflowExpressionQueryquery=newWorkflowExpressionQuery(
newNestedExpression(expressions,NestedExpression.AND));
wfIdList=workflow.query(query);
}catch(Exceptione){
e.printStackTrace();
}
}
4.8.com.opensymphony.workflow.soap
OSWorkflow通过SOAP来支持远端调用。这种调用借助WebMethods实现。
4.9.com.opensymphony.workflow.spi
该包可以说是OSWorkflow与持久层打交道的途径,如当前工作流的实体,其中包括:EJB、Hibernate、JDBC、Memory、Ofbiz、OJB、Prevayler。

HibernateWorkflowEntryhwfe=(HibernateWorkflowEntry)getHibernateTemplate()
.find("fromHibernateWorkflowEntrywhereId="
+wfIdList.get(i)).get(0);
4.10.com.opensymphony.workflow.util
该包是OSWorkflow的工具包,包括了对BeanShell、BSF、EJBLocal、EJBRemote、JNDI的支持。
5.OSWorkFlow表结构分析
5.1.OS_WFENTRY
工作流主表,存放工作流名称和状态

字段名数据类型说明
IDNUMBER自动编号
NAMEVARCHAR2(20)工作流名称
STATENUMBER工作流状态

5.2.OS_CURRENTSTEP
当前步骤表,存放当前正在进行步骤的数据

字段名数据类型说明
IDNUMBER自动编号
ENTRY_IDNUMBER工作流编号
STEP_IDNUMBER步骤编号
ACTION_IDNUMBER动作编号
OWNERVARCHAR2(20)步骤的所有者
START_DATEDATE开始时间
FINISH_DATEDATE结束时间
DUE_DATEDATE授权时间
STATUSVARCHAR2(20)状态
CALLERVARCHAR2(20)操作人员的帐号名称

5.3.OS_CURRENTSTEP_PREV
前步骤表,存放当前步骤和上一个步骤的关联数据

字段名数据类型说明
IDNUMBER当前步骤编号
PREVIOUSNUMBER前步骤编号

5.4.OS_HISTORYSTEP
历史步骤表,存放当前正在进行步骤的数据

字段名数据类型说明
IDNUMBER自动编号
ENTRY_IDNUMBER工作流编号
STEP_IDNUMBER步骤编号
ACTION_IDNUMBER动作编号
OWNERVARCHAR2(20)步骤的所有者
START_DATEDATE开始时间
FINISH_DATEDATE结束时间
DUE_DATEDATE授权时间
STATUSVARCHAR2(20)状态
CALLERVARCHAR2(20)操作人员的帐号名称

5.5.OS_HISTORYSTEP_PREV
前历史步骤表,存放历史步骤和上一个步骤的关联数据

字段名数据类型说明
IDNUMBER当前历史步骤编号
PREVIOUSNUMBER前历史步骤编号

5.6.OS_PROPERTYENTRY
属性表,存放临时变量

字段名数据类型说明
GLOBAL_KEYVARCHAR2(255)全局关键字
ITEM_KEYVARCHAR2(255)条目关键字
ITEM_TYPENUMBER条目类型
STRING_VALUEVARCHAR2(255)字符值
DATE_VALUEDATE日期值
DATA_VALUEBLOB数据值
FLOAT_VALUEFLOAT浮点值
NUMBER_VALUENUMBER数字值