osworkflow学习笔记2-标签

 
一、Step,Status ,Action
Step
大致相当于流程所在的位置。譬如企业年检,年检报告书在企业端算一个step,在工商局算第二个step,在复核窗口算第三个step。
每个step可以有多种状态(status)和多个动作(action),用Workflow.getCurrentSteps()可以获得所有当前的step
(如果有并列流程,则可能同时有多个step,例如一次年检可能同时位于“初审”step和“广告经营资格审查”step)。

 Status
流程在某个step中的状态。很容易理解,譬如“待认领”、“审核不通过”之类的。OSWorkflow中的状态完全是由开发者自定义的,
状态判别纯粹是字符串比对,灵活性相当强,而且可以把定义文件做得很好看

Action
导致流程状态变迁的动作。一个action典型地由两部分组成:可以执行此动作的条件(conditions),以及执行此动作的结果(results)。
条件可以用BeanShell脚本来判断,因此具有很大的灵活性,几乎任何与流程相关的东西都可以用来做判断。
有的时候,我们需要一些动作可以基于一些条件自动地执行。为了达到这个目的,你可以在action中加入auto="true"属性。流程将考察这个动作的条件和限制,如果条件符合,那么将执行这个动作。Auto action是由当前的调用者执行的,所以将对该动作的调用者执行权限检查。

二、Results, Joins, and Splits
执行动作后的结果。这是个比较重要的概念。result分为两种,conditional-result和unconditional-result。执行一个动作之后,
首先判断所有conditional-result的条件是否满足,满足则使用该结果;如果没有任何contidional-result满足条件,
则使用unconditional-result。一个result也就是通过一系列指示来告诉osworkflow下一步的任务是干什么。这种调用使得产生变迁进而从一个state到另外一个state。这种概念是在UML的状态机里有讲,希望了解状态机相关概念的可以到UML相关书籍中查看。
(1)unconditional-result需要指定两部分信息:old-status,表示“当前step的状态变成什么”;
后续状态,可能是用step+status指定一个新状态,也可能进入split或者join。 对于每个action,要求至少存在一个Unconditional  result。
(2)Conditional result是unconditional result的一种扩展。不同的地方在于他需要一些子元素:condition。用and 和 or来标志各个condition之间的关系。

Conditional 和unconditional 的最终result可以产生三种效应或者说是结果:
流程的切分和融合。很简单的概念,split提供多个result;join则判断多个current step的状态,提供一个result。
普遍的,一个split或者join不能result出另外一个split或join。
1、  一个新的step/status
<unconditional-resultold-status="Finished" step="2" status="Underway"owner="${someOwner}"/>
如果状态不是Queued的话,那么第三个必要条件就是新步骤的所有者(owner)。除了可以指明下一个状态的信息之外,result也可以指定validators和 post-functions,这将在下面讨论。
2、  一个split,出现一或多个step/status
<unconditional-resultsplit="1"/>
...
<splits>
  <split id="1">
    <unconditional-resultold-status="Finished" step="2" status="Underway" owner="${someOwner}"/>
    <unconditional-resultold-status="Finished" step="2" status="Underway" owner="${someOtherOwner}"/>
  </split>
</splits>
3、  一个join,一个新的step/status
Joins是比较复杂的用例。一个典型的join看起来大致如下:
<!-- for step id 6 ->
<unconditional-result join="1"/>
...
<!- for step id 8 ->
<unconditional-result join="1"/>
...
<joins>
  <join id="1">
    <join id="1">
    <conditions type="AND">
      <condition type="beanshell">
        <arg name="script">
          "Finished".equals(jn.getStep(6).getStatus()) && "Finished".equals(jn.getStep(8).getStatus())
        </arg>
      </condition>
    </conditions>
  </join>
  <unconditional-result old-status="Finished" status="Underway" owner="test" step="2"/>
  </join>
</joins>
上面这段代码中最需要关心的就应该是jn。当join实际发生的时候,这个特殊的变量jn可以被用来建立表达式。本质上,可以很容易理解出这个段
xml的意思就是:当step6和8都finish时候在此处进行join。
 
