Oracle HTTP Adapter
The Secret BPEL Adapter
I had a phone call a while back from a partner who wanted to call a service that took as input an XML document and returned an XML document. The normal way to do this of course is using SOAP to manage the interface definition for the input and output parameters. What was needed in this case was an HTTP adapter that could call the service appropriately. The problem is that when you look in JDeveloper or the user guide there is no mention of an HTTP adapter. My friend at the partner wanted to know if there was an HTTP adapter to which I replied “No and Yes”! This left him a little confused to say the least so let me share with you the explanation I gave him. Along the way we will look at how to use the HTTP Adapter functionality from BPEL.
WSIF Bindings
The key to using HTTP POST and GET requests is in the WSIF bindings. Web Service Invocation Framework (WSIF) provides a way for non-SOAP services to be described with a WSDL wrapper. For example the database adapter uses WSIF to provide a WSDL wrapper around a TopLink JCA adapter. The adapters listed in the developers guide and supported directly in JDeveloper have re-entrant wizard driven interfaces that makes them easy to use. There are other bindings supported by WSIF that do not have nice wizards to help you build them, however with a bit of knowledge (always a dangerous thing) they can provide useful functionality.
Where to Find Samples
The Oracle BPEL Process Manager ships with 3 tutorials for non-wizard driven bindings. They can be found in the $ORACLE_HOME/bpel/samples/tutorials/702.Bindings directory. The three samples are provided in three sub-directories:
- EJBBinding – Calling an EJB session bean.
- HTTPBinding – Calling an HTTP based service.
- JavaBinding – Calling a plain old java object (POJO).
Lets look in more detail at how the HTTP binding works.
HTTP Refresher
HTTP has a number of verbs that describe the operation to be performed, these include GET, POST and HEAD amongst others. Generally if we are retrieving data then we are interested in GET or POST. When using GET we pass parameters as part of the target URL, for example http://localhost/EchoApp/echo?p1=1&p2=2. This example passes two parameters to the service located at EchoApp/echo, p1 with a value of 1 and p2 with a value of 2. When using POST then the parameters are passed as data in the body of the message rather than as part of the URL. Originally GET was intended for non-mutative operations and POST for mutative operations, but POST is often used when there is a large amount of data to be sent even if it is not mutative, it is also used to improve security as the parameters are not visible on the URL.
Performing a GET
Lets look at how to execute a GET operation that passes some parameters and receives an XML document in response.
I have created a simple Echo application that returns as an XML document the parameters it received and the contents of the body of the HTTP request. This can be downloaded here. To test the echo application there is an EchoApp/index.html that provides a simple form to perform a POST operation. Just typing EchoApp/echo into a browser bar will perform a GET operation.
A sample WSDL for a GET operation is available here. Lets look at the key binding section.
Within the binding we specify the binding verb for the HTTP operation. In this case we want to use a GET operation.
<binding name="HttpGetBinding" type="tns:HttpGetPortType">
<http:binding verb="GET"/>
Having described the type of operation we must specify the path of the URL (/EchoApp/echo) that we wish to invoke. The server and port number are specified later. Note that multiple operations may be specified at different URL paths.
<operation name="GetData">
<http:operation location="/EchoApp/echo"/>
We must now describe how we want to process the parameters. In this case we want all the parts to be encoded as parameters on the URL and so use http:urlEncoded. As the return is an XML document we specify that the return type is of mime type XML by specifying mime:mimeXml and providing the name of the part in the response message.
<input>
<http:urlEncoded/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
If we have input and output message definitions as shown below then the request would be encoded as /EchoApp/echo?param1=VALUEP1¶m2=VALUEP2. Note that the input message should have multiple parts of simple types. The response would be expected to be received as an XML document with <get:Request> as a root element.
<message name="HttpGetIn">
<part name="param1" type="xsd:string"/>
<part name="param2" type="xsd:string"/>
</message>
<message name="HttpGetOut">
<part name="Body" element="get:Request"/>
</message>
The actual server location of the target is given in the service section of the WSDL as shown below.
<service name="GetService">
<port name="HttpGetPort" binding="tns:HttpGetBinding">
<http:address location="http://localhost:7001"/>
</port>
</service>
The above definitions then let us call a service using the GET verb and receive an XML document as a response. Using this WSDL we can call the HTTP GET based service as though it were any other WSDL described web service, BPEL does not care about the underlying transport bindings.
Performing a POST with Form Style input
Lets now look at how to execute a POST operation that passes some parameters as though submitted from an HTML form and receives an XML document in response.
A sample WSDL for a POST operation passing form style parameters is available here. Lets look at the key binding section. As before we specify the binding for the HTTP operation, but change the verb to be a POST operation. The location is specified in the same way as for the GET operation.
<binding name="HttpPostParamBinding"
type="tns:HttpPostParamPortType">
<http:binding verb="POST"/>
<operation name="PostData">
<http:operation location="/EchoApp/echo"/>
We must now describe how we want to process the parameters. In this case we want all the parts to be encoded as form style parameters in the body of the request and so use mime:content type=”application/x-www-form-urlencoded”. As the return is an XML document we specify that the return type is of mime type XML by specifying mime:mimeXml and providing the name of the part in the response message.
<input>
<mime:content type="application/x-www-form-urlencoded"/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</binding>
If we have the same input and output message definitions as used in the GET example then the request URL would be encoded as /EchoApp/echo with the body containing the following “param1=VALUEP1¶m2=VALUEP2”. Note that the input message should have multiple parts of simple types. The response is handled in the same way as with the GET.
The actual server location of the target is given in the service section of the WSDL in the same was as the GET request.
The above definitions then let us call a service using the POST verb and receive an XML document as a response. Using this WSDL we can call the HTTP POST based service as though it were any other WSDL described web service.
Performing a POST with XML Document input
In the previous section we looked as using a POST to submit form style parameters. The POST verb lets us put any content into the body of the request and so it is often useful to be able to send an XML document to the service. Lets now look at how to execute a POST operation that passes an XML document and receives an XML document in response.
A sample WSDL for a POST operation using XML input is available here. Lets look at the key binding section. As before we specify the binding for the HTTP operation with a POST verb. The location is specified in the same way as before. This time though for the parameter handling we map the input to a part in the input message using mime:mimeXml to identify the input as an XML document. The output is mapped as before
<binding name="HttpPostXMLBinding" type="tns:HttpPostXMLPortType">
<http:binding verb="POST"/>
<operation name="PostData">
<http:operation location="/EchoApp/echo"/>
<input>
<mime:mimeXml part="param"/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
This binding will cause the body of the request to consist of the XML document specified in the given message part. If we have the input message definition shown below then the request URL would be encoded as /EchoApp/echo with the body containing the an XML document with a root element of “<get:HttpClientBPELProcessProcessRequest>”. Note that the input message should have a single part. The response is handled in the same way as with the GET and the previous POST.
<message name="HttpPostXMLIn">
<part name="param"
element="get:HttpClientBPELProcessProcessRequest"/>
</message>
<message name="HttpPostXMLOut">
<part name="Body" element="get:Request"/>
</message>
The actual server location of the target is given in the service section of the WSDL in the same way as the previous GET and POST requests.
The above definitions then let us call a service using the POST verb, passing an XML document as input and receiving an XML document as a response. Using this WSDL we can call the HTTP POST based service as though it were any other WSDL described web service.
Sample Code
A complete example is available for download. To use it first deploy the example echo WAR file and then deploy the BPEL process which will call the sample echo application three times, once via a GET, once via a POST with forms style parameters and once via a POST with XML input. The three results are stored in a sequence and returned from the BPEL process.
Summary
In this entry I have spoken about using the HTTP WSIF binding to provide a an HTTP adapter in BPEL. It should also work fine with ESB. OSB currently has a different (and easier) way of calling HTTP based services. When creating an HTTP WSIF process it is generally a good idea to start with a working one and modify it to reflect your data types and endpoints.
So in answer to the question that started all this; is there an HTTP Adapter? No there isn’t a nice adapter wizard to use HTTP bindings, but yes there is support for HTTP bindings through WSIF.