Thursday, September 27, 2007

Using custom headers in BPEL

Sending messages to a BPEL process mostly done via the web service interface. In general the message is packed in a SOAP envelope in the body part. The header part of the SOAP envelope id not touch. This is mostly done automatically between the client and web service.

Sometimes you need information to send or retrieve information to the BPEL process that is not part of the message. This information is mostly technical and not functional related to the message in the SOAP body. In these cases you could manipulate the SOAP header to add your own message.

The next example describes a solution of retrieving headers from the SOAP request. The example is very simple it just an 'HelloWorld' application that reads the SOAP header. If the custom header exists it returns it, otherwise it does not. The BPEL process is show as follows:



Now this is simple. The trick is in the WSDL specification and the 'receive' step in the BPEL process. A few changes have been made in the default WSDL (after you create a default async BPEL process in jDeveloper).

The WSDL is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloHeader"
targetNamespace="http://xmlns.oracle.com/HelloHeader"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:client="http://xmlns.oracle.com/HelloHeader"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://xmlns.oracle.com/HelloHeader"
schemaLocation="HelloHeader.xsd"/>
<import namespace="http://schemas.xmlsoap.org/ws/2003/03/addressing"
schemaLocation="https://dvlp1.eurotransplant.nl/
orabpel/xmllib/ws-addressing.xsd"/>
</schema>
</types>
<!-- SOAP HEADER -->
<message name="RelatesToHeader">
<part name="RelatesTo" element="wsa:RelatesTo"/>
</message>
<message name="MessageIDHeader">
<part name="MessageID" element="wsa:MessageID"/>
</message>
<message name="ReplyToHeader">
<part name="ReplyTo" element="wsa:ReplyTo"/>
</message>
<message name="CustomHeader">
<part name="CustomHeader" element="client:HelloHeaderHeaderMessage"/>
</message>
<!-- EOF SOAP HEADER -->
<message name="HelloHeaderRequestMessage">
<part name="payload" element="client:HelloHeaderProcessRequest"/>
</message>
<message name="HelloHeaderResponseMessage">
<part name="payload" element="client:HelloHeaderProcessResponse"/>
</message>
<portType name="HelloHeader">
<operation name="initiate">
<input message="client:HelloHeaderRequestMessage"/>
</operation>
</portType>
<portType name="HelloHeaderCallback">
<operation name="onResult">
<input message="client:HelloHeaderResponseMessage"/>
</operation>
</portType>
<binding name="HelloHeaderBinding"
type="client:HelloHeader">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="initiate">
<soap:operation style="document" soapAction="initiate"/>
<input>
<soap:header message="client:MessageIDHeader"
part="MessageID" use="literal"/>
<soap:header message="client:ReplyToHeader"
part="ReplyTo" use="literal"/>
<soap:header message="client:CustomHeader"
part="CustomHeader" use="literal"/>
<soap:body use="literal"/>
</input>
</operation>
</binding>
<binding name="HelloHeaderCallbackBinding"
type="client:HelloHeaderCallback">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="onResult">
<soap:operation soapAction="onResult" style="document"/>
<input>
<soap:header message="client:RelatesToHeader"
part="RelatesTo" use="literal" required="false"/>
<soap:body use="literal"/>
</input>
</operation>
</binding>

<plnk:partnerLinkType name="HelloHeader">
<plnk:role name="HelloHeaderProvider">
<plnk:portType name="client:HelloHeader"/>
</plnk:role>
<plnk:role name="HelloHeaderRequester">
<plnk:portType name="client:HelloHeaderCallback"/>
</plnk:role>
</plnk:partnerLinkType>
</definitions>



In the WSDL we overwrite the binding of the web service. Here we specify the custom header. We should not forget to use the normal headers as MessageId and ReplyTo.

Note: In the XSD-file we added a message":
 <element name="
<complextype>
<sequence>
<element name="message" type="string">
</sequence>
</complextype>
</element>

Now the message and the WSDL are correct we could change the BPEL file to add the code to read the SOAP Header. In the variable declaration add:

<variable name="customHeader"
messageType="client:CustomHeader"/>
<variable name="messageID"
messageType="client:MessageIDHeader"/>
<variable name="replyTo"
messageType="client:ReplyToHeader"/>

Now change the receive task to add the "bpelx:headerVariable" statement.

<receive name="receiveInput"
partnerLink="client"
portType="client:HelloHeader"
operation="initiate"
variable="inputVariable"
createInstance="yes"
bpelx:headerVariable="customHeader messageID replyTo"
/>

After the receice step the headers, if the exist, are put into the variables. Now you could use normal assign/copy tasks to use this data.

You can download the example code here.

To test the BPEL process, use a tool as SoapUI.org (open source). Here is a SOAP request with a custom header:

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:hel="http://xmlns.oracle.com/HelloHeader"
xmlns:add="http://schemas.xmlsoap.org/ws/2003/03/addressing">
<soapenv:Header>
<hel:HelloHeaderHeaderMessage>
<hel:message>This is the custom header</hel:message>
</hel:HelloHeaderHeaderMessage>
</soapenv:Header>
<soapenv:Body>
<hel:HelloHeaderProcessRequest>
<hel:input>Hello World</hel:input>
</hel:HelloHeaderProcessRequest>
</soapenv:Body>
</soapenv:Envelope>

Post a Comment