创建描述符

    首先,让我们来定义工作流。你可以使用任何你想要的名字来命名工作流。工作流的定义在一个xml文件中被详细说明,每个工作流对应一个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报头(xml header),注意的是OSWorkflow将会通过这些指定的DTD来验证XML文件的正确性,因此工作流的定义必须正确,你可以使用绝大多数可以高亮显示相应的错误的工具来编辑它。

actions and steps (步骤和动作)

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

动作指定了可能在一个特殊步骤内发生的转变,动作的结果常常是步骤的一次变更。在我们的公文管理系统中,动作的例子是,在上面我们定义的草案初稿这个步骤中可能有“start first draft - 开始草案初稿“complete first draft - 完成草案初稿两个动作。

 

    简单一点,步骤是在哪里'where it is'),动作是可以去哪里'where it can go')。

 

    初始化步骤initial-actions是一种特殊类型的步骤,它被用来启动工作流。在一个工作流恰好开始的时候,没有状态(no state),不处在任何一个步骤之中,用户必须使用某些动作开始这个流程。这些可能开始工作流的步骤在 <initial-actions>中被定义。

在我们的例子中,我们假定只有一个简单的初始化动作'Start Workflow',在<initial-actions>里面添加如下动作定义:

<action id="1" name="Start Workflow">

  <results>

    <unconditional-result old-status="Finished" status="Queued" step="1"/>

  </results>

</action>

    这可能是最简单的一个动作类型,它仅仅定义了我们要去的步骤以及设置状态(status)的值。

工作流状态(Workflow status

    工作流状态是用来描述工作流中一个具体步骤的状态的字符串。在我们的文档管理系统中,“First Draft(草案初稿)这一步中可能有'Underway(进行中)''Queued(队列中)两个状态需要照料。

我们用'Queued'表示这一条目已经排入First Draft步骤中,比如说有人已经请求编写一篇详细文档,但是还没有指定作者,那么这篇文档在'First Draft'步骤中当前的状态就是'Queued''Underway'可以被用来表示一个作者已经从队列中挑选了这篇文档来写,而且可能已经锁定了它,表明他正工作在first draft步骤中。

第一个步骤(The first step

    让我们来查看在<steps>元素(element)中怎样定义第一个步骤。我们知道有两个actions(动作),第一个动作(start first draft)是保持当前步骤不变,只是把状态改变到了'Underway';第二个action(动作)使我们移动到工作流中的下一个step(步骤),也就是finished' step(步骤)。现在让我们在<steps> element(元素)中添加如下内容:

<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" />

上面我们看到了两个action(动作)是怎样被定义的。old-status attribute(属性)被用来表示当前状态完成之后在history table(历史表格)中是什么,在大多数的案例中,通常都是"Finished"

上面我们定义的两个action(动作)用途比较狭窄,比如说,一个用户在调用action 1(动作1)之前就调用了action 2,很明显,草稿尚未开始,更谈不上完成草稿了。同样的,“first draft”步骤也可能被开始好多次,那是没有意义的。最后,我们也没有采取适当的措施阻止第二个用户完成第一个用户的草稿,这也是我们应该避免的。

让我们一个个来解决这些问题。首先,我们想指定当工作流处于'Queued' state(状态)的时候,一个调用者只能开始一个草稿,这能够阻止用户多次启动first draft步骤。为实现这一目的,我们需要在action(动作)中指定一个restriction(约束),restriction由一个condition(条件)组成。

Conditions(条件)

    OSWorkflow有许多有用的内置条件可供使用,在这个例子中相关的条件是StatusCondition(状态条件)。Conditions也可以接受参数,通常在java文档里面有一个详细定义(如果条件使用java类实现的话)。在例子里面,status condition(状态条件)接受一个名为“'status'”的参数,它指定了以便condition(条件)通过的检查状态。如果我么查看定义这些条件所必需的的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>

    希望condition(条件)的概念现在是清晰的。以上条件保证了action1(动作1)只有当前状态为'Queued'的时候才能被调用,它仅仅在initial action(初始化动作)被条用之后才是正确的。

Functions(函数)

    接下来,我们想定义当一个用户开始first draft(草稿初稿)之后,把它设置为'owner'。为做到这一点,需要两件事情:

1)   一个在当前环境中设置'caller'变量的函数

2)   设置'owner'属性到'caller'变量

    函数是OSWorkflow的重要特色。函数基本上是在一个工作流变化中能够被完成的工作单位,那不会给工作流本身带来影响。例如,你可能有一个SendEmail函数,它可以用来在一些特定的变化发生的时候可靠地发出一个email通知。

    函数也可以把变量添加到当前环境中。变量是一个指定名称的、对工作流有用的、可以被以后的函数或脚本调用的对象。

    OSWorkflow提供了一些内置的有用的函数,其中一个是'Caller'函数,这个函数寻找当前调用工作流的用户,并把它放置到一个名称为'caller'string型变量中。

    既然我们想知道开始了first draft(草稿初稿)的用户,我们可以作如下修改来使用这个函数:

<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>

综合

综合以上所有想法,现在我们有了如下定义的action(动作)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>

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 ownly only',这保证了只有开始了first draft的用户才能完成它,这个状态变量也保证了只有当状态为'Underway'时,'finish first draft'才能被执行,这只有当一个用户开始了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>

   现在,工作流已经完整的定义完了,到了测试和验证它的时候了。


posted on 2006-07-17 21:47  榻榻米  阅读(305)  评论(1编辑  收藏  举报