jBPM如何自定义task

jBPM如何自定义task

1      背景

jBPM中,task表示一段业务逻辑,比如发送邮件、查询数据库等。jBPM支持的task的总类如下图所示。除此之外,jBPM支持用户自定义task,官方的叫法有domain-specific task、custom work items、custom service node。


2      例子

2.1    创建wid文件

文件的路径src/main/resources/META-INF/MyWorkDefinitions.wid。文件内容如下。

[
  // the Notification work item
  [
    "name" : "Notification",
    "parameters" : [
      "Message" : new StringDataType(),
      "From" : new StringDataType(),
      "To" : new StringDataType(),
      "Priority" : new StringDataType(),
    ],
    "displayName" : "Notification",
    "icon" : "icons/notification.gif"
  ]
]

wid的全称是work itemdefinition,使用MVEL语言,定义了一个custom work item。

2.2    注册wid文件

创建src/main/resources/META-INF/drools.rulebase.conf,文件内容如下。

drools.workDefinitions = MyWorkDefinitions.wid

2.3    使用custom work item

重启eclipse之后,你会发现元件面板多了一个Notification元件,你可以按照其他元件的使用方法使用这个元件。



2.4    创建JAVA类:NotificationWorkItemHandler

NotificationWorkItemHandler是一个必须实现接口org.kie.runtime.instance.WorkItemHandler的JAVA类,用于执行具体的业务逻辑。

import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.process.WorkItemManager;

public class NotificationWorkItemHandler implements WorkItemHandler {
    public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
        //获取参数
        String from = (String) workItem.getParameter("From");
        String to = (String) workItem.getParameter("To");
        String message = (String) workItem.getParameter("Message");
        String priority = (String) workItem.getParameter("Priority");
        //业务逻辑
        EmailService service = ServiceRegistry.getInstance().getEmailService(); 
        service.sendEmail(from, to, "Notification", message);
        // 通知work item manager work item已经处理完成
        manager.completeWorkItem(workItem.getId(), rm); 
    }
    public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
        System.out.println("Aborting");
    }
}


2.5    关联custom work item和WorkItemHandler

public class ServiceTaskExample {
	public static void main(String[] args) {
		KieServices ks = KieServices.Factory.get();
		KieContainer kContainer = ks.getKieClasspathContainer();
		KieBase kbase = kContainer.getKieBase("kbase");

		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put("category", "big");
		variables.put("dollars", 100000);
		
		RuntimeManager manager = createRuntimeManager(kbase);
		RuntimeEngine engine = manager.getRuntimeEngine(null);
		KieSession ksession = engine.getKieSession();
		ksession.getWorkItemManager().registerWorkItemHandler("Notification", new NotificationWorkItemHandler());
		ksession.startProcess("test5.test5",variables);
		manager.disposeRuntimeEngine(engine);
		System.exit(0);
	}

	private static RuntimeManager createRuntimeManager(KieBase kbase) {
		JBPMHelper.startH2Server();
		JBPMHelper.setupDataSource();
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa");
		RuntimeEnvironmentBuilder builder = RuntimeEnvironmentBuilder.Factory.get()
			.newDefaultBuilder().entityManagerFactory(emf)
			.knowledgeBase(kbase);
		return RuntimeManagerFactory.Factory.get()
			.newSingletonRuntimeManager(builder.get(), "com.sample:example:1.0");
	}
}

完整的代码如上,其中核心代码如下:

ksession.getWorkItemManager().registerWorkItemHandler("Notification",new NotificationWorkItemHandler());

第一个参数"Notification"对应wid文件中的name,第二个参数是待注册的workitem handler。

3      注意点

3.1    customwork itemworkitem handler的界限

从前面的例子可以看出,我们需要结合custom work item和work item handler两者来使用,两者的区别是如下。

custom work item 侧重于说明workitem是什么,不会说明如何去实现,是一个高层次的描述。custom work item handler侧重于说明如何来实现custom workitem的功能,有详细的业务逻辑(体现在方法executeWorkItem中)。

3.2    自定义任务和BPMN2.0的关系

自定义的任务对应到BPMN2.0中的元件是”tak”,在上面的例子中的custom work item 对应的BPMN2.0的XML代码如下。

<bpmn2:task id="Task_2" tns:taskName="Notification" tns:displayName="Notification" tns:icon="icons/notification.gif”  name="Notification">
  <bpmn2:extensionElements>
    <tns:metaData name="elementname">
      <tns:metaValue><![CDATA[Notification]]></tns:metaValue>
    </tns:metaData>
  </bpmn2:extensionElements>
  <bpmn2:ioSpecification id="InputOutputSpecification_2">
    <bpmn2:dataInput id="DataInput_2" itemSubjectRef="_2-2-4_InMessageType" name="Message"/>
    <bpmn2:dataInput id="DataInput_3" itemSubjectRef="_2-2-4_InMessageType" name="From"/>
    <bpmn2:dataInput id="DataInput_4" itemSubjectRef="_2-2-4_InMessageType" name="To"/>
    <bpmn2:dataInput id="DataInput_5" itemSubjectRef="_2-2-4_InMessageType" name="Priority"/>
    <bpmn2:inputSet id="_InputSet_2">
      <bpmn2:dataInputRefs>DataInput_2</bpmn2:dataInputRefs>
      <bpmn2:dataInputRefs>DataInput_3</bpmn2:dataInputRefs>
      <bpmn2:dataInputRefs>DataInput_4</bpmn2:dataInputRefs>
      <bpmn2:dataInputRefs>DataInput_5</bpmn2:dataInputRefs>
    </bpmn2:inputSet>
    <bpmn2:outputSet id="OutputSet_2" name="Output Set 2"/>
  </bpmn2:ioSpecification>
  <bpmn2:dataInputAssociation id="_DataInputAssociation_2">
    <bpmn2:targetRef>DataInput_2</bpmn2:targetRef>
  </bpmn2:dataInputAssociation>
  <bpmn2:dataInputAssociation id="_DataInputAssociation_3">
    <bpmn2:targetRef>DataInput_3</bpmn2:targetRef>
  </bpmn2:dataInputAssociation>
  <bpmn2:dataInputAssociation id="_DataInputAssociation_4">
    <bpmn2:targetRef>DataInput_4</bpmn2:targetRef>
  </bpmn2:dataInputAssociation>
  <bpmn2:dataInputAssociation id="_DataInputAssociation_5">
    <bpmn2:targetRef>DataInput_5</bpmn2:targetRef>
  </bpmn2:dataInputAssociation>
</bpmn2:task>

3.3    workitem handler的生命周期的管理

如果handler的创建是非常轻量的,我们可以让handler实现接口org.kie.internal.runtime.Closeable,实现这个接口后,handler的实例会随着handlerowner即work item handler manager的关闭而释放。

如果handler的创建是重量级的,比如加载了许多数据库的数据,连接外部socket等等,我们可以通过实现接口org.kie.internal.runtime.Cacheable,来达到重用handler实例的目的。

猜你喜欢

转载自blog.csdn.net/liaoxiangui/article/details/80577274
今日推荐