概述
本文基于jBPM 5.2.x分析jBPM 5jbpm-human-task 部分源代码,我们之所以选择jBPM 5.2.x是由于jBPM 5.2.x是有对应企业版本的BRMS,该代码是被Red Hat维护更新,经常企业版本BRMS5.3的patch等是基于此进行的。
jBPM 5.2.x代码链接:https://github.com/droolsjbpm/jbpm/tree/5.2.x
本处源代码分析基于: https://github.com/droolsjbpm/jbpm/tree/5.2.x/jbpm-human-task
https://github.com/droolsjbpm/jbpm/tree/5.2.x/jbpm-human-task-war
org.jbpm.task.service.jms
org.jbpm.task.service.jms下定义了JMS作为执行human task的类,我们依次来看这些类。
org.jbpm.task.service.jms.JMSTaskServer
我们先来看JMSTaskServer类图:
org.jbpm.task.service.TaskServer定义的start()方法JMSTaskServer进行了实现,JMSTaskServer实现的start()方法主要逻辑是初始化JMS相关的MessageConsumer,QueueSession,QueueConnection等,MessageConsumer基于服务器接收queue。顺序大致如下:
通过JNDI查询获取QueueConnectionFactory,通过QueueConnectionFactory创建QueueConnection,通过QueueConnection创建QueueSession,通过QueueSession创建MessageConsumer,如果初始化成功,则认为TaskServer运行状态为true,相关代码段如下:
如下:
QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup(connFactoryName);
try {
this.connection = factory.createQueueConnection();
this.session = connection.createQueueSession(transacted, ackMode);
this.queue = this.session.createQueue(queueName);
this.responseQueue = this.session.createQueue(responseQueueName);
this.consumer = this.session.createConsumer(this.queue);
this.connection.start();
} catch (JMSException e) {
throw new RuntimeException("No se pudo levantar la cola servidora del JMSTaskServer", e);
}
this.running = true;
JMSTaskServer只定义一个构造方法,如下:
public JMSTaskServer(TaskService service, Properties connProperties, Context context) {
super(new JMSTaskServerHandler(service, SystemEventListenerFactory.getSystemEventListener()), connProperties, context);
}
构造方法中参数:
- service - 用来创建服务器端处理器JMSTaskServerHandler
- connProperties - 定义初始化JMS发送消息相关的Session,Producer,Consumer等参数,如队列名字等
- context - 定义JNDI的上下文,用来查询QueueConnectionFactory
另为JMSTaskServer实现Runnable,run()方法的实现如下:
public void run() {
try {
start();
while (this.running) {
Message clientMessage = this.consumer.receive();
if (clientMessage != null) {
Object object = readMessage(clientMessage);
String selector = readSelector(clientMessage);
this.handler.messageReceived(this.session, object, this.responseQueue, selector);
}
}
} catch (JMSException e) {
if ("102".equals(e.getErrorCode())) {
logger.info(e.getMessage());
} else {
logger.error(e.getMessage());
}
} catch (Exception e) {
throw new RuntimeException("Error leyendo mensaje", e);
}
}
该部分代码大致逻辑是接收到一条消息后,JMSTaskServerHandler的messageReceived方法被调运。org.jbpm.task.service.jms.JMSTaskServerHandler类图如下:
messageReceived方法实现如下:
public void messageReceived(QueueSession session, Object message, Destination destination, String selector) throws Exception {
String name = "";
if (destination instanceof Queue) {
name = ((Queue) destination).getQueueName();
} else if (destination instanceof Topic) {
name = ((Topic) destination).getTopicName();
}
MessageProducer producer = (MessageProducer) this.producers.get(name);
if (producer == null) {
producer = session.createProducer(destination);
this.producers.put(name, producer);
}
this.handler.messageReceived(new JMSSessionWriter(session, producer, selector), message);
}
此处理的结果是将结果发送到responseQueue,这一过程是在JMSSessionWriter的write()方法中,JMSSessionWriter的类图如下:
JMSSessionWriter实现org.jbpm.task.service.SessionWriter,其中write()方法如下:
public void write(Object message) throws IOException {
try {
ObjectMessage clientMessage = this.session.createObjectMessage();
clientMessage.setObject((Serializable) message);
clientMessage.setStringProperty(TaskServiceConstants.SELECTOR_NAME, this.selector);
this.producer.send(clientMessage);
} catch (JMSException e) {
throw new IOException("Unable to create message: " + e.getMessage());
} finally {
try {
if(this.session.getTransacted()) {
this.session.commit();
}
} catch (JMSException e) {
throw new IOException("Unable to commit message: " + e.getMessage());
}
}
}
}
org.jbpm.task.service.TaskClient
TaskClient实现了接口org.jbpm.task.AsyncTaskService,相关类图 jbpm_source_taskclient.png。
TaskClient 提供了一系列方法用来管理Human Task的生命周期,这些方法包括:
void start(long taskId, String userId, TaskOperationResponseHandler responseHandler);
void stop(long taskId, String userId, TaskOperationResponseHandler responseHandler);
void suspend(long taskId, String userId, TaskOperationResponseHandler responseHandler);
void release(long taskId, String userId, TaskOperationResponseHandler responseHandler);
void remove(long taskId, String userId, TaskOperationResponseHandler responseHandler);
void resume(long taskId, String userId, TaskOperationResponseHandler responseHandler);
void skip(long taskId, String userId, TaskOperationResponseHandler responseHandler);
所有这些方法都有如下参数:
- taskId - Task的ID,这个ID是通过JPA数据库自动产生的,我们是通过查取数据库得到Task,然后从中获取此ID
- userId - 这是指执行Task的用户ID,通常我们是在流程设计时设计定义,流程执行时通过此来获取Task
- responseHandler - jBPM中执行Human Task,与Task Service的交互是异步的,所以我们需要返回处理器当返回结果可达时获取返回结果
When a message is invoked on the TaskClient, a message is created that will be sent to the server, and the server will execute the logic that implements the correct action.
我们会在后面的系列给出一个使用TaskClient操作改变Task生命周期的例子,具体链接:http://blog.csdn.net/kylinsoong/article/details/17040793#t4
org.jbpm.task.Task
org.jbpm.task.Task为数据库层模型,我们知道jBPM 执行Human Task时需要将数据存储与数据库,jBPM 通过JPA/Hibernate来实现这一功能,jBPM 数据模型主要包括两类实体:
- Task实体 - 代表Human Task的主要信息
- deadline, escalation, 和 notification实体 - 代表 执行Human Task时的相关deadline, escalation,已经与deadline, escalation相关的notification
相关类图: jbpm_source_task.png
另为i18ntext 和 organizationalentity也是主要数据模型的实体:
i18ntext实体- 代表与语言相关的文本存储,例如用户输入的名字,描述等
organizationalentity实体 - 代表一个用户
我们会在后面的系列给出一个数据模型明细相关的实验,具体链接:http://blog.csdn.net/kylinsoong/article/details/17040793#t3
org.jbpm.task.service.TaskService
org.jbpm.task.service.TaskService用来在执行Human Task时操作数据库,其中TaskSessionFactory包括JPA EntityManager,org.jbpm.task.service.TaskService所提供的构造方法如下:
public TaskService(EntityManagerFactory emf, SystemEventListener systemEventListener) {
initialize(emf, systemEventListener, null);
}
public TaskService(EntityManagerFactory emf, SystemEventListener systemEventListener, EscalatedDeadlineHandler escalationHandler) {
initialize(emf, systemEventListener, escalationHandler);
}
org.jbpm.task.service.TaskService相对应的类图 jbpm_source_taskservice.png