最近也在osworkflow的学习,也试着想写一篇关于它的详细介绍,突发现了该篇文章,现转载

工作流简介:
1. 工作流是业务流程的全部或部分自动化,在此过程中,文档、信息或任务按照一定的过程规则流转,实现组织成员间的协同工作,以达到业务的整体目标。
2. 工作流治理系统是支持企业经营过程高效执行并监控其执行过程的计算机软件系统
3. 典型的WFMS至少由如下几个模块组成:业务流程建模定义工具、过程定义、工作流执行环境(引擎)、任务治理。当然还会包括应用和IT工具
4. 目前开源工作流项目众多(shark、osworkflow、jbpm、ofbiz、werkflow、willow……)


OSWorkflow简介:
1. Osworkflow与目前绝大多数的工作流系统是不同的,而最大的不同点体现在它的韧性上和灵活程度上 。osworkflow所提供的解决方案能够提供足够的灵活度来满足一个大型各种应用的所有需求。
2. OSWorkflow是只是一个workflow engine的内核体。我们都说osworkflow非常的易扩展,但是这也同样说明了,用osworkflow去实现一个能够运行的工作流系统是非常繁琐的事情。 
§Osworkflow 的api部分将会支持jdk1.3+
3. 工作流的持久存储(memorystore(默认)自带的例子就是如此,SerializableStore,JDBCStore,ofbizstore,和EJBStore. )另外还可以自己实现。
4. 工作流定义部分(核心)通过osworkflow自带例子理解
   主要是osworkflow.XML 、workflows.xml以及***.xml文件
5. OSWorkflow是基于FSM(finite state machine,有限状态机)理论。

OSWorkFlow基本概念:
1. 在商用和开源世界里,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 文件解释工作流业务流程。

OSWorkFlow核心概念:
步骤(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),动作将会使一个步骤的状态发生改变。

OSWorkFlow包用途分析及代码片断
4.1.    com.opensymphony.workflow
该包为整个OSWorkflow 引擎提供核心接口。例如 com.opensymphony.workflow.Workflow 接口,可以说,实际开发中的大部分工作都是围绕该接口展开的,该接口有 BasicWorkflow、EJBWorkflow、OfbizWorkflow 三个实现类。
4.2.    com.opensymphony.workflow.basic
该包有两个类,BasicWorkflow 与 BasicWorkflowContext。BasicWorkflow 不支持事务,尽管依赖持久实现,事务也不能包裹它。BasicWorkflowContext 在实际开发中很少使用。

public void setWorkflow(int userId) {
    Workflow workflow = new BasicWorkflow(Integer.toString(userId));
}

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

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

public String findNameByStepId(int stepId,String wfName) {
    WorkflowDescriptor wd = workflow.getWorkflowDescriptor(wfName);
    StepDescriptor stepDes = wd.getStep(stepId);
    return stepDes.getName();
}
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 方法来得到最终查询结果。

