在osworkflow中最最核心的東西就是工作流定義的xml文件。盡管它并不是一定要定義成xml文件。但是xml格式是一種標準的通用的格式。OSWorkflow引擎只負責了“流程的運轉”,當然這個運轉會根據你所定義的Action和condtion來判斷。
這個xml文件為某一個給定的工作流進行描述steps、states,transitions,和functionality。下面闡述一下此xml的一般規則:
1、 一個工作流由多個steps組成
2、 對于每個step,可以包括多個actions。一個action可以被設置成自動運行或者需要通過人工交互才可以運行。
3、 每個action都要包括至少一個unconditional result和0或多個conditional results。
4、 如果設定了多個concitioanl results,所有當中的第一個將被執行,如果沒有設定conditional results或者沒有conditions滿足,那么執行unconditional result
5、 一個result過后可能依舊停留在當前的step中,一個新的step,一個split,一個join。在所有的情形中,工作流的state跟著變化(例子工作流中的states分別為:Underway,Queued,和finished)
6、 如果一個result引起一個split,這個result會指定split的屬性,以指向一個split元素。
7、 一個split可以有一個或者多個unconditional results,但是沒有conditional results。Unconditional results。Unconditional results需要指定steps。
8、 一個propertyset是一個持久層數據的map,在全局應用中都是可用的。
9、 還有一種叫做transientVars的map,它只存活于一個工作流調用過程中的一定的生命周期,它將會對所有functions和conditions,包括所有的registers,user input,以及工作流上下文狀態等起作用。
工作流概念:
下面開始理解osworkflow的核心概念:
對于step,status,actions部分就不多說明了,其實我覺得理解概念的最快方法應該是參照實例,即使我們不能用高高大大的詞匯描繪出來,能自己理解是什么意思就可以了。
Unconditional result 和 conditional results
這里做以簡單介紹,對于每個action,要求至少存在一個Unconditional result,一個result也就是通過一系列指示來告訴osworkflow下一步的任務是干什么。這種調用使得產生變遷進而從一個state到另外一個state。這種概念是在UML的狀態機里有講,希望了解狀態機相關概念的可以到UML相關書籍中查看。
Conditional result是unconditional result的一種擴展。不同的地方在于他需要一些子元素:condition。用and 和 or來標志各個condition之間的關系。
Conditional 和unconditional 的最終result可以產生三種效應或者說是結果:
1、 一個新的step/status
2、 一個split,出現一或多個step/status
3、 一個join,一個新的step/status
普遍的,一個split或者join不能result出另外一個split或join。
一個step/status result可以按下面方式簡單的設定:
<unconditional-result old-status="Finished" step="2"
status="Underway" owner="${someOwner}"/>
從一個state split 到多個 states可以按以下方式達到:
<unconditional-result split="1"/>
...
<splits>
<split id="1">
<unconditional-result old-status="Finished" step="2"
status="Underway" owner="${someOwner}"/>
<unconditional-result old-status="Finished" step="2"
status="Underway" owner="${someOtherOwner}"/>
</split>
</splits>
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
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中
Functions部分:
Osworkflow用function來定義商業邏輯和一些需要定義執行的服務。用functions標簽來表示。
兩種functions(pre和post)
Pre 是在工作流進行某個變遷之前需要被執行的。一個比較好的例子:為了在result中state變更產生,而先建立caller。
Post是在之后執行的。如當某一個state改變后,發送一email到某處。
Functions可以在兩個分別的地方被指定:steps和actions。
Trigger Functions
Trigger和jobDetail,trigger觸發條件滿足后,則會激活真正的job實例,job實例真正執行的是trigger function(在配置文件中定義)
Validators
Registers
一個function:用來返回一個用以被其他普通對象能夠容易訪問得到的對象。尤其是指workflow 的實體類。返回的對象類型不閑典型的例子如:document,metadata,issue,task等。非常便利。
<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>
Conditions
變量
授權與限權
自動執行的action
設置auto=true
Common and global actions:
Common和globalactions的主要作用在于在工作流定義文件中能夠避免代碼重復。
基本思想就是簡單。這兩種actions是在最開始就進行說明的,在initial-actions元素后面。
這兩處還不能完全理解好!
Common actions:在最開始定義好,可以在其他地方如此引用
<common-action id="100" />
例如一個“send mail”的action
Global actions:不同之處在于顯式的被某一個step引用。它通常對所有的steps都是可用的。一個例子:“終止工作流”,在任何一步,都有可能終止工作流。
需要注意的是:這兩種actions要具備唯一的ID,而不能和其他action的ID重復。
接下來主要講解關于function的四種情況:
osworkflow中的function就是可以在變遷之前或者后進行執行的內容。
1、 基于java的functions
從classloader中加載java 類,通過jndi找會java類,遠程ejbs,本地ejb。
這一類型的function必須實現接口:com.opensymphony.workflow.FunctionProvider,在這個接口中有一個方法execute。這個方法(execute)需要三個參數 可以自己去查api即可找到這三個參數,兩個map一個propertyset
public interface FunctionProvider { public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException;
}
所有的Function實現類都必須實現這個FunctionProvider接口中execute方法,而且能夠處理的信息,也全部來自這個方法中的三個參數:
transientVars |
這個是最為核心的參數,記錄非常重要的一些對象,比如WorkflowContext,WorkflowEntry,輸入參數等等。 |
args |
這個是function配置中的arg參數,具體請參考osworkflow dtd |
ps |
是PropertySet對象,記錄了流程實例所需要保存的數據,可以理解成osworkflow所描述的流程相關數據。 |
具體transienVars中包含哪些對象,請參考 FunctionProvider api doc。
下面就說說如何利用Function進行任務的分配。
個人建議你在Step的pre-function中做處理,配置如下:
<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> </function> </pre-functions> <actions> ······ </actions> </step> |
看了這個配置形式,大家應該明白如何去處理。你可以在function中獲取自己所定義的角色、根據角色獲取人員、根據人員產生workitem······ 。你在function 所作的這一切操作對osworkflow engine來說都是透明的—— 你所產生的worklist所代表的含義只有你自己知道。
其中我為什么會附加了一個arg屬性:actionID?這是因為我需要告訴每一個workitem在其應該處理哪一個動作。 因為外部程序都是通過Workflow.doAction(long, int, java.util.Map)
這個接口來激活流程的運轉或改變實例的狀態。
基于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
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,這是一種腳本語言??梢栽?/SPAN>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是個好辦法,這里就不去多寫的。
osworkflow的schedule:
定時執行某項任務的功能
<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>
validators:
與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中用錯誤信息來完成。邏輯如下:
u 如果返回值是一個InvalidInputException對象,這個對象立刻拋出到client。
u 如果返回值是一個map,map被用做一個error/errormessage對。
u 如果返回值是一個String [],偶數字被做為key。奇數做為value來構造一個map
u 其他情況,把值轉換成string并且作為一個普通的錯誤信息來添加。
Registers:
Register是一個在工作流定義文件中用來動態注冊的運行時(塊)
它也是和validators,functions差不多,都是能夠以java-based,beanshell和bsf不同格式出現。
Conditions:
Conditions與osworkflow小小不相似之處在于:在bsf或者beanshell腳本中,有一個額外的對象叫做“jn”。這個jn來源于com.opensymphony.workflow.joinnodes。它的作用就是連接條件(join-conditions)。除此之外,condition必須有一個返回值(true or false)。
Condition必須被conditions包含成為其子元素。Conditions有一個屬性type。可以為and或者or。And表示:所有condition元素必須都為true或者false。Or表示只要有一個condition元素為true。如果你需要更多復雜的condition邏輯。可以考慮實現condition或者conditionremote接口,beanshell,bsf。如果只有一個condition子元素的時候,conditions的type屬性值可以省略。
在2.7中??梢郧短?/SPAN>conditions,這樣可以讓你實現更為復雜的商業邏輯。
下面是一個寫標準的conditions
OSUserGroupCondition、StatusCondition、AllowOwnerOnlyCondition、DenyOwnerCondition
Soap支持,暫時略!因為暫時可能涉及不到!
Gui Designer部分略。
(申明:本文來源于網絡,摘錄于此,僅為日后方便查看)