zhangv on November 25th, 2008

之前用jPDL时候有一个头疼的地方是界面的整合开发。jPDL designer可以生成jsf的界面(但因为对jsf的敬畏而没有去进一步考证),后来看到liferay里的一种做法是给任务节点上定义一些页面元素,比如 username:text, password:password, gender:checkbox(M,F)…记得不太清楚了,但是意思就是把一些关于界面的参数放到流程定义里,再通过工具来生成相应的页面。思路比较清楚,也比较简单。
后来了解了一些XUL的东西,觉得似乎这些界面参数也可以用XUL来定义,相对标准化一点,而且也容易扩展。标准化的优点就是每个人都可以写自己的XUL解析和界面生成引擎,或者有统一的引擎可以用。
先YY记录下来。

Continue reading about jPDL和XUL结合

zhangv on October 16th, 2008

seven forms of bpm - after read
use case 1:bpm as a disciplinerefers to the analysis, documentation and improvement of the procedures thatdescribe how people and systems work together in an organization.In the context of BPM as a discipline, we believe that a process modelfrom a non technical business analyst can never be translated into an […]

Continue reading about seven forms of bpm - after read

zhangv on April 15th, 2008

在jbpm中,如果action可以配置为异步执行
<action class=”ActionClassName” async=”true”></action>
如果是异步action,那么在flow执行到action所依附的节点时,会保存一个job,然后交由单独的job执行线程处理.源代
码:
GraphElement.java的executeActions方法:
if (action.isAsync()) {
ExecuteActionJob job = createAsyncActionExecutionJob(executionContext.getToken(), action);
MessageService messageService = (MessageService) Services.getCurrentService
(Services.SERVICENAME_MESSAGE);
messageService.send(job);
} else {
executeAction(action, executionContext);
}
这个job保存到数据库,并由JobExecutor去执行.
而jobExecutor在默认情况下是不会被启用的,需要手动启用或者配置为自动启动的servlet(JobExecutorServlet).
手动启动通过这个方法:
JbpmConfiguration.startJobExecutor()
还需要做的工作,在jbpm.cfg.xml里定义一个jobExecutor
<bean name=”jbpm.job.executor” class=”org.jbpm.job.executor.JobExecutor” singleton=”true” />
如果不用JbpmConfiguration应该也可以启动.做的事都是一样的,创建一个新的JobExecutor然后启动线程.只是猜测,没试过.
在3.1的数据库里是没有job的表的,升级到3.2.2后才有这个表.

Continue reading about [源码研究]jbpm中的异步Action

zhangv on April 2nd, 2008

今天在整合jbpm时遇到这样一个错误can‘t create process instance when processdefinition is null
因为使用了subprocess,跟进源代码看了一下:(我用的是springmodules整合jbpm和spring)
发现子流程实例无法创建,因为没有context(JbpmContext).问题最终归结在怎样启动流程实例.原来的做法是:
ProcessDefinition pd = jbpmTemplate.getProcessDefinition();
ProcessInstance pi = new ProcessInstance(pd,variables);
pi.getRootToken().signal();
这样启动,如果没有子流程是没问题的.但是如果有了子流程,ProcessState(子流程state)会通过当前JbpmContext
去启动子流程.而上面这种做法是没有JbpmContext的!正确的做法是:
jbpmTemplate.execute(new JbpmCallback(){
public Object doInJbpm(JbpmContext context) throws JbpmException {
HashMap<String,Object> variables = new HashMap<String, Object>();
ProcessInstance pi = new ProcessInstance(jbpmTemplate.getProcessDefinition()
,variables);
pi.getRootToken().signal();
return null;
}
});
这种做法会初始化一个新的context然后启动流程.问题解决.但要注意设置subprocess的属性binding=”late”.如下:
<process-state name=”V3-sub-process” >
<sub-process name=”V3″ binding=”late”></sub-process>
<variable access=”read,write” name=”objType”></variable>
<variable access=”read,write” name=”objId”></variable>
<transition to=”tradeMatch”></transition>
</process-state>
意味着subprocess不是在初始化父流程时就初始化(findSubprocess),而是在processState.execute时候才初始化(这个时候才有context).如果不加binding=”late”,还是会有同样的错误.
另:在网上找解决方法时候发现,这个issue.貌似目前springmodules0.8不支持context外包含子流程的流程实例创建.所以做法应该是没错的.check过了,0.9也没有支持