三、Conditions
在BSF和Beanshell的script中,有一个特别的对象叫做"jn"。这个变量是com.opensymphony.workflow.JoinNodes类的一个实例,被用于join-conditions中。除此之外,conditions与functions的不同在于,conditions必须返回一个true或false的值。
这个值可以是一个"true"或"false"的字串,也可以是一个"true"或"false"的布尔值,甚至是一个含有toString()的函数,其返回值为"true"或"false"的对象。

Condition必须被conditions包含成为其子元素。Conditions有一个属性type。可以为and或者or。
And表示所有condition元素必须都为true或者false。Or表示只要有一个condition元素为true。
如果你想要更复杂的逻辑判断,那么你就要自己考虑可以嵌套conditions或者使用Condition或ConditionRemote接口、BeanShell或者是BSF来实现。如果只有一个condition子元素的时候,conditions的type属性值可以省略。

下面是OSWorkflow自带的一些标准的conditions:
  --OSUserGroupCondition     - 使用OSUser来判断调用者是否在参数"group"中。
  --StatusCondition                - 判断当前步骤的状态是否与参数"status"相同。
  --AllowOwnerOnlyCondition - 如果调用者是指定的步骤的所有者的话,那么只返回true,如果没有指明步骤的话,就返回当前步骤。
  --DenyOwnerCondition        - 与AllowOwnerOnlyCondition功能相反。

Common actions and global actions主要作用在于在工作流定义文件中能够避免代码重复。
基本思想就是简单。这两种actions是在最开始就进行说明的,在initial-actions元素后面。
这两处还不能完全理解好!
Common actions:在最开始定义好,可以在其他地方如此引用
<common-action id="100" /> 例如一个“send mail”的action
Global actions:不同之处在于显式的被某一个step引用。它通常对所有的steps都是可用的。如:“终止工作流”,在任何一步,都有可能终止工作流
需要注意的是:这两种actions要具备唯一的ID,而不能和其他action的ID重复。
 

四、 Functions
Osworkflow用function来定义商业逻辑和一些需要定义执行的服务。用functions标签来表示。两种functions(pre和post)
1.Pre 是在工作流进行某个变迁之前需要被执行的。一个比较好的例子:为了在result中state变更产生,而先建立caller。
2.Post是在之后执行的。如当某一个state改变后,发送一email到某处。

Functions可以在两个分别的地方被指定:steps和actions。
1.functions被定义在action中。在action中定义的Pre-functions是指在该动作发生之前要执行的函数。当工作流发生切换的时候,函数用来做某些事情,不管是发送E_mail也好,还是为以后的使用设置变量。
2.functions被定义在step中的时候,用途就有点不同了。在step中定义的Pre-functions是指在切换到这个step之前要执行的函数。
注意:这些函数将被应用到这个步骤的所有的切换,即使是由于这个步骤本身发起的切换,例如:在同一个步骤内,由Queued状态转移到Underway状态时,也将调用所有的 Pre functions。与此相同,在step中的Post functions将在流程离开这个步骤之前。
一个function:用来返回一个用以被其他普通对象能够容易访问得到的对象。尤其是指workflow 的实体类。返回的对象类型不闲典型的例子如:
document,metadata,issue,task等。非常便利。

接下来主要讲解关于function的四种情况:
osworkflow中的function就是可以在变迁之前或者后进行执行的内容。
1、java functions  基于java的functions从classloader中加载java 类,通过jndi找会java类,远程ejbs,本地ejb。
这一类型的function必须实现接口:com.opensymphony.workflow.FunctionProvider,在这个接口中有一个方法execute。这个方法(execute)需要三个参数
可以自己去查api即可找到这三个参数,两个map一个propertyset
基于java的functions在以下类型是可用的。
(1)class 对于一个class function,classloader必须能够知道你的function的类名。如下:
<function type="class">
      <arg name="class.name">com.acme.FooFunction</arg>
      <arg name="message">The message is ${message}</arg>
</function>
(2)jndi function与 class想类似,当然必须已经确实存在于jndi树中,在这里,需要一个jndi.location来进行配置:
<function type="jndi">
      <arg name="jndi.location">java:/FooFunction</arg>
      <arg name="message">The message is ${message}</arg>
