Invocation of web services as part of business process is common and most likely because of that default implementation of Service Task in BPMN2 specification is web service. Recently (5.4) jBPM5 has gotten support for such activity.
jBPM5 web service support is based on Apache CXF dynamic client. It provides dedicated Service Task handler (that implements WorkItemHandler interface).
Worth noting is that this handler is capable of invoking both web service end points and simple Java based services as with previous ServiceTask handler (org.jbpm.bpmn2.handler.SendTaskHandler) based on the implementation attribute of service task node
web service implementation
java implementation
ServiceTaskHandler can invoke web service operations in three modes:
Let's try to go through this implementation with example. We are going to build a process that will get weather forecast for given zip codes in US. So process will look like this:
This process will:
But how does it know it is web service and even more important what web service it is? This is configured as part of process definition using few dedicated constructs:
1. first of all we need to tell the engine where is our WSDL so it can be read and operations from it can be invoked - this is done with BPMN2 import:
<import importType="http://schemas.xmlsoap.org/wsdl/" location="http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL" namespace="http://ws.cdyne.com/WeatherWS/"/>
2. next message, interface and operations must be defined:
Important: make sure that implementationRef for both interface and operations point to valid service and operation in WSDL.
3. Next use defined operation in your service task and set implementation as web service (or don't specify that attribute at all so default will be taken):
NOTE: Unfortunately tooling does not support this yet so the bpmn2 file needs to be edited by hand. Soon tooling will provide this as well.
Yet another important thing here is that if you plan to use request or response object of the service in your process as variables make sure that all of them implement java.io.Serializable interface so they can be properly persisted. One way to do this (used in the example) is to provide additional configuration to tell JAXB to add Serializable while generating classes from WSDL and generate classes as part of the build:
Complete source code can be found here. It comes with test cases that uses this example as well as local service that can be used to illustrate difference between sync and async modes.
This example can be executed on jbpm-console when build from master, as it already has this service task handler configured. Here is a short guide on how to do it:
1. clone jbpm master and build it with mvn clean install -DskipTests -Dfull (alternatively download latest build from build server)
2. clone jbpm-examples and build jbpm-ws-example project with mvn clean install
3. copy result of build in point 2 (jbpm-ws-sample-1.0-SNAPSHOT.jar) into jbpm-installer/dependencies
4. copy WeatherWSServiceProcess.bpmn2 into jbpm-installer/sample/evaluation/src/main/resource
5. copy all archives from jbpm-distribution into jbpm-installer/lib
6. use jbpm-installer to install jbpm into jboss AS7 - ant install.demo.noeclipse
7. start demo server - ant start.demo.noeclipse
then go to jbpm-console and run the process with name WeatherWSServiceProcess.
Have fun!
jBPM5 web service support is based on Apache CXF dynamic client. It provides dedicated Service Task handler (that implements WorkItemHandler interface).
org.jbpm.process.workitem.bpmn2.ServiceTaskHandler
Worth noting is that this handler is capable of invoking both web service end points and simple Java based services as with previous ServiceTask handler (org.jbpm.bpmn2.handler.SendTaskHandler) based on the implementation attribute of service task node
web service implementation
<bpmn2:serviceTask id="ServiceTask_1" name="Service Task" implementation="##WebService" operationRef="_2_ServiceOperation"> </bpmn2:serviceTask>
<bpmn2:serviceTask id="_2" name="Hello" operationRef="_2_ServiceOperation" implementation="Other" >
</bpmn2:serviceTask> ServiceTaskHandler can invoke web service operations in three modes:
- synchronous (sends request and waits for response before continuing)
- asynchronous (sends request and uses callback to get response)
- one way (sends request and does not wait for any response)
Let's try to go through this implementation with example. We are going to build a process that will get weather forecast for given zip codes in US. So process will look like this:
This process will:
- ask for couple of zip codes on the first human task (task is assigned to john)
- next transform result of the user task to a collection that will be used as input for multi instance service task
- then based on the input collection process will create several instances of service task to query the weather forecast service
- once all service task instances are completed it will log result to the console
- and create another human task to show the weather forecast for selected zip codes (task is assigned to john)
But how does it know it is web service and even more important what web service it is? This is configured as part of process definition using few dedicated constructs:
1. first of all we need to tell the engine where is our WSDL so it can be read and operations from it can be invoked - this is done with BPMN2 import:
<import importType="http://schemas.xmlsoap.org/wsdl/" location="http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL" namespace="http://ws.cdyne.com/WeatherWS/"/>
2. next message, interface and operations must be defined:
<itemDefinition id="_2-2-4_InMessageType" />
<message id="_2-2-4_InMessage" itemRef="_2-2-4_InMessageType" />
<interface id="_2-2-4_ServiceInterface" name="" implementationRef="Weather">
<operation id="_2-2-4_ServiceOperation"
implementationRef="GetCityWeatherByZIP" name="hello">
<inMessageRef>_2-2-4_InMessage</inMessageRef>
</operation>
<inMessageRef>_2-2-4_InMessage</inMessageRef>
</operation>
</interface>
Important: make sure that implementationRef for both interface and operations point to valid service and operation in WSDL.
3. Next use defined operation in your service task and set implementation as web service (or don't specify that attribute at all so default will be taken):
<serviceTask id="_2" name="Service Task" operationRef="_2-2-4_ServiceOperation" implementation="##WebService" >
........
</serviceTask>NOTE: Unfortunately tooling does not support this yet so the bpmn2 file needs to be edited by hand. Soon tooling will provide this as well.
Yet another important thing here is that if you plan to use request or response object of the service in your process as variables make sure that all of them implement java.io.Serializable interface so they can be properly persisted. One way to do this (used in the example) is to provide additional configuration to tell JAXB to add Serializable while generating classes from WSDL and generate classes as part of the build:
- create extra binding file
- configure cxf codegen maven plugin
Complete source code can be found here. It comes with test cases that uses this example as well as local service that can be used to illustrate difference between sync and async modes.
This example can be executed on jbpm-console when build from master, as it already has this service task handler configured. Here is a short guide on how to do it:
1. clone jbpm master and build it with mvn clean install -DskipTests -Dfull (alternatively download latest build from build server)
2. clone jbpm-examples and build jbpm-ws-example project with mvn clean install
3. copy result of build in point 2 (jbpm-ws-sample-1.0-SNAPSHOT.jar) into jbpm-installer/dependencies
4. copy WeatherWSServiceProcess.bpmn2 into jbpm-installer/sample/evaluation/src/main/resource
5. copy all archives from jbpm-distribution into jbpm-installer/lib
6. use jbpm-installer to install jbpm into jboss AS7 - ant install.demo.noeclipse
7. start demo server - ant start.demo.noeclipse
then go to jbpm-console and run the process with name WeatherWSServiceProcess.
Have fun!