In one of my previous blog posts on Business Process Management (BPM) I outlined the important role that BPM plays in a Service Oriented Architecture (SOA), and how a well defined SOA is a prerequisite for successful Cloud implementations.
The
jBPM5 engine, part of the JBoss BRMS platform, is a highly flexible
and versatile BPM engine based on open standards like BPMN2 and
WS-HumanTask. This article will show how the jBPM5 platform can
integrate with WebServices by utlizing the JAX-WS API.
The
jBPM5 platform provides a simple, but very powerful, extension
mechanism to add domain specific service nodes and their
implementations to a business process. This allows us to plug our own,
custom, logic into the business process runtime system. The extension
mechanism is
based on the jBPM5 WorkItemHandler API. The WorkItemHandler interface
declares 2 methods which need to be implemented by the domain
specific WorkItemHandler implementation:
-
public
void
executeWorkItem(WorkItem workItem, WorkItemManager workItemManager):
Is
called by the process engine when a service node is executed.
-
public
void
abortWorkItem(WorkItem workItem, WorkItemManager workItemManager):
Can
be implemented to signal the workitem to be aborted.
In
this example we will utilize this WorkItemHandler API to implement
our own custom service nodes which use the JAX-WS API to call external
WebServices. This article will not cover how to define and use custom
nodes in your business process editor (i.e. the JBoss BRMS BPMN2 Web
editor, the JBoss Tools Eclipse BPMN2 editor, etc.). For inforrmation on how to define and use custom process nodes in your
BPMN2 process, please consult:
The source codes of the examples in this blogpost are available in my Github repository. The code also contains the WorktemDefinitions file
which contains the definitions of the ‘PaymentService‘ and
‘JAX-WS-Dispatcher-Service‘ workitems. These definitions can, for
example, be used in the JBoss BRMS system to add the custom service
nodes to the BPMN2 web-editor palet.
The
Process
The
process used in this example is a simple process which calls a
PaymentService to check whether a payment-type (e.g. VISA,
MasterCard, etc.) is valid and which, if the payment-type is valid,
calls an OrderService to place a specific order. The process contains
additional ScriptTask nodes which provide debug output
which is written to System.out.
The BPMN2 process definition of this specific process can be found here.
In
this example, the process runs in a simple Java client application
(the ‘Simple_jBPM_Process‘ project), which creates the jBPM5
KnowledgeBase, containing the BPMN2 process definition, creates the
StatefulKnowledgeSession, registers our custom JAX-WS WorkItemHandlers and
starts the process instance. See the
‘org.jboss.ddoyle.howtojboss.jbpm5webservices.Main‘ class for the example code.
WebServices
JAX-WS
JAX-WS
provides two client APIs which can be used to execute WebService
calls, the Dispatch API and the Proxy API.
The
Proxy API provides a Java proxy object representing the WebService endpoint
to be called. The JAXB2 library is utilized to marshall and
unmarshall Java objects to and from XML. This client mode can be used
when one wants to operate on Java objects.
The
Dispatch API is a dynamic API in which the client code which uses
this API is responsible for the creation of the XML payload or even
the entire SOAP message that will be sent to the WebService endpoint.
This API can be used when one wants to operate on the XML message level.
In
this example we will use both client modes. We will call the
‘PaymentService‘ using a JAX-WS Proxy client and the ‘OrderService‘
via a JAX-WS Dispatch client.
JAX-WS
Proxy Client: PaymentServiceJaxWsProxyWorkItemHandler
JBoss
BRMS (and any other JBoss platform for that matter) provides a
utility that is able to generate the JAX-WS annotated Java code from a
given WSDL file. This utility, called ‘wsconsume‘, is located in the
‘jboss-as/bin‘ directory of your JBoss BRMS (or EAP) platform. The utility can be used as follows:
./wsconsume.sh -kn {WSDL-file}. This will generate the JAX-WS annotated client
and server code which can be used to both implement the webservice
provider and a webservice consumer. Both the ‘Simple_jBPM_Process‘
(consumer) and the ‘SimpleWebServicesWeb‘ (provider) contain the
JAX-WS code generated from the ‘PaymentService‘ and ‘OrderService‘ WSDL files.
The
‘PaymentServiceJaxWsProxyWorkItemHandler‘
uses the generated JAX-WS Proxy client to call the
PaymentService. As can be seen from the code, the WorkItemHandler
is, because it directly uses the generated PaymentService proxy classes,
tightly
coupled to the PaymentService. I.e. This WorkItemHandler
implementation is specifically created to call a PaymentService
WebService. In general, a WorkItemHandler which uses a JAX-WS Proxy
client can only be used to call that specific service. This implies that
one has to define and create a WorkItemHandler per service, and thus a
domain specific process node per service.
The
jBPM5 WorkItemHandler API provides the ability to pass parameters from
the jBPM5 process instance to the WorkItemHandler via
a parameter Map. In the jBPM5 BPMN2 process definition, a mapping needs
to be defined on the ‘PaymentService‘ node which maps the process
instance data onto the parameters required by the WorkItemHandler.
In the case of the ‘PaymentServiceJaxWsProxyWorkItemHandler‘, 2 parameters
can (must) be passed to the WorkItemHandler:
- input: a
String object containing the input value for the PaymentService.
- endpointAddress: the URL of the location of the PaymentService.
The service response data is
returned to the process instance via the ‘paymentServiceResponse‘
parameter in the returned parameter Map. This response can then be
mapped back onto a process instance variable.
The ‘endpointAddress‘ parameter allows us to configure the actual
location of the PaymentService endpoint. This makes it possible to
use the same WorkItemHandler to point to different endpoint
locations of the PaymentService, which is specifically useful when one has to deploy the
process in multiple environments (i.e. Development, Test,
Production).
JAX-WS
Dispatch Client: JaxWsDispatcherWorkItemHandler
The
‘JaxWsDispatcherWorkItemHandler‘
uses the JAX-WS Dispatch API to, in this process definition, call
the OrderService. The JAX-WS Dispatch API allows us to work on XML
structures directly. The responsibility of providing the correct XML
SOAP-message payload (or the entire SOAP-message itself, depending on
whether the Dispatch client is used in PAYLOAD or MESSAGE mode) lies
now with the code that uses the Dispatch API.
In
this example we‘ve tried to make this WorkItemHandler as generic
as possible, so it can be used to call any webservice and can be reused in
various projects. This is done by parameterizing the name and
location of the service to be called, as well as by providing a
simple ‘injection‘ mechanism to inject the RequestMapper and
ResponseMapper objects responsible for marshalling and unmarshalling
the XML payload from and to jBPM5 WorkItemHandler parameters (which are passed via the WorkItemHandler parameter Map).
The
WorkItemHandler requires the following parameters to be passed by the
process instance:
-
serviceNamespace:
the namespace of the service to be called. I.e. The namespace
defined in the services‘ WSDL file.
-
serviceName:
The name of the service as defined in the services‘ WSDL file.
-
portTypeNamespace:
The namespace of the PortType.
-
portTypeName:
The name of the PortType.
-
soapAction:
The soapAction value of the service operation to be called.
-
endpointAddress:
The URL of the service endpoint.
-
requestMapper:
The name of the request-mapper which will be used to lookup a
RequestMapper instance via the ‘RequestMapperFactory‘.
- responseMapper:
The name of the response-mapper which will be used to lookup a
ResponseMapper instance via the ‘ResponseMapperFactory‘.
- input: The input data for the WebService call.
The service response data is returned to the process instance via the ‘response‘ parameter in the returned parameter Map.
These
parameters make this WorkItemHandler very generic. One can call
different services, inject specific RequestMappers and
ResponseMappers, etc. The picture below shows how the mapping of jBPM5
process instance data to WorkItemHandler parameters is configured in the
JBoss BRMS BPMN2 web editor:
If required, the WorkItemHandler can be extended to support additional WS-* features like WS-Security, WS-Addressing, etc.
Running
the example.
To
run the example, first the project containing the OrderService and
PaymentService implementations needs to be build using Maven. To do
this, execute the command ‘mvn clean install‘ in the
‘SimpleWebServicesWeb‘ directory. This will build the WAR file and
add it to your local Maven repository. Deploy this WAR file on a JBoss
BRMS 5.3 platform (or any JBoss platform with a JBossWS-CXF
WebServices stack) of which the HTTP connector is bound to
‘localhost:8080‘. The WSDL files of the WebServices can now be
accessed at:
Next,
build the ‘Simple_jBPM_Process‘ client project by again executing
‘mvn clean install‘ in the ‘Simple_jBPM_Process‘ directory. This will
produce a JAR file which contains all the jBPM5 and Drools
dependencies required to run the process instance.
To
run the client, simply execute the command ‘java -jar Simple_jBPM_Process-0.0.1-SNAPSHOT.jar JBoss_T-Shirt VISA‘ from a terminal. If
everything exectutes correctly, this will produce the following output:
Loading StatefulKnowledgeSession.
Starting Process Instance.
Payment type: VISA
PaymentService response: VALID
Payment approved!
Oct 4, 2012 12:39:43 AM
org.jboss.ddoyle.howtojboss.jbpm5webservices.workitemhandlers.JaxWsDispatcherWorkItemHandler
executeWorkItem
INFO: Calling Service: http://impl.orderservice.howtojboss.ddoyle.jboss.org/:SimpleOrderServiceService
Oct 4, 2012 12:39:43 AM
org.jboss.ddoyle.howtojboss.jbpm5webservices.workitemhandlers.JaxWsDispatcherWorkItemHandler
executeWorkItem
INFO: Received response from Service: http://impl.orderservice.howtojboss.ddoyle.jboss.org/:SimpleOrderServiceService
Order ‘JBoss_T-Shirt‘ submitted successfully
Finished Process Instance with id: 1
If
another payment-type then VISA is entered, the process will show the
following output.
Loading StatefulKnowledgeSession.
Starting Process Instance.
Payment type: MasterCard
PaymentService response: INVALID
Payment not approved. Order cancelled.
Finished Process Instance with id: 1
Conclusion
jBPM5
is a highly versatile and flexible Business Process Management
platform which can be easily extended, customized and integrated with
a vast array of external systems. In this example we combined the
JAX-WS API and the jBPM5 WorkItemHandler API to integrate
WebServices with our business processes. The WorkItemHandler API is a
simple, yet powerful, construct that can be used to integrate business processes with
almost any (external) system, as long as that system provides a Java
client API (or as long as a Java client can be written for it). This implies
that we can use the same mechanism to, from our business process,
call RESTful services, send JMS messages to message queues (e.g.
JBoss HornetQ), etc. As such, the jBPM5 platform can be easily integrated in almost any IT landscape.