Friday, 11 December 2009

Multi Operations BPEL

Invocation flavours
Most BPEL processes have just one entry and one exit point. Actually, if you create a new BPEL process you have the following templates:
  • Synchronous
  • Asynchronous
  • Empty
Empty you use when you want to start your BPEL process using an Adapter (File, Database, AQ, MQ, etc.). But often developers choose asynchronous and then figure they need to start the process using an adapter but leave the originally generated WSDL. The side effect might be that another developer might try to invoke the process/service using the original WSDL that is in fact not implemented anymore.

For the two other templates you can have the following service flavours:
  • Synchronous (Request/Reply)
  • Asynchronous Request/Reply
  • Fire&Forget
Fire&Forget is about the same as Asynchronous Request/Reply. Often the terms and their meanings are mixed up. One says Asynchronous but means Fire&Forget. The distinguise is in the fact that with an Asynchronous process you expect an answer and with Fire and Forget you don't. Most of the times (I did that in the past as well) one builds an asynchronous process but does not put a corresponding receive in the calling process. There is little wrong with that. However if the developer even deletes the invoke to call back to the caller, but another developer does put in a receive (it is in fact an asynchronous process, right?) then it waits for a callback that never comes. So I strongly advice in to distinguise between Asynchronous and Fire&Forget, by removing the call-back partnerlink-type and porttype from the WSDL. And so delete the corresponding call-back-invoke from the process.

Normally there are two ways for invoking these process, corresponding to the type. The "process"-operation for Synchronous and the "initiate"-operation for the Asynchronous/Fire&Forget ones.

So that's about it on the invocation flavours, right?

Multiple Operations
Well, not really. There are certain cases that you need to invoke your process in different ways. In the past I build processes that are initiated by one Operation (the initiate for Asynchronous), but I needed to send signals to the running process. For example, I build a schedule process that is initiated to wait for a certain time to do a certain task, based on information in the database. And if that is changed by an end-user, because the scheduled date/time is moved, you want to reschedule the process to have it wait for the new time.
Another reason may be that you have to impelement a certain WSDL that is agreed upon (top-down-method).

You do that by adding a new operation to the port-type in the WSDL. This new operation can have other message-types for input and output then the initiate operation.

For example, if you create a new process, like the Asynchronous MultiOperationProcess, the WSDL will look like:

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="MultiOperationProcess"
targetNamespace="http://xmlns.oracle.com/MultiOperationProcess"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:client="http://xmlns.oracle.com/MultiOperationProcess"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/">

<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE DEFINITION - List of services participating in this BPEL process
The default output of the BPEL designer uses strings as input and
output to the BPEL Process. But you can define or import any XML
Schema type and use them as part of the message types.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://xmlns.oracle.com/MultiOperationProcess" schemaLocation="MultiOperationProcess.xsd" />
</schema>
</types>

<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MESSAGE TYPE DEFINITION - Definition of the message types used as
part of the port type defintions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<message name="MultiOperationProcessRequestMessage">
<part name="payload" element="client:MultiOperationProcessProcessRequest"/>
</message>

<message name="MultiOperationProcessResponseMessage">
<part name="payload" element="client:MultiOperationProcessProcessResponse"/>
</message>


<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PORT TYPE DEFINITION - A port type groups a set of operations into
a logical service unit.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- portType implemented by the MultiOperationProcess BPEL process -->
<portType name="MultiOperationProcess">
<operation name="initiate">
<input message="client:MultiOperationProcessRequestMessage"/>
</operation>
</portType>

<!-- portType implemented by the requester of MultiOperationProcess BPEL process
for asynchronous callback purposes
-->
<portType name="MultiOperationProcessCallback">
<operation name="onResult">
<input message="client:MultiOperationProcessResponseMessage"/>
</operation>
</portType>

<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PARTNER LINK TYPE DEFINITION
the MultiOperationProcess partnerLinkType binds the provider and
requester portType into an asynchronous conversation.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<plnk:partnerLinkType name="MultiOperationProcess">
<plnk:role name="MultiOperationProcessProvider">
<plnk:portType name="client:MultiOperationProcess"/>
</plnk:role>
<plnk:role name="MultiOperationProcessRequester">
<plnk:portType name="client:MultiOperationProcessCallback"/>
</plnk:role>
</plnk:partnerLinkType>
</definitions>


