浅谈jbpm流程收回和回退的控制方法(二:分支流程的控制)
(本篇文章的回退实现,是建立在前一篇文章提到的功能实现之上,重复的地方不在详说了)
终于有一天,一个同事跑来告诉我,流程回退功能出问题了,并告诉我他用了分支节点.看来又到了解事实真相,解决问题的时候了.先画个流程草图.
a---b---fork---d---join---f---g
\ /
c-------e
经过测试发现对分支的回退会出现两个问题:
1.当流程执行到分支内节点时(d,c,e),如果要退回到b任务,并把分支内的任务关闭掉,当再次进入分支节点后,流程就只能运行到join节点,不能到达F.
2.当流程执行到F时,如果要将流程回退到一个分支内的任务上(d,c,e),流程就也只能运行到join节点,不能再到达F.
看来只是开关一下任务实例,再把令牌指到fork是不能实现涉及分支的回退功能.其根本原因就是我们没有对分支中的子令牌进行控制.所以我们先简单的分析jbpm分支的具体实现.
当流程执行到fork时,会根据分支的个数创建几个子令牌(本例是创建2个),子令牌会各自流转,直到到达join节点.join节点会检查子令牌是否都到达join节点,如果是就流转主令牌到点一个节点,如果不是就继续等待其他子令牌.完成这个逻辑主演是依靠Token的isAbleToReactivateParent属性来完成这个功能.isAbleToReactivateParent这个属性的含义可以理解成,当前持有这个属性的子令牌是否可以激活(恢复)其父令牌.所以这个属性只有分支的子令牌才具有.
isAbleToReactivateParent在fork创建分支令牌为true,当子令牌到达join是会被设为false.具体说一下过程(详细的可以看看join的execute方法)每一个子令牌到达join节点,都会触发join的execute方法.该方法的第一步就是检测子令牌的isAbleToReactivateParent是否为true,不是ture你这个子令牌就什么都别想干了.当为true时子令牌才有权尝试(仅仅是尝试)驱动一下父令牌.
子令牌过这第一关,isAbleToReactivateParent就会被赋值false.(每个子令牌只有一次机会去见他的父亲)下面还要过好多关(这里就不详细说了,和本文无关了,主要还是检测子令牌能不能驱动主令牌).所有的关卡都通过,终于来到他伟大的父令牌面前了,呵呵.这时这个父令牌会找到他的全部儿子,检查儿子们的isAbleToReactivateParent属性是否都为fasle(看看还有没有想见他的儿子).如果还有为true的子令牌,说明还有儿子没来那.父令牌会等待他来.要是全为fasle.那就是全部儿子都见过父亲了,父令牌就可以说白白了,奔向下一个节点.
不小心编了故事讲完了.下面我们分析一下最开始出现的两个问题:
1.当流程执行到分支内节点时(d,c,e),如果要退回到b任务,并把分支内的任务关闭掉,当再次进入分支节点后,流程就只能运行到join节点,不能到达F是问什么那 . 在这里虽然我们关闭里分支内的任务,但没有让两个子令牌放弃见他们老爸的想法.所以当你再次由b进入分支时.又创建了两个子令牌.这个老爸现在有4个儿子了.其中先前的两个儿子想见老爸.却永远都见不到,父令牌会在join那一个劲的等啊等.你流程就跟着一起等吧.所以要从分支往分支外跳的时候,除了杀掉任务,也别忘了让子令牌放弃见老爸的想法.isAbleToReactivateParent=false.
2.当流程执行到F时,如果要将流程回退到一个分支内的任务上(d,c,e),流程就也只能运行到join节点,不能再到达F . 这个就很好解释了,你从f跳会分支里.历史任务开启.要命的是这个任务上的子令牌不想见父令牌(此时isAbleToReactivateParent=false).这个子令牌到了join那,第一关都过去.怎么有机会让他老爸走人那.所以,开启分支里的任务时,不要忘记将该任务的令牌属性isAbleToReactivateParent=true.这样他才能见到父令牌让他走人.
匆忙中,写完了这个文章.会有不详尽,而表达啰嗦的地方.如果有疑问.我会回答补充.另外在查看join节点代码时,发现有个nOutOfM属性,应该是在定义流程模板的时候可以定义,这个属性可以设定一个值,代表.有一个令牌到达join后就可以驱动父令牌了,如果是nOutOfM=3,那就是有3个分支线到达就可以驱动父令牌.要是用分支做会签,这个属性是比较有用的,