We live in a service oriented world. Or we will do so in the very near future. Services are all around us. And mind you: services not just as in WebServices or BPEL Processes. Services as in well defined interfaces that provide reusable functionality with clearly specified input and output parameters. And that definition covers a lot of existing ‘legacy’ functionality, implemented in a plethora of technologies. Much of which, grantedly, is not already exposed with a well-defined interface. But than again: according to that definition, many services do exist.
A vast domain of services lurks behind the HTTP protocol. With straightforward GET and POST request messages can we invoke services within our intranets and across the internet. The response message can be generated by Java based applications – such as Servlets or JSPs – and just as easy by VB.NET, C#, Perl, (MOD_)PLSQL, PHP -powered applications. Publishing a service as a simple HTTP ‘end-point’ is easy. We have been doing that for a long time. Frequently these services return markup language – HTML – but some already reply in XML messages. Let’s agree that implementing services and exposing existing functionality as services is within our grasp if it can be as simple as deploying a PHP page or a Servlet.
One of the major service consuming forces to be reckoned with is of course the body of of BPEL processes that we have implemented or will develop in the near future. So it is important to know how HTTP services can be invoked from within BPEL processes. That is what this article is about. And fortunately, it turns out to be quite simple. The essence really is not BPEL specific – it is creating a WSDL (Web Service Definition Language) document, based on the WSIF extensions to WSDL (specifically the HTTPBinding), for our HTTP service.
The steps for BPEL-enabling HTTP services are
- create or locate the HTTP service to leverage from the BPEL Process – that is: the Servlet, JSP, PHP or Perl program we deploy on our web server
- specify the input and the output parameters for the service – for a GET service that is for example the list of parameters appended to the URL with ?param=value¶m2=value
- create the WSDL document with the HTTP binding and possibly the XSD for the type definitions for complex types in request or – more likely – response
Using this WSDL document, we can create a PartnerLink in our BPEL process and Invoke this PartnerLink.
The HTTP Service – The Hotel Booking Method Service
Let’s look at an example service. Our Service is a very simple one: it takes the name of an hotel as input parameter and returns the method to contact this hotel as well as the contact-details like email-address. The Service is published through a Servlet:
package nl.amis.coa.rules; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.*; import javax.servlet.http.*; public class HotelBookingMethodServiceServlet extends HttpServlet { private static final String CONTENT_TYPE = "text/xml; charset=windows-1252"; public void init(ServletConfig config) throws ServletException { super.init(config); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); String hotelName = (String)request.getParameter("hotelName"); HotelBookingMethod bookingMethod = HotelRulesService.getHotelBookingMethod(hotelName); out.println("<coa:hotelBooking xmlns:coa=\"http://coa.amis.nl/HotelRules\"><coa:bookingMethod>"+bookingMethod.bookingMethod+"</coa:bookingMethod><coa:hotelContact>"+bookingMethod.getContactDetails()+"</coa:hotelContact></coa:hotelBooking>"); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType(CONTENT_TYPE); doGet(request, response); } }
The Servlet expects a parameter called hotelName. It writes its response as a piece of XML that looks like this:
<coa:hotelBooking xmlns:coa="http://coa.amis.nl/HotelRules"> <coa:bookingMethod>manual</coa:bookingMethod> <coa:hotelContact>053-302150</coa:hotelContact> </coa:hotelBooking>
The servlet uses additional backoffice services – the HotelRulesService class – that presumably access enterprise resources for retrieving the required information. Of course we as Service Consumers do not need to know about such internals.
Creating the WSDL document
Now we need to express our HTTP Service through a WSDL document. This document has a standard structure that specifies the service, the operations, the input and output parameters, the fauls or exceptions that can be raised and the physical protocol and end point location required for the actual access of the service. The WSDL for our Servlet based service looks as follows:
<?xml version="1.0" encoding="utf-8"?> <definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://coa.amis.nl/HotelRules" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" targetNamespace="http://coa.amis.nl/HotelRules" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <xsd:schema elementFormDefault="qualified" targetNamespace="http://coa.amis.nl/HotelRules"> <xsd:element name="hotelBooking"> <xsd:complexType> <xsd:sequence> <xsd:element name="bookingMethod" type="xsd:string"/> <xsd:element name="hotelContact" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="hotel" type="xsd:string"/> </xsd:schema> </types> <message name="GetStockQuoteHttpGetIn"> <part name="hotelName" element="tns:hotel" /> </message> <message name="GetStockQuoteHttpGetOut"> <part name="Body" element="tns:hotelBooking"/> </message> <portType name="HotelRulesHttpGet"> <operation name="GetHotelBookingMethod"> <input message="tns:GetStockQuoteHttpGetIn"/> <output message="tns:GetStockQuoteHttpGetOut"/> </operation> </portType> <binding name="HotelRulesHttpGet" type="tns:HotelRulesHttpGet"> <http:binding verb="GET"/> <operation name="GetHotelBookingMethod"> <http:operation location="/COA_WEB-COARules-context-root/hotelbookingmethodserviceservlet"/> <input> <http:urlEncoded/> </input> <outp ut> <mime :mimeXml part="Body"/> </output> </operation> </binding> <service name="HotelRules"> <port name="HotelRulesHttpGet" binding="tns:HotelRulesHttpGet"> <http:address location="http://localhost:8988/"/> </port> </service> <plnk:partnerLinkType name="HotelRulesService"> <plnk:role name="HotelRulesServiceProvider"> <plnk:portType name="tns:HotelRulesHttpGet"/> </plnk:role> </plnk:partnerLinkType> </definitions>
Here we see a number of sections. We can start with service element. This specifies the overall service (HotelRules) and ties it to a specific port. The port is a combination of a physical location (the base url where the service is deployed) and a binding. The binding joins a functional service description (the portType) with a protocol specific binding (http:binding). The binding defines operations and for each contains the second part of the url that directs us to the specific servlet/page/module that implements the specific operation. It also specifies the ‘physical’ characteristics of the input and output of the service. The logical definition of the input and the output is defined withing the portType element.
It is important to realize that the Oracle BPEL PM knows how to invoke services that have an http:binding, instead of the more common soap:binding. Interpreting the logical part of the WSDL is the same for SOAP WebServices and HTTP based services but actually making the service request requires the BPEL engine to interact over the HTTP protocol. The details of the actual service call are completely shielded from us: based on the WSDL, the BPEL engine makes the call.
<portType name="HotelRulesHttpGet"> <operation name="GetHotelBookingMethod"> <input message="tns:GetStockQuoteHttpGetIn"/> <output message="tns:GetStockQuoteHttpGetOut"/> </operation> </portType>
The portType element specifies the logical operation GetHotelBookingMethod. It indicates that the input should be of message type tns:GetStockQuoteHttpGetIn and the output is of type tns:GetStockQuoteHttpGetOut. The definitions of these messages is also in the WSDL:
<message name="GetStockQuoteHttpGetIn"> <part name="hotelName" element="tns:hotel" /> </message> <message name="GetStockQuoteHttpGetOut"> <part name="Body" element="tns:hotelBooking"/> </message>
and the messages are built on types that too are in the WSDL (could also have been in an external XSD):
<types> <xsd:schema elementFormDefault="qualified" targetNamespace="http://coa.amis.nl/HotelRules"> <xsd:element name="hotelBooking"> <xsd:complexType> <xsd:sequence> <xsd:element name="bookingMethod" type="xsd:string"/> <xsd:element name="hotelContact" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="hotel" type="xsd:string"/> </xsd:schema> </types>
The hotel type is a very simple one, just a single string that is called hotel. The hotelBooking is a slightly more complex one, that contains child elements bookingMethod and hotelContact. Note that this definition is the
one that describes the servlet response that we saw earlier:
<coa:hotelBooking xmlns:coa="http://coa.amis.nl/HotelRules"> <coa:bookingMethod>manual</coa:bookingMethod> <coa:hotelContact>053-302150</coa:hotelContact> </coa:hotelBooking>
With the WSDL in hand, we can include this Service in our BPEL Process.
Invoking the HTTP Service from the BPEL Process
Our BPEL Process deals with the Registration of an Attendee for a Conference. As part of the registration, our BPEL process can make a Hotel reservation if so requested by the registree. The Conference visitor can select a hotel from a list of several options. Our BPEL process then will either automatically invoke the hotel’s reservation service – if there is one – or start a Humanual Task (a bit of workflow) that requires one of the back office staff to call or fax the hotel to make the reservation. We need the HotelRulesService to tell us what the method is to contact a specific hotel and also to learn the contact details for that particular hotel.
Creating the PartnerLink for the HotelBookingRulesService is no different from creating any PartnerLink based on a WSDL document. We simply select the WSDL and the BPEL Designer interprets the WSDL and helps us to set up the invoke and the input and output variables.
The definition of the (structure of the) Input and Output variable are taken from the Messages and Types defined in the WSDL. We can now easily set up the input variable and retrieve the values we need from the output:
<sequence name="Sequence_8"> <scope name="ZoekHotelReserveringsRegels"> <variables> <variable name="Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_InputVariable" messageType="ns15:GetStockQuoteHttpGetIn"/> <variable name="Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable" messageType="ns15:GetStockQuoteHttpGetOut"/> </variables> <sequence name="Sequence_10"> <assign name="PrepareHotelBookingsRulesService_Input"> <copy> <from expression="'manual'"/> <to variable="TypeReservering"/> </copy> <copy> <from variable="COARegistration" part="COAWebConferenceRegistration" query="/COAWebConferenceRegistration/hotelName"/> <to variable="Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_InputVariable" part="hotelName" query="/ns15:hotel"/> </copy> </assign> <invoke name="Invoke_HotelBookingsRulesService" partnerLink="HotelBoekingRulesService" portType="ns15:HotelRulesHttpGet" operation="GetHotelBookingMethod" inputVariable="Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_InputVariable" outputVariable="Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable"/> <assign name="ProcessBookingMethod"> <copy> <from variable="Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable" part="Body" query="/ns15:hotelBooking/ns15:bookingMethod"/> <to variable="TypeReservering"/> </copy> <copy> <from variable="Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable" part="Body" query="/ns15:hotelBooking/ns15:hotelContact"/> <to variable="HotelContact"/> </copy> </assign> </sequence> ..
More visually pleasing:
Note that nothing in the BPEL process is special because we invoke an HTTP Binding, a Service that is implemented and deployed as a Servlet. The WSDL provides the logical definition and that is all that matters – because the BPEL Engine knows how to deal with the http:binding and the URL that are specified in the WSDL. If we were to change the deployment method for this service, into for example a SOAP WebService, all we need to do is change the PORT and BINDING sections of the WSDL, redeploy the changed WSDL (and nothing else) and we are in business with the newly deployed – yet logically identical – service.
Running the BPEL Process and Accessing the HTTP Service
Running this BPEL Process is obviously not different from running any BPEL Process. The fact that now a HTTP Servlet is invoked matters not in the least.
So we normally deploy the BPEL Process to the Oracle BPEL PM, have it invoked in whatever way it is invoked – in this case by the reception of an email – and see if it calls the servlet. Of course for this to happen, we must make sure that the Servlet is available at the url where we specified in the WSDL it would be available. So the WebServer at http://localhost:8988/ must be up and running.
If we look in the BPEL PM Console, it is easy to find out what happened when the process had to call out to our HotelBookingMethodRulesService:
Conclusion
Many service are already available for simple HTTP invocation. They can be implemented in Java, PHP, Perl, C# or any technology that can be exposed by a webserver and can handle HTTP Requests. Publishing these services in a way that makes them accessible to the Oracle BPEL PM is straightforward: we need to create a WSDL document for the service, specify the http:binding, provide the physical location of the service and from there on we can treat this service like any other service we create partnerlinks for.
How can I specify UTF-8 encoding on the generated get call based on the WSDL?
Thanks,
J
Could you please send the source code for Oracle 11 g SOA suite as I am not able to run this example.
regards,
Anil verma
That was great post.
By the way does HTTP Binding in WSDL support “multipart/form-data”. ?
We have one HTTP service running , which accepts files to be uploaded on to the server.But it only accepts “multipart/form-data”. I could invoke the service from my Browser using “INPUT TYPE=”FILE” NAME=”userFile” size=70″ in my html page.
But wondering how we can achieve this in BPEL/WSDL?
Thanks
/Mishit
Could you post the complete wsdl
Nice article…
I have a requirement where I have to download a file from a external server using HTTPS method. Can I use the HTTPBinding in BPEL to download the file. I have been given an hostname, port ,userid and passworrd.. How can I download this file from the target location using BPEL HTTPS route ??
Thanks
Sunil
Hi Lucas,
Nice article. Can you please provide the sample code of the wsdl file. I was particular interested in the binding part info. I assume that the binding syntax will be http:binding
and the rest of the syntax follows the same as the soap:binding.
Please clarify.
Best Regards,
Purushottaman
Hi Lucas
Can you please tell me little more detail on invoking jsp application (URL) from BPEL using HTTP POST, also how to send the URL parameters
Lucas, what would you change/add if this example was invoking a HTTP service on a secured server? Meaning, if you had to first (http) authenticate with the App server like you would do through a browser pop-up window.
I have used this method before to read out a students website using HTTP binding, you can simply make a dummy webservice(BPEL) that connects using HTTP binding and call this as a partnerlink in your process, you will have to transform the Mime output ..
Nice article, i had to find it out the hardway !!
Regards,
Aiman
Jean, The JSP is invoked at a URL; it may use URL Request Parameters. Say your URL is http://host:port/dir/page.jsp?a=1&b=2. Once we are talking about the JSP in terms of a URL, the article applies just like it works for the HotelBooking Servlet. The essence is that BPEL invokes the URL over HTTP. Whatever is lurking behind the URL is of no consequence.
best regards,
Lucas
Hi Lucas,
It’s very good article but I have a question about this.
If I have to invoke JSP page through HTTP Binding, how can I create WSDL Document from the JSP?
Thanks.
How do i call an http service that does not support unicode.(windows-1255)
the input to the bpel process is in unicode.
Hi Lucas,
I suppose I can POST instead of GET in your example. If so what should I put into the tag inside of the binding? is only working with GET.
Thanks,
Nathan Tsang
Clemens (Utschig, SOA Product Management Team @ Oracle Headquarters) is nice about this article in his own weblog, at http://clemensblog.blogspot.com/2006/07/bpel-samples-where-do-i-fi_115213595643785035.htm.
Hi Dimitri,
Of course any service implemented using APEX that is available through a normal HTTP Request can be used in the same way. Just define the service through a WSDL and you can get going.
This solution is certainly not SOAP and I suppose you could call it REST, though I am not sure if that is correct in a very strict and formal way.
best regards,
Lucas
Hi Lucas,
I suppose we can also make the above in APEX (PL/SQL)?
I don’t know this BPEL – Webservices domain very well, but I’d like to know if the above solution is based on SOAP or REST?
Thanks,
Dimitri