Bossa研究总结
胡长城(银狐999)
2004-10-10
Bossa主站点:http://www.bigbross.com/bossa/
Bossa与其说是一个workflow engine,不如说是一个Petri Net Engine。其完全采用Petri Net的Notation,定义语言也是采用WFNet PNML(WFNet是其的Net Type)。
其可以采用PNK进行模型定义,但是需要使用WFNet的PNK支持配置文件,这个Bossa提供了,但是很遗憾的是,总是造成PNK的错误,可能与文件格式和编码有关系,这个后来因为时间问题,没有继续查找具体原因。
Bossa的帮助文档非常匮乏,即使其网站上提供的how to和api文档,也仅仅只是泛泛介绍。甚至没有一个如何正确运行其所提供了example的说明。
Bossa支持的是Color Petri Net。这一点是由Case对象的attribute属性体现
Bossa的基本对象元素:
这些主要对象元素,放在 com.bigbross.bossa.wfnet 包中。
包括:CaseType,Case,Place,Transition,Edge,Activity,Workitem
|
|
|
|
CaseType
|
流程定义对象
|
|
Case
|
流程的实例
|
|
Place
|
对应于Petri Net中的元素 place
|
|
Transition
|
对应于Petri Net中的元素 transition
|
|
Edge
|
对应于Petri NetArc(有向弧)
|
|
Workitem
|
代表了一个Transtion的firing。
This class represents a transition of a specific case instance。a work item is a likely fireable transition
|
|
Activity
|
当打开一个workitem的时候就获取一个Activiy对象
This class represents an open (firing) work item
|
Bossa的token解决
Petri Net允许从一个place到transition有几个arc,来表示允许几个token。
Bossa为了解决这个问题,引入了weight这个方式。而且允许这个weight是一个javascripte计算表达式(运行期间,解析表达式,返回的值就是token的个数)。
但注意,weight本身并不是以属性存在于这些对象中,而是以方法。
List edges = activity.getTransition().getOutputEdges();
for (Iterator i = edges.iterator(); i.hasNext(); ) {
Edge e = (Edge) i.next();
/* An EvaluationException can be inconsistently thrown here. */
int tokenNumber = e.output(this);
this.marking[e.getPlace().getIndex()] += tokenNumber;
eventQueue.newPlaceEvent(getBossa(), WFNetEvents.ID_ADD_TOKENS,
this, e.getPlace(), tokenNumber);
}
Bossa的Resouce
在Bossa中,Resouce是Task(Transition)的执行者,但是其不是简单的实user的集合,在定义的时候,其表示的是一个“表达式”,而运行中,才会转换为相应得user list。
比如“sales - $a”,代表的就是,这个Task的执行者是“sales用户组中的用户 减去 a任务(Task,Transition)的执行者”。
注意,这个“表达式”,不是script的了,而是bossa自己的规则表达式。
但是,具体这个Resouce如何解析、运行。并没有深入
Bossa的引擎
Bossa的引擎类是 com.bigbross.bossa.Bossa.
其是通过BossaFactory创建的
Bossa的Workitem
注意,我们通常所理解的workitem概念,在Bossa中是不一样的。
在一个CaseType,如果存在多少个Transition,则在一个Case实例中,则存在多少个Workitem。其workitem表示的代表一个transition的firable状态。
Collection ts = caseType.getTransitions();
workItems = new HashMap(ts.size());
for (i = ts.iterator(); i.hasNext(); ) {
Transition t = (Transition) i.next();
workItems.put(t.getId(), new WorkItem(this, t, isFireable(t)));
}
这个是在Case实例初始化的时候构造workitems列表,只是其中一些workitem是fireable的,一些不是。
每一次close activity之后,会更改workitem的firable状态(主要是调用其update方法)。
Bossa的Event和Queqe
com.bigbross.bossa.notify 包提供了一种事件监听、通知的机制。
Listener
Event
NotificationBus 就是一个support类。
NotificationQueue 表示的是一个“处理队列”类,提供记录了一些需要处理的Event可能。
WFNetEvents (extends NotificationQueue)则记录了所有有关 WFNet的event事件ID,以及调用这些事件的方法。每调用一个时间处理方法,如下所示
void newCaseEvent(Bossa bossa, String notificationId, Case caze) {
if (bossa != null) {
Map attrib = new HashMap();
attrib.put(ATTRIB_CASE_ID, Integer.toString(caze.getId()));
attrib.put(ATTRIB_CASE_TYPE_ID, caze.getCaseType().getId());
addEvent(new Event(notificationId, Event.WFNET_EVENT, attrib,
bossa.getTimeSource().getTime()));
}
}
可以看出来,其是将一个event注入到NotificationQueue 所提供的queue列表中。
那么是如何执行的呢?
WFNetEvents queue = new WFNetEvents();
queue.newCaseEvent(getBossa(), WFNetEvents.ID_OPEN_CASE, caze);
queue.notifyAll(getBossa());
其最后调用notifyAll方法,来进行处理。
public void notifyAll(Bossa bossa) {
if (bossa != null) {
NotificationBus bus = bossa.getNotificationBus();
for (Iterator i = queue.iterator(); i.hasNext(); ){
Event e = (Event) i.next();
bus.notifyEvent(e);
i.remove(); } } }
到这一步,就可以很清晰的明白了吧:
整个内部还是一个“事件监听”,但是在这个事件监听外围,封装了一层“事件处理队列”。
发表于 @ 2004年10月10日 14:09:00|评论(loading...)