天天看點

寫一個簡單的工作流(四)資源的處理

昨天晚上搞到深夜,終于将資源子產品搞定。到今天已經完成的功能包括:

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