昨天晚上搞到深夜,終于将資源子產品搞定。到今天已經完成的功能包括:
1.四種基本路由:順序、選擇、并行、循環
2.流程定義檔案和系統配置檔案的讀取和解析
3.使用記憶體作為流程資料和案例資料存儲的memoryworkflowdao的開發
4.資源子產品的開發
5.并發情況下的正确性測試等
計劃中的功能:
1.一個gui的流程定義工具,這個不急,也還沒想好用什麼做,web還是桌面?
2.各個資料庫版本的workflowdao的開發,将流程資料和案例資料儲存在資料庫中。
3.更多的測試和example試驗。
回到資源這個概念,工作流中工作項(work item)的由資源來驅動的,這個資源(resource)可能是使用者、角色、定時時間或者某個事件消息。在标準petri網中,工作項對應于transition(變遷),變遷都是自動的,不需要所謂資源來驅動,顯然,這與工作流系統不同。具體到insect workflow(我取的名字,小巧之意),每個transition都有一個resource,用于驅動自身的firing,所有的resource都實作resource接口:
public interface resource extends serializable {
public void start(transition transition, token token, object args);
public resourcetype gettype();
public long getid();
}
每個資源都有一個類型,以及這個類型中獨一無二的id,start方法用于驅動transtion的firing。一般情況下,你不需要實作這個接口,隻要繼承這個接口的抽象實作類abstractresource,abstractresource的start方法預設實作是首先調用模闆方法doaction(稍後解釋),然後檢查觸發條件,如果通過就直接調用transition的fire方法:
public abstract class abstractresource implements resource {
public void start(transition transition, token token, object args) {
doaction(transition, token, args);
if (transition.getcondition() != null
&& !transition.getcondition().check(token))
throw new conditionexception(transition.getname()
+ " transition沒有滿足觸發條件");
transition.fire(token, args);
}
public abstract void doaction(transition transition, token token,
object
args) ;
transtion類的fire方法有三個操作組成:從輸入庫所移走token,往輸出庫所放入token,回調handler:
public void fire(token token, object
args) {
removetokenfrominputs(token);
addtokentooutputs(token);
invokehandler(token, args);
那麼具體的資源顯然要實作abstractresource中的doaction抽象方法,系統内置了五種資源:自動資源(autoresource)、使用者(user)、使用者組(group)、定時器(timerresource)和事件監聽器(observerresource)。顯然,autoresource、user和group的doaction方法不需要做任何事情:
public class user extends abstractresource {
protected group group;
@override
public void doaction(transition transition, token token, object
arg){
而timerresource就需要做特殊處理了,比如我們要達到這樣的效果:節點1狀态已經處于就緒,可以被觸發,可我們希望在就緒後延遲半分鐘再觸發,或者在晚上10點觸發等等。這樣的定時需求很常見,我采用了jdk5引入的scheduledexecutorservice來處理。系統中啟動這樣一個線程池,每個類似上面的請求都送出給這個線程池來處理,那麼timerresource就需要進行相應的修改:
public abstract class timerresource extends abstractresource {
protected int pool_size;
protected static scheduledexecutorservice scheduledexecutorservice;
public long getid() {
// todo auto-generated method stub
return common.timer_resource_id;
public timerresource() {
this.pool_size = 5;
scheduledexecutorservice = executors.newscheduledthreadpool(pool_size);
public static void shutdownpool() {
if (scheduledexecutorservice != null)
scheduledexecutorservice.shutdown();
public final void start(transition transition, token token, object
args)
throws interruptedexception {
transition.removetokenfrominputs(token);
protected class changerunner implements runnable {
private transition transition;
private token token;
private object[] args;
public changerunner(transition transition, token token, object
this.transition = transition;
this.token = token;
this.args = args;
}
public void run() {
if (transition.getcondition() != null
&& !transition.getcondition().check(token))
throw new conditionexception(transition.getname()
+ " transition沒有滿足觸發條件");
transition.addtokentooutputs(token);
object real_args[] = new object[args.length - 2];
for (int i = 0; i < real_args.length; i++)
real_args[i] = args[i + 2];
transition.invokehandler(token, real_args);
try {
// 回調
((workflowalgorithm) args[1]).enabledtraversing(token
.getworkflow());
((workflowmanager) args[0]).doaction(token.getid());
} catch (interruptedexception e) {
thread.currentthread().interrupt();
}
注意到,start方法不再是直接調用transition的fire方法,而僅僅是進行了第一步操作:移除輸入庫所的place防止重複送出。後兩步操作都延遲到了送出給線程池的任務中,也就是代碼中的changerunner類中的run方法。例如timerresource的子類delaytimerresource用于處理延遲的觸發,doaction就像這樣:
public class delaytimerresource extends timerresource {
args){
scheduledexecutorservice.schedule(new changerunner(transition, token,
args), this.delay, this.timeunit);
延遲的時間,時間機關這些資訊都可以在流程定義檔案中設定。事件監聽器資源與此類似,observerresource實作了java.util.observer接口,往輸出庫所放入token和回調handler兩步操作被放在了update方法中提供給subject回調。
文章轉自莊周夢蝶 ,原文釋出時間2007-10-13