Continue reading about 使用springmodules启动子流程的问题

zhangv on January 19th, 2008

基于自己目前对jBPM的了解,发现使用jBPM做为工作流引擎时流程可以通过jPDL很方便的定义和发布。主要的工作来自于界面的定制,因为觉得 想要做一个通用的jBPM界面简直是不可能(或者是我目前的思路有问题),每个流程的流程meta是没问题,比方说把transition定义为一个 button然后去调用webcontroller,但是业务meta就不行了,某个字段可能需要显示为一个dropdown而不是文本框。尽管jPDL designer可以生成form但也只能生成比较简单的文本框和按钮,而且是基于jsf。
偶然中发现了liferay中对jPDL的扩展恰好是我想要的,增加了表单数据类型的定义
每个node的变量定义为:
text:username
textarea:introduction
checkbox:married:yes,no
“liferay的workflow portlet对jbpm的变量定义经行了扩展,可以看到每个变量的名字都由多部分组成其中用冒号分隔,workflow portlet会根据变量的前缀自动为该变量生成html中的表单。”
现在扩展是扩展了,但是如果想要加入业务规则呢?试试另一种思路:业务数据是在流在工作流上的,那么在不同的流程阶段(phase)要满足不同的业 务规则。这里就有一个问题了,规则是应该作为流程的一部分还是作为数据的一部分,显然应该是流程的一部分。但流程怎么能够知道这些meta(某个数据在某 个节点上要怎么显示并满足哪些规则)呢 ?(其实这些东西早就有现成的产品了。比如PEGA)这个时候就又需要扩展jPDL了。
考虑怎么去扩展jPDL:每个流程应该有一个flowBean的model,他可能包含很多其他的业务数据对象,这样每个流程所要操作的数据就都在 这个flowBean里,而规则和显示则要定义到流程的每个节点。有点类似JPF(java page flow,weblogic portal用的webmvc)。
先想到这里,以后再补充。

Continue reading about jPDL的扩展思考

zhangv on January 6th, 2008

今天发现在创建一个task实例之后,数据库中会出现两个task记录,不同的只是其中一个的issignaling是r,另一个是null.而且这两个使用的也是同一个token.查看jBPM的手册中的task management发现这样解释的:
A signalling task instance is a task instance that, when completed, can send a signal to its token to continue the process execution. Task instances can be blocking, meaning that the related token (=path of execution) is not allowed to leave the task-node before the task instance is completed. By default task instances are […]

Continue reading about jBPM中task的signalling和blocking属性

zhangv on January 5th, 2008

