本文基于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下定义了JMS作为执行human task的类,我们依次来看这些类。
我们先来看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); }
另为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); } }
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()); } } } }
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);
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为数据库层模型,我们知道jBPM 执行Human Task时需要将数据存储与数据库,jBPM 通过JPA/Hibernate来实现这一功能,jBPM 数据模型主要包括两类实体:
相关类图: jbpm_source_task.png
另为i18ntext 和 organizationalentity也是主要数据模型的实体:
i18ntext实体- 代表与语言相关的文本存储,例如用户输入的名字,描述等
organizationalentity实体 - 代表一个用户
我们会在后面的系列给出一个数据模型明细相关的实验,具体链接:http://blog.csdn.net/kylinsoong/article/details/17040793#t3
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); }