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實例的目的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章