其实也还是hibernate得性能测试.不过为了满足boss的要求,还是写了一个测试.
启动20个线程,每个形成使用JbpmContext生成1000个ProcessInstance,然后遍历每个节点.
测试结果: 每个线程所需时间范围是360 - 420 s
用jconsole看了一下,瓶颈主要在网络读取(jdbc driver的socketread)和连接池等待(waiting available, checkout)上 .
import java.io.FileNotFoundException;
import java.io.IOException;
import org.jbpm.JbpmContext;
import org.jbpm.JbpmException;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.taskmgmt.exe.TaskInstance;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.util.Log4jConfigurer;
import org.springmodules.workflow.jbpm31.JbpmCallback;
import org.springmodules.workflow.jbpm31.JbpmTemplate;
import com.jpmchase.zpcclass.common.util.SpringUtils;
import com.jpmchase.zpcclass.workflow.service.WorkFlowService;
public class JbpmScalTest {
static {
SpringUtils.initFromClasspath(new String[]{”com/jpmchase/zpcclass/applicationContext*.xml”});
try {
Log4jConfigurer.initLogging(”classpath:com/jpmchase/zpcclass/log4j.properties”);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
WorkFlowService wfs;
private JbpmTemplate jbpmTemplate;
@Before
public void setUp() throws Exception {
wfs = (WorkFlowService) SpringUtils.getBean(”workFlowService”);
jbpmTemplate = (JbpmTemplate) SpringUtils.getBean(”jbpmTemplate”);
}
@After
public void tearDown() throws Exception {
}
public static void […]

Continue reading about jBPM的性能测试

zhangv on November 27th, 2007

ZhangV
在jbpm的流程定义文件(processdefinition.xml)中当定义一个task的assignment的时候有几种选择:

Swimlane

Pooled Actors

Expression

Actor

Handler

这里分别描述一下每种的用法,以及使用场景。使用场景的理解很重要,只有清楚每一种用法的所适合的情形,以及他们之间的相互转换才能说是真的“会用了”。
Swimlane
可以理解为角色,这里是指这个流程中的参与者或者角色。在实际的业务系统中,他可能根本就不是一个业务角色,可能是一个外部应用,也可能是一个处理过程,或者是几个业务角色的结合。所以要清楚他是指“在该流程中”的角色。在jPDL的user guide中写的很清楚也反复强调 - “process role”。
通过在流程定义文件中定义:
<swimlane name=”leader”>
<assignment class=”com.modofo.engine.swimlane.LeaderSwimlane”></assignment>
</swimlane>
同样可以实现运行时的结合实际应用进行灵活的任务分配。这也是目前我看到的使用比较多的方式。
Actor
相当于设置TaskInstance的actorId属性,主要用于获取某个actor的所有任务列表。设置方法在定义中描述actor-id属性,或者调用TaskInstance.setActorId(String)方法,或者在AssignmentHandler中调用assignable.setActorId(String)方法。
Pooled Actors
用于定义所有的任务参与人(candidates for task instance)。在查找某个参与者可参与的任务时使用,其实就是一个actor的集合,jBPM通过TaskMgmtSession.findPooledTaskInstances(String actorId)或者TaskMgmtSession.findPooledTaskInstances(List actorIds) 来查找任务集合。
注意:actor的优先级比pooled actors要高,所以如果同时设置两者,那jBPM只会用actor来查找,而忽略pooled actors。
一句话: actor被用来获取某个参与者的个人任务列表,pooled actors用来获取某个参与者可以参与的所有任务列表,或者说组任务列表。
使用这个actor集合的初衷就是为了不让任务分配和角色体系耦合。流程定义中始终都是只有参与者的名称和集合,而不存在用户,角色和用户组的具体设计。而使用Expression就耦合了这些信息在流程定义里。
Expression
如果你使用jBPM的identity component的话。你可以使用表达式定义的任务分配模式。通常这个表达式的形式是:
<assignment expression=’previous –> group(hierarchy) –> member(boss)’ />
我看了之后也不是很清楚,group和member是jBPM的identity componenet的概念,这个表达的意思大概是:使用之前的actor,然后在hierarchy组,并且member(角色)是boss的所有actor。这种方法仅限于使用jBPM的IC时使用。
Handler
指定你自己的AssignmentHandler实现。该接口只有assign方法。这种任务分配方式主要用于运行时的任务分配,而不是hardcode到定义文件里。使用场景,如果不想让原本应用中的访问控制与jBPM耦合起来,就可以使用这种方法来将jBPM中的任务分配代理出来。当然更好的定义是用swimlane,这样可以让定义文件看起来不是很凌乱。

Continue reading about jBPM中的assignment