</function>
(3)remote-ejb这部分跳过
<function type="remote-ejb">
      <arg name="ejb.location">java:/comp/env/FooEJB</arg>
      <arg name="message">The message is ${message}</arg>
</function>
(4)local-ejb跳过
<function type="local-ejb">
      <arg name="ejb.location">java:/comp/env/FooEJB</arg>
      <arg name="message">The message is ${message}</arg>
</function>

2、  beanshell function  osworkflow支持beanshell,这是一种脚本语言。可以在http://www.beanshell.org/来查看beanshell的相关内容。
在这种情况下,需要将xml过程定义中的type设置成beanshell。另外还需要有个一个参数名字为script的参数,此参数值是实际需要被执行的。
例如:
<function type="beanshell">
      <arg name="script"> 
            System.out.println("Hello, World!");
      </arg>
</function>
三种变量:entry,context,store
entry:实现com.opensymphony.workflow.spi.WorkflowEntry并且表示工作流实例。
Context:com.opensymphony.workflow.WorkflowContext。允许beanshell functions回滚事务或者确定caller的name
Store:com.opensymphony.workflow.WorkflowStore。允许function访问工作流的持久存储层。
<function type="beanshell">
      <arg name="script"> 
            propertySet.setString("world", "Earth");
      </arg>
</function>
<function type="beanshell">
      <arg name="script"> 
            System.out.println("Hello, "+propertySet.getString("world"));
      </arg>
</function>
输出结果是“hello,earth”因为任何存储在propertyset中的变量将可以在整个工作流中被持久使用。

3、  BSF function(perlscript, vbscript, javascript)除了上面说过的两种type的function。还有bsf类型的function。
BSF(bean scripting framework)是IBM的一个组织做的一个通用环境可以使用VBScript, Perlscript, Python, and JavaScript
<function type="bsf">
      <arg name="source">foo.pl</arg>
      <arg name="row">0</arg>
      <arg name="col">0</arg>
      <arg name="script">
            print $bsf->lookupBean("propertySet").getString("foo");
      </arg>
</function>
个人觉得这部分可以先跳过去,知道有这么一回事就可以了。

4、  Utility Function 可以到api的com.opensymphony.workflow.util这部分查看。下面只是列出一些主要的功能。相当于java.util里的东西。
主要用于创建动态的工作流定义,主要是包括一些实用功能,如caller、webworkexecutor、ejbinvoker、jmsmessage、mostrecentowner、schedulejob、unschdulejob、sendmail。
这部分碰到不懂就去查api是个好办法,这里就不去多写的。

    Trigger Functions
TriggerFunctions与其他函数一样,不同点在于他们不是与一个动作相联系的。他们也是通过一个唯一的ID来标识。这些函数通常是运行在系统级用户或非正规用户的环境中。Trigger functions是通过OSWorkflow的API来使用。

五、Validators
是用来校验一个动作的输入的有效性的。如果输入符合条件,那么将执行这个动作。如果输入不符合条件,那么将抛出InvalidInputException异常。
与functions类似,osworkflow有下面几种不同形式的validators:java-based,beanshell,和bsf。
Java-based的validators必须实现com.opensymphony.workflow.Validator接口(如果是remote-ejb,则需实现com.opensymphony.workflow.ValidatorRemote接口)。
Java-based这种情况是通过抛出个InvalidInputException异常表明一个输入是不合法的,并且停止工作流action。
在beanshell和bsf中,有一点小小不同,即使异常可以在脚本中抛出,但是不能抵达到jre。所以在beanshell和bsf中用错误信息来完成。逻辑如下:
      如果返回值是一个InvalidInputException对象,这个对象立刻抛出到client。
      如果返回值是一个map,map被用做一个error/errormessage对。
      如果返回值是一个String [],偶数字被做为key。奇数做为value来构造一个map
      其他情况,把值转换成string并且作为一个普通的错误信息来添加。
 