Adding an operation is simple:
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="MultiOperationProcess" targetNamespace="http://xmlns.oracle.com/MultiOperationProcess"
xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:client="http://xmlns.oracle.com/MultiOperationProcess"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/">
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE DEFINITION - List of services participating in this BPEL process
The default output of the BPEL designer uses strings as input and
output to the BPEL Process. But you can define or import any XML
Schema type and use them as part of the message types.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://xmlns.oracle.com/MultiOperationProcess" schemaLocation="MultiOperationProcess.xsd"/>
</schema>
</types>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MESSAGE TYPE DEFINITION - Definition of the message types used as
part of the port type defintions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<message name="MultiOperationProcessRequestAapMessage">
<part name="payload" element="client:MultiOperationProcessProcessAapRequest"/>
</message>
<message name="MultiOperationProcessRequestNootMessage">
<part name="payload" element="client:MultiOperationProcessProcessNootRequest"/>
</message>
<message name="MultiOperationProcessResponseMessage">
<part name="payload" element="client:MultiOperationProcessProcessResponse"/>
</message>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PORT TYPE DEFINITION - A port type groups a set of operations into
a logical service unit.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- portType implemented by the MultiOperationProcess BPEL process -->
<portType name="MultiOperationProcess">
<operation name="initiateAap">
<input message="client:MultiOperationProcessRequestAapMessage"/>
</operation>
<operation name="initiateNoot">
<input message="client:MultiOperationProcessRequestNootMessage"/>
</operation>
</portType>
<!-- portType implemented by the requester of MultiOperationProcess BPEL process
for asynchronous callback purposes
-->
<portType name="MultiOperationProcessCallback">
<operation name="onResult">
<input message="client:MultiOperationProcessResponseMessage"/>
</operation>
</portType>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PARTNER LINK TYPE DEFINITION
the MultiOperationProcess partnerLinkType binds the provider and
requester portType into an asynchronous conversation.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<plnk:partnerLinkType name="MultiOperationProcess">
<plnk:role name="MultiOperationProcessProvider">
<plnk:portType name="client:MultiOperationProcess"/>
</plnk:role>
<plnk:role name="MultiOperationProcessRequester">
<plnk:portType name="client:MultiOperationProcessCallback"/>
</plnk:role>
</plnk:partnerLinkType>
</definitions>



You can even change an existing operation. But then you'll have to change the initial receive:Now you can add another Receive to cater for the receive events of the other porttype. Of course you need a Correlation Set to make sure that the event is sent to the right instance of the process.

We just added an operation to the Port Type. But you can also add another PortType. That means however also another Partnerlink type:
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="MultiOperationProcess" targetNamespace="http://xmlns.oracle.com/MultiOperationProcess"
xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:client="http://xmlns.oracle.com/MultiOperationProcess"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/">
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE DEFINITION - List of services participating in this BPEL process
The default output of the BPEL designer uses strings as input and
output to the BPEL Process. But you can define or import any XML
Schema type and use them as part of the message types.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://xmlns.oracle.com/MultiOperationProcess" schemaLocation="MultiOperationProcess.xsd"/>
</schema>
</types>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MESSAGE TYPE DEFINITION - Definition of the message types used as
part of the port type defintions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<message name="MultiOperationProcessRequestAapMessage">
<part name="payload" element="client:MultiOperationProcessProcessAapRequest"/>
</message>
<message name="MultiOperationProcessRequestNootMessage">
<part name="payload" element="client:MultiOperationProcessProcessNootRequest"/>
</message>
<message name="MultiOperationProcessRequestMiesMessage">
<part name="payload" element="client:MultiOperationProcessProcessMiesRequest"/>
</message>
<message name="MultiOperationProcessResponseMessage">
<part name="payload" element="client:MultiOperationProcessProcessResponse"/>
</message>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PORT TYPE DEFINITION - A port type groups a set of operations into
a logical service unit.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- portType implemented by the MultiOperationProcess BPEL process -->
<portType name="MultiOperationProcess">
<operation name="initiateAap">
<input message="client:MultiOperationProcessRequestAapMessage"/>
</operation>
<operation name="initiateNoot">
<input message="client:MultiOperationProcessRequestNootMessage"/>
</operation>
</portType>
<portType name="MultiOperationProcessMies">
<operation name="initiateMies">
<input message="client:MultiOperationProcessRequestMiesMessage"/>
</operation>
</portType>
<!-- portType implemented by the requester of MultiOperationProcess BPEL process
for asynchronous callback purposes
-->
<portType name="MultiOperationProcessCallback">
<operation name="onResult">
<input message="client:MultiOperationProcessResponseMessage"/>
</operation>
</portType>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PARTNER LINK TYPE DEFINITION
the MultiOperationProcess partnerLinkType binds the provider and
requester portType into an asynchronous conversation.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<plnk:partnerLinkType name="MultiOperationProcess">
<plnk:role name="MultiOperationProcessProvider">
<plnk:portType name="client:MultiOperationProcess"/>
</plnk:role>

