天天看点

写一个简单的工作流(四)资源的处理

昨天晚上搞到深夜,终于将资源模块搞定。到今天已经完成的功能包括:

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