public List queryDepAdmin(int userId,int type) {
    int[] arr = getSubPerson(userId,type);
   
    //构造表达式
    Expression[] expressions = new Expression[1 + arr.length];
    Expression expStatus = new FieldExpression(FieldExpression.STATUS,
    FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, "Queued");
    expressions[0] = expStatus;
   
    for (int i = 0; i < arr.length; i++) {
        Expression expOwner = new FieldExpression(FieldExpression.OWNER,
        FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS,
        Integer.toString(arr[i]));
        expressions[i + 1] = expOwner;
    }

    //查询未完成流编号
    List wfIdList = null;
    try {
        WorkflowExpressionQuery query = new WorkflowExpressionQuery(
        new NestedExpression(expressions, NestedExpression.AND));
        wfIdList = workflow.query(query);
    } catch (Exception e) {
        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。

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 的支持。
Osworkflow api 基本
§sworkflow提供了集中工作流实现方式:
   BasicWorkflow
   EJBWorkflow
   Ofbizworkflow
§创建新的工作流实例,执行action
   Workflow workflow = new BasicWorkflow("testuser");
   DefaultConfiguration config = new DefaultConfiguration();
   workflow.setConfiguration(config);
   long workflowId = workflow.initialize("mytest", 1, null);
   workflow.doAction(workflowId, 1, null);
api-abstractworkflow:

§osworkflow中有关工作流流转的所有核心代码都在AbstractWorkflow中,BasicWorkflow就是派生自它,可以从AbstractWorkflow派生自己的Workflow类以加入扩展功能
§最重要的方法doAction
§其他主要功能:Initialize、executeFunction、众多get方法、query、state相关、等等
api-配置文件相关:

§Configuration实例负责系统配置的加载。AbstractWorkflow会调用其load方法,该方法内部会查找一个名为osworkflow.XML的配置文件,并对其解析。
§WorkflowFactory包括XMLWorkflowFactory 、JDBCWorkflowFactory、URLWorkflowFactory,作用即是加载各个不同的工作流定义,维护一个map。
§WorkflowLoader的作用实现配置文件的读取
§WorkflowDescriptor的作用将平面的xml流转化为osworkflow内部所使用的具有真正意义的对象。
§其他不同的descriptor,如(step、action…………)之间的关系。
其他不同的descriptor,如(step、action…………)之间的关系。
api-查询:

§目的:希望了解流程当前的运行状况à查询
§WorkflowQuery及其相关类(query包)
§ WorkflowQuery queryLeft = new WorkflowQuery(
  WorkflowQuery.OWNER, WorkflowQuery.CURRENT, WorkflowQuery.EQUALS, “test");
WorkflowQuery queryRight = new WorkflowQuery(
  WorkflowQuery.STATUS, WorkflowQuery.CURRENT, WorkflowQuery.EQUALS, “Underway");
WorkflowQuery query = new WorkflowQuery(
  queryLeft, WorkflowQuery.AND, queryRight);
List workflows = wf.query(query);
for (Iterator iterator = workflows.iterator(); iterator.hasNext();)
  Long wfId = (Long) iterator.next();
}
§AbstractWorkflow导向workflowstore进行实际查询,最后将查询结果存储与arraylist中
§目的:希望了解流程当前的运行状况à查询
§WorkflowQuery及其相关类(query包)
§ WorkflowQuery queryLeft = new WorkflowQuery(
  WorkflowQuery.OWNER, WorkflowQuery.CURRENT, WorkflowQuery.EQUALS, “test");
WorkflowQuery queryRight = new WorkflowQuery(
  WorkflowQuery.STATUS, WorkflowQuery.CURRENT, WorkflowQuery.EQUALS, “Underway");
WorkflowQuery query = new WorkflowQuery(
  queryLeft, WorkflowQuery.AND, queryRight);
List workflows = wf.query(query);
for (Iterator iterator = workflows.iterator(); iterator.hasNext();)
  Long wfId = (Long) iterator.next();
}
§AbstractWorkflow导向workflowstore进行实际查询,最后将查询结果存储与arraylist中
api-用户治理:

§OSWorkflow在用户治理方面所提供的功能,主要包括用户的创建、群组的定义、用户验证、以及对step执行人的跟踪记录和执行权限的判定等等
§用户/群组的治理是由UserManager来完成的
§代码中具体讲解
代码中具体讲解
osworkflow任务治理:

§OSWorkflow引擎只负责了“流程的运转”,当然这个运转会根据你所定义的Action和condtion来判定。
§Condition—条件判定
§Function(pre and post)--Step、action、result执行过程需要调用的功能
§FunctionProvider接口、execute方法
§<step id="4" name="Assign">
§      <pre-functions>
§        <function type="class">
§      <arg name="class.name">nUCleus.assign.AssignmentFunction</arg>
§      <arg name="Participant">A</arg>
§      <arg name="ParticipantType">role</arg>
          <arg name="actionID">22</arg>
§        </function>
§      </pre-functions>
§      <actions>
§         ••••••
§      </actions>
§    </step>
    </step>
osworkflow的schedule:

§定时执行某项任务的功能,Quartz
§<function type="class">
 <arg name="class.name">com.opensymphony.workflow.util.ScheduleJob</arg>
 <arg name="triggerId">1</arg>
 <arg name="jobName">testJob</arg>
 <arg name="triggerName">testTrigger</arg>
 <arg name="groupName">test</arg>
 <arg name="repeat">10</arg>
 <arg name="repeatDelay">2000</arg>
 <arg name="cronEXPression">0,5,10,15,20,25,30,35,40,45,50,55 * * * * ?</arg>
 <arg name="username">test</arg>
 <arg name="passWord">test</arg>
 <arg name="local">true</arg>
 <arg name="schedulerStart">true</arg>
</function>
§Trigger和jobDetail,trigger触发条件满足后,则会激活真正的job实例,job实例真正执行的是trigger function(在配置文件中定义)


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    浮点值
NUMBER_VALUE    NUMBER    数字值



创建你的第一个工作流
首先,让我们来定义工作流。你可以使用任何名字来命名工作流。一个工作流对应一个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>
    <unconditional-result old-status="Finished" status="Underway" step="1"/>
  </results>
</action>
希望对于条件的理解现在已经清楚了。上面的条件定义保证了动作1只能在当前状态为“Queued”的时候才能被调用,也就是说在初始化动作被调用以后。
函数
接下来,我们想在一个用户开始撰写草稿以后,设置他为“owner”。为了达到这样的目的,我们需要做2件事情:
1) 通过一个函数设置“caller”变量在当前的环境设置里。
2) 根据“caller”变量来设置“owner”属性。
函数是OSWorkflow的一个功能强大的特性。函数基本上是一个在工作流程中的工作单位,他不会影响到流程本身。举例来说,你可能有一个“SendEmail”的函数,用来在某些特定的流程流转发生时来发送email提醒。
函数也可以用来添加变量到当前的环境设置里。变量是一个指定名称的对象,可以用来在工作流中被以后的函数或者脚本使用。
OSWorkflow提供了一些内置的常用函数。其中一个称为“Caller”,这个函数会获得当前调用工作流的用户,并把它放入一个名为“caller”的字符型变量中。
因为我们需要追踪是哪个用户开始了编写草稿,所以可以使用这个函数来修改我们的动作定义:
<action id="1" name="Start First Draft">
  <pre-functions>
    <function type="class">
      <arg name="class.name">
      com.opensymphony.workflow.util.Caller</arg>
    </function>
  </pre-functions>
  <results>
    <unconditional-result old-status="Finished"status="Underway"
    step="1" owner="${caller}"/>
  </results>
</action>
h3 组合起来
把这些概念都组合起来,这样我们就有了动作1:
<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>
  <pre-functions>
    <function type="class">
      <arg name="class.name">
        com.opensymphony.workflow.util.Caller
      </arg>
    </function>
  </pre-functions>
  <results>
    <unconditional-result old-status="Finished"status="Underway"
    step="1"  owner="${caller}"/>
  </results>
</action>
我们使用类似想法来设置动作2:
<action id="2" name="Finish First Draft">
  <restrict-to>
    <conditions type="AND">
      <condition type="class">
        <arg name="class.name">
          com.opensymphony.workflow.util.StatusCondition
        </arg>
        <arg name="status">Underway</arg>
      </condition>
      <condition type="class">
        <arg name="class.name">
          com.opensymphony.workflow.util.AllowOwnerOnlyCondition
       </arg>
      </condition>
    </conditions>
  </restrict-to>
  <results>
    <unconditional-result old-status="Finished" status="Queued" step="2"/>
  </results>
</action>
在这里我们指定了一个新的条件:“allow owner only”。这样能够保证只有开始撰写这份草稿的用户才能完成它。而状态条件确保了只有在“Underway”状态下的流程才能调用“finish first draft”动作。
把他们组合在一起,我们就有了第一个流程定义:
<?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>
    <action id="1" name="Start Workflow">
      <results>
        <unconditional-result old-status="Finished"
        status="Queued" step="1"/>
      </results>
    </action>
  </initial-actions>
  <steps>
    <step id="1" name="First Draft">
      <actions>
        <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>
          <pre-functions>
            <function type="class">
              <arg name="class.name">
                 com.opensymphony.workflow.util.Caller
              </arg>
            </function>
          </pre-functions>
          <results>
            <unconditional-result old-status="Finished" status="Underway"
            step="1"  owner="${caller}"/>
          </results>
        </action>
        <action id="2" name="Finish First Draft">
          <restrict-to>
            <conditions type="AND">
              <condition type="class">
                <arg name="class.name">
                    com.opensymphony.workflow.util.StatusCondition
                </arg>
                <arg name="status">Underway</arg>
              </condition>
              <condition type="class">
                <arg name="class.name">
                  com.opensymphony.workflow.util.
                  AllowOwnerOnlyCondition
                </arg>
              </condition>
            </conditions>
          </restrict-to>
          <results>
            <unconditional-result old-status="Finished"
            status="Queued" step="2"/>
          </results>
        </action>
      </actions>
    </step>
    <step id="2" name="finished" />
  </steps>
</workflow>
现在这个工作流的定义已经完整了,让我们来测试和检查它的运行

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值