六、Registers
OSWorkflow中的Register是一个运行时的变量,它能够动态的注册到workflow的定义文件中。Registers在很多场合都是很有用的。
被注册的对象可以是任何类型,典型的注册对象的例子是:Document, Metadata, Issue, 和Task。
例如:你想提供让workflow在它的描述符文件中就能访问一个实体的方法。这时,你就可以定义一个Register来封装这个实体。如果这个实体是一个本地的sessionEJB的话,你就要使用com.opensymphony.workflow.util.ejb.local.LocalEJBRegister注册类。例如,在后面的post-function中,你就可以访问这个实体,并且可以通过beanshell script来调用这个实体中的方法。

Registers也有三种实现方式:Java-based, BeanShell和BSF.
1. Java-based registers  必须实现com.opensymphony.workflow.Register接口
   本地的session EJB的话,你就要使用com.opensymphony.workflow.util.ejb.local.LocalEJBRegister注册类
   远程ejb的话,实现com.opensymphony.workflow.RegisterRemote接口
2. BeanShell and BSF registers       通过script返回的值或对象将是你注册的对象。
注:在registers的接口中,你只需要一个args Map参数就行了,这是因为registers的调用根本不管用户的输入。
3. 例子:
下面的例子将说明register的功能和用途。在这里register被用于一个简单的日志register,它有一个可访问的变量"log",这个log变量可以在可以在整个工作流的生命期内被访问。日志记录器可以做很多有用的工作,比如说将工作流的实例id加入到日志记录中。我们在workflow的描述符文件的顶层定义register。
<registers>
    <register type="class" variable-name="log">
      <arg name="class.name">com.opensymphony.workflow.util.LogRegister</arg>
      <arg name="addInstanceId">true</arg>
    </register>
</registers>
从代码中可以看到,我们创建了一个名为log的LogRegister,还指定了一个值为true的参数addInstanceId。
我们可以在workflow描述符文件中的任何地方使用这个变量。例如:
<function type="beanshell" name="bsh.function">
  <arg name="script">transientVars.get("log").info("function called");</arg>
</function>
上面的函数将输出"function called",同时在输出前附加了workflow的实例id。
  
  <registers>
       <register name="doc" class="com.acme.DocumentRegister"/>
  </registers>
  <results>
       <result condition="doc.priority == 1" step="1" status="Underway"  owner="${someManager}"/>
       <unconditional-result step="1" status="Queued"/>
  </results>

七. Variable Interpolation
在所有的functions、conditions、validators和registers中,可能要提供一系列的参数。这些参数将会被转化为参数Map,这将在后面讨论。同样,在workflow描述符中的status,old-status和owner标签也将被动态的解析成变量。一个变量是这样被识别的:${foo}。当OSWorkflow识别出这种格式的时候,它首先到transientVars中去找关键字为foo的对象,如果没有找到,那么就到propertySet中去找,如果也没找到,那么变量foo将被转换为一个空字串。
<argname="foo">${someDate}</arg>
<argname="bar"> ${someDate} </arg> <!-- 注意多余的空格 -->
 
八. Integrating with Abstract Entities
建议在你的核心实体中,例如"Document" 或 "Order",在内部创建一个新的属性:workflowId。这样,当新的"Document" 或 "Order"被创建的时候,它能够和一个workflow实例关联起来。那么,你的代码可以通过OSWorkflow API查找到这个workflow实例并且得到这个workflow的信息和动作。

九. Workflow Instance State
有的时候,为整个workflow实例指定一个状态是很有帮助的,它独立于流程的执行步骤。OSWorkflow提供一些workflow实例中可以包含的"meta-states"。这些"meta-states"可以是CREATED, ACTIVATED, SUSPENDED,KILLED 和 COMPLETED。当一个工作流实例被创建的时候,它将处于CREATED状态。然后,只要一个动作被执行,它就会自动的变成ACTIVATED状态。如果调用者没有明确地改变实例的状态,工作流将一直保持这个状态直到工作流结束。当工作流不可能再执行任何其他的动作的时候,工作流将自动的变成COMPLETED状态。
 
然而,当工作流处于ACTIVATED状态的时候,调用者可以终止或挂起这个工作流(设置工作流的状态为KILLED或 SUSPENDED)。一个终止了的工作流将不能再执行任何动作,而且将永远保持着终止状态。一个被挂起了的工作流会被冻结,他也不能执行任何的动作,除非它的状态再变成ACTIVATED。
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值