<plnk:role name="MultiOperationProcessRequester">
<plnk:portType name="client:MultiOperationProcessCallback"/>
</plnk:role>
</plnk:partnerLinkType>
<plnk:partnerLinkType name="MultiOperationProcessMies">
<plnk:role name="MultiOperationProcessProviderMies">
<plnk:portType name="client:MultiOperationProcessMies"/>
</plnk:role></plnk:partnerLinkType>
</definitions>
Having this you need another partnerlink in your process to get events from it:


The corresponding XSD is:
<schema attributeFormDefault="unqualified" elementFormDefault="qualified"
targetNamespace="http://xmlns.oracle.com/MultiOperationProcess" xmlns="http://www.w3.org/2001/XMLSchema">
<element name="MultiOperationProcessProcessAapRequest">
<complexType>
<sequence>
<element name="inputAap" type="string"/>
</sequence>
</complexType>
</element>
<element name="MultiOperationProcessProcessNootRequest">
<complexType>
<sequence>
<element name="inputNoot" type="string"/>
</sequence>
</complexType>
</element>
<element name="MultiOperationProcessProcessMiesRequest">
<complexType>
<sequence>
<element name="inputMies" type="string"/>
</sequence>
</complexType>
</element>
<element name="MultiOperationProcessProcessResponse">
<complexType>
<sequence>
<element name="result" type="string"/>
</sequence>
</complexType>
</element>
</schema>
Now you can implement about any WSDL with BPEL.

Multi Initiate
A BPEL process can have only one Receive with the initiate checkbox checked. So there is just one and only one entry point in the BPEL process. This should also be the very first activity in the process. Actually it isn't. That is, if you have implemented an exception handler (Catch/CatchAll) on the outermost-scope. Then the activities in the fault-handlers are the first in the BPEL process. And I found that there is a little pitfall in it. It might be that you have an exception handling bpel-process that you call from the catch-branches. No worries if it is a logging process (Fire&Forget). But if it returns a value to determine if you have to do a retry or an abort, then you have a Receive activity before the first Initiate-Receive!

But apparently you can not initiate your BPEL process from the other operations we introduced before. And that makes it only usefull in cases where you initiate your bpel process in one way and have it receive messages over the other operations. If you have to implement a certain WSDL with multiple operations that have to initiate the process: "Houston we have a problem".

Until yesterday this is what I believed as well. But I under-estimated the use of the Pick activity!
The Pick activity splits up the initiation of the process from the messages it listens to:
You can then remove the Timer Branch and add extra Branches. For Aap (Ape):

For Noot (Nut)

For Mies:
And in the branches you can for example add an assignment from the corresponding message:
If you do that for each of the branches, the example process will look like:

Don't forget to remove the original InputMessage-variable.

Unfortunately the BPEL Console does not support the extra porttype for the test screen. I haven't been able to test it with SoapUI yet. So I'm not sure if that works. Deleting the ClientMies parts of the process will work:

That leaves us with this process (belonging with the second WSDL above):


Conclusion
Now you can implement about any WSDL using BPEL, although apparently you're contracted to having one partnerlink-type and one port-type with multiple operations. For me it was a revelation to be able to initiate your process in multiple ways. It might come in handy when you have a case that has some different initiation message but a common process-part. Normally you would create seperate processes to receive the different messages and have them transform them to a common message-format and call the common process. But apparently we can do it all in one process too.

You can find my code-examples here.

1 comment: