Invoking HTTP Services from Oracle BPEL PM – SOA enabling PHP, Servlets, RSS,…

16

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&param2=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;<br /><br />import java.io.IOException;<br />import java.io.PrintWriter;<br /><br />import java.util.Enumeration;<br /><br />import javax.servlet.*;<br />import javax.servlet.http.*;<br /><br />public class HotelBookingMethodServiceServlet extends HttpServlet {<br />    private static final String CONTENT_TYPE = &quot;text/xml; charset=windows-1252&quot;;<br /><br />    public void init(ServletConfig config) throws ServletException {<br />        super.init(config);<br />    }<br /><br />    public void doGet(HttpServletRequest request, <br />                      HttpServletResponse response) throws ServletException, IOException {response.setContentType(CONTENT_TYPE);<br />        PrintWriter out = response.getWriter();<br />        String hotelName = (String)request.getParameter(&quot;hotelName&quot;);<br />        <br />        HotelBookingMethod bookingMethod = HotelRulesService.getHotelBookingMethod(hotelName);<br />        out.println(&quot;&lt;coa:hotelBooking xmlns:coa=\&quot;http://coa.amis.nl/HotelRules\&quot;&gt;&lt;coa:bookingMethod&gt;&quot;+bookingMethod.bookingMethod+&quot;&lt;/coa:bookingMethod&gt;&lt;coa:hotelContact&gt;&quot;+bookingMethod.getContactDetails()+&quot;&lt;/coa:hotelContact&gt;&lt;/coa:hotelBooking&gt;&quot;);<br />        out.close();<br />    }<br /><br />    public void doPost(HttpServletRequest request, <br />                       HttpServletResponse response) throws ServletException, IOException {response.setContentType(CONTENT_TYPE);<br />      doGet(request, response);<br />    }<br />}<br />&nbsp;

The Servlet expects a parameter called hotelName. It writes its response as a piece of XML that looks like this:

&lt;coa:hotelBooking xmlns:coa=&quot;http://coa.amis.nl/HotelRules&quot;&gt;<br />  &lt;coa:bookingMethod&gt;manual&lt;/coa:bookingMethod&gt;<br />  &lt;coa:hotelContact&gt;053-302150&lt;/coa:hotelContact&gt;<br />&lt;/coa:hotelBooking&gt;<br />

 

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:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;<br />&lt;definitions xmlns:http=&quot;http://schemas.xmlsoap.org/wsdl/http/&quot;<br />             xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot;<br />             xmlns:tns=&quot;http://coa.amis.nl/HotelRules&quot;<br />             xmlns:mime=&quot;http://schemas.xmlsoap.org/wsdl/mime/&quot;<br />             xmlns:plnk=&quot;http://schemas.xmlsoap.org/ws/2003/05/partner-link/&quot;<br />             targetNamespace=&quot;http://coa.amis.nl/HotelRules&quot;<br />             xmlns=&quot;http://schemas.xmlsoap.org/wsdl/&quot;&gt;<br />  &lt;types&gt;<br />    &lt;xsd:schema elementFormDefault=&quot;qualified&quot;<br />                targetNamespace=&quot;http://coa.amis.nl/HotelRules&quot;&gt;<br />      &lt;xsd:element name=&quot;hotelBooking&quot;&gt;<br />        &lt;xsd:complexType&gt;<br />          &lt;xsd:sequence&gt;<br />            &lt;xsd:element name=&quot;bookingMethod&quot; type=&quot;xsd:string&quot;/&gt;<br />            &lt;xsd:element name=&quot;hotelContact&quot; type=&quot;xsd:string&quot;/&gt;<br />          &lt;/xsd:sequence&gt;<br />        &lt;/xsd:complexType&gt;<br />      &lt;/xsd:element&gt;<br />      &lt;xsd:element name=&quot;hotel&quot; type=&quot;xsd:string&quot;/&gt;<br />    &lt;/xsd:schema&gt;<br />  &lt;/types&gt;<br />  &lt;message name=&quot;GetStockQuoteHttpGetIn&quot;&gt;<br />  &lt;part name=&quot;hotelName&quot; element=&quot;tns:hotel&quot; /&gt;<br />  &lt;/message&gt;<br />  &lt;message name=&quot;GetStockQuoteHttpGetOut&quot;&gt;<br />    &lt;part name=&quot;Body&quot; element=&quot;tns:hotelBooking&quot;/&gt;<br />  &lt;/message&gt;<br />  &lt;portType name=&quot;HotelRulesHttpGet&quot;&gt;<br />    &lt;operation name=&quot;GetHotelBookingMethod&quot;&gt;<br />      &lt;input message=&quot;tns:GetStockQuoteHttpGetIn&quot;/&gt;<br />      &lt;output message=&quot;tns:GetStockQuoteHttpGetOut&quot;/&gt;<br />    &lt;/operation&gt;<br />  &lt;/portType&gt;<br />  &lt;binding name=&quot;HotelRulesHttpGet&quot; type=&quot;tns:HotelRulesHttpGet&quot;&gt;<br />    &lt;http:binding verb=&quot;GET&quot;/&gt;<br />    &lt;operation name=&quot;GetHotelBookingMethod&quot;&gt;<br />      &lt;http:operation location=&quot;/COA_WEB-COARules-context-root/hotelbookingmethodserviceservlet&quot;/&gt;<br />      &lt;input&gt;<br />        &lt;http:urlEncoded/&gt;<br />      &lt;/input&gt;<br />      &lt;outp
ut&gt;<br />        &lt;mime
:mimeXml part=&quot;Body&quot;/&gt;<br />      &lt;/output&gt;<br />    &lt;/operation&gt;<br />  &lt;/binding&gt;<br />  &lt;service name=&quot;HotelRules&quot;&gt;<br />    &lt;port name=&quot;HotelRulesHttpGet&quot; binding=&quot;tns:HotelRulesHttpGet&quot;&gt;<br />      &lt;http:address location=&quot;http://localhost:8988/&quot;/&gt;<br />    &lt;/port&gt;<br />  &lt;/service&gt;<br />  &lt;plnk:partnerLinkType name=&quot;HotelRulesService&quot;&gt;<br />    &lt;plnk:role name=&quot;HotelRulesServiceProvider&quot;&gt;<br />      &lt;plnk:portType name=&quot;tns:HotelRulesHttpGet&quot;/&gt;<br />    &lt;/plnk:role&gt;<br />  &lt;/plnk:partnerLinkType&gt;<br />&lt;/definitions&gt;<br />&nbsp;

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.

  &lt;portType name=&quot;HotelRulesHttpGet&quot;&gt;<br />    &lt;operation name=&quot;GetHotelBookingMethod&quot;&gt;<br />      &lt;input message=&quot;tns:GetStockQuoteHttpGetIn&quot;/&gt;<br />      &lt;output message=&quot;tns:GetStockQuoteHttpGetOut&quot;/&gt;<br />    &lt;/operation&gt;<br />  &lt;/portType&gt;<br />&nbsp;

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:

  &lt;message name=&quot;GetStockQuoteHttpGetIn&quot;&gt;<br />  &lt;part name=&quot;hotelName&quot; element=&quot;tns:hotel&quot; /&gt;<br />  &lt;/message&gt;<br />  &lt;message name=&quot;GetStockQuoteHttpGetOut&quot;&gt;<br />    &lt;part name=&quot;Body&quot; element=&quot;tns:hotelBooking&quot;/&gt;<br />  &lt;/message&gt;<br />&nbsp;

and the messages are built on types that too are in the WSDL (could also have been in an external XSD):

  &lt;types&gt;<br />    &lt;xsd:schema elementFormDefault=&quot;qualified&quot;<br />                targetNamespace=&quot;http://coa.amis.nl/HotelRules&quot;&gt;<br />      &lt;xsd:element name=&quot;hotelBooking&quot;&gt;<br />        &lt;xsd:complexType&gt;<br />          &lt;xsd:sequence&gt;<br />            &lt;xsd:element name=&quot;bookingMethod&quot; type=&quot;xsd:string&quot;/&gt;<br />            &lt;xsd:element name=&quot;hotelContact&quot; type=&quot;xsd:string&quot;/&gt;<br />          &lt;/xsd:sequence&gt;<br />        &lt;/xsd:complexType&gt;<br />      &lt;/xsd:element&gt;<br />      &lt;xsd:element name=&quot;hotel&quot; type=&quot;xsd:string&quot;/&gt;<br />    &lt;/xsd:schema&gt;<br />  &lt;/types&gt;<br /><br />

 

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:

&lt;coa:hotelBooking xmlns:coa=&quot;http://coa.amis.nl/HotelRules&quot;&gt;<br />  &lt;coa:bookingMethod&gt;manual&lt;/coa:bookingMethod&gt;<br />  &lt;coa:hotelContact&gt;053-302150&lt;/coa:hotelContact&gt;<br />&lt;/coa:hotelBooking&gt;<br />&nbsp;

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:

&lt;sequence name=&quot;Sequence_8&quot;&gt;<br />  &lt;scope name=&quot;ZoekHotelReserveringsRegels&quot;&gt;<br />  &lt;variables&gt;<br />    &lt;variable name=&quot;Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_InputVariable&quot; messageType=&quot;ns15:GetStockQuoteHttpGetIn&quot;/&gt;<br />    &lt;variable name=&quot;Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable&quot; messageType=&quot;ns15:GetStockQuoteHttpGetOut&quot;/&gt;<br />  &lt;/variables&gt;<br />  &lt;sequence name=&quot;Sequence_10&quot;&gt;<br />    &lt;assign name=&quot;PrepareHotelBookingsRulesService_Input&quot;&gt;<br />      &lt;copy&gt;<br />        &lt;from expression=&quot;'manual'&quot;/&gt;<br />        &lt;to variable=&quot;TypeReservering&quot;/&gt;<br />      &lt;/copy&gt;<br />      &lt;copy&gt;<br />        &lt;from variable=&quot;COARegistration&quot; part=&quot;COAWebConferenceRegistration&quot; query=&quot;/COAWebConferenceRegistration/hotelName&quot;/&gt;<br />        &lt;to variable=&quot;Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_InputVariable&quot; part=&quot;hotelName&quot; query=&quot;/ns15:hotel&quot;/&gt;<br />      &lt;/copy&gt;<br />    &lt;/assign&gt;<br />    &lt;invoke name=&quot;Invoke_HotelBookingsRulesService&quot; partnerLink=&quot;HotelBoekingRulesService&quot; portType=&quot;ns15:HotelRulesHttpGet&quot; operation=&quot;GetHotelBookingMethod&quot; inputVariable=&quot;Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_InputVariable&quot; outputVariable=&quot;Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable&quot;/&gt;<br />    &lt;assign name=&quot;ProcessBookingMethod&quot;&gt;<br />      &lt;copy&gt;<br />        &lt;from variable=&quot;Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable&quot; part=&quot;Body&quot; query=&quot;/ns15:hotelBooking/ns15:bookingMethod&quot;/&gt;<br />        &lt;to variable=&quot;TypeReservering&quot;/&gt;<br />      &lt;/copy&gt;<br />      &lt;copy&gt;<br />        &lt;from variable=&quot;Invoke_HotelBoekingsRulesService_GetHotelBookingMethod_OutputVariable&quot; part=&quot;Body&quot; query=&quot;/ns15:hotelBooking/ns15:hotelContact&quot;/&gt;<br />        &lt;to variable=&quot;HotelContact&quot;/&gt;<br />      &lt;/copy&gt;<br />    &lt;/assign&gt;<br />  &lt;/sequence&gt;<br />&nbsp; ..

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.

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

16 Comments

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. 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.

  7. 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

  8. 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

  9. 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.

  10. How do i call an http service that does not support unicode.(windows-1255)
    the input to the bpel process is in unicode.

  11. 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

  12. 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

  13. 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