Invoking web services dynamically in BPEL 1.1
By Andy.Knight on Aug 02, 2011
This topic has been covered in postings that can be found at various locations. Your favourite search engine will reveal them to you.
Unfortunately, not all of these posts are up-to-date and some are just confusing. My intention here is to demonstrate a practical example from beginning to end using modern Oracle technologies. I have used JDeveloper 220.127.116.11.0 and Weblogic Server 10.3. I am assuming that the reader is familiar with JDeveloper, deploying to Weblogic and using the Weblogic Enterprise Manager (for testing purposes).
Before one can invoke a web service via its well-known endpoint, it is important to understand a significant restriction of this technique. Each web service must have identical message, port and namespace definitions. These need to be known at design time. So what's the point of this? The benefit of this technique is that services located at different endpoints may be invoked based on runtime decisions (data driven). Indeed, the payload of the input message to the "driver" code [ see later ] may even contain the endpoint address. Thus, different functionality can be easily achieved by being able to invoke completely different services or perhaps just different versions of a service (providing the different versions are deployed and their endpoints are well known).
The development of this demonstration is strictly "bottom up". We need to define our web service message structure. Implement and deploy the web service. "Clone" that service as many times as is necessary to give the number of services you need [ more detail later ]. We'll just build 2 services.
Here's the schema definition for our messages:-
<?xml version="1.0" encoding="windows-1252" ?>
<xsd:element name="Endpoint" type="xsd:string"/>
<xsd:element name="parameter" type="xsd:string"/>
<xsd:element name="parameter" type="xsd:string"/>
<xsd:element name="status" type="xsd:string"/>
For the purposes of this example, we have an input message that contains Endpoint (being the endpoint of the service we intend to invoke) and parameter which is an arbitrary value that the service will "echo" to the invoker.
The output contains parameter (being the value that will be echoed) and status which will contain some value unique to the service.
So let's start to design, build and deploy our project.
Create a new SOA application in JDeveloper and call it ATeamDynamic and specify an Application Package Prefix of your choice.
Name the Project Service_1 and we'll start with an empty Composite.
Create an XML Schema Definition in the project's xsd folder and call it common.xsd. Don't worry about the namespace declaration because we'll now overwite the xsd stub. Populate the schema with the xml shown above. Also, please note that for the sake of brevity we will use this schema for both the service(s) and the "driver" even though the Endpoint element is only significant in the driver process (i.e. not used by the service itself).
Drag a BPEL process onto the Composite canvas. Ensure that BPEL Spec' 1.1 is checked. Name the BPEL activity as Process. Specify http://xmlns.oracle.com/ATeamDynamic/Service/Process as its namespace. Select Synchronous BPEL Process as the template. [ The service does not need to be synchronous for it to be usable dynamically but, obviously, the driver would have to be constructed differently if it was asynchronous ] The service name should read process_client.
Expose as a SOAP Service should be checked. Use the element browser to locate the input and output messages from the schema definition we created earlier.
Double-click the BPEL activity to go into the BPEL designer.
Drag an Assign activity onto the BPEL design canvas between the receive and reply activities.
Double-click the assign and do this:-
So all we're doing is to copy (echo) the parameter value and set the status to "Service 1".
Deploy the Project to Weblogic. In Enterprise Manager, test this service to ensure that it runs as expected. The tester will require an Endpoint value even though it's not used. The parameter value should be echoed and the Status should indicate "Service 1".
We will now create the second service. In JDeveloper, create a new SOA Project and name it Service_2. The procedure is exactly the same as for Service_1 except that we don't need to create the xsd (we can re-use what we've already built) and in the BPEL Assign, we will copy the expression "Service 2" to the status element. Everything else is identical.
Now for the exciting part - the Dynamic Driver.
Create a new SOA Project and call it DynamicDriver and we'll start with an empty Composite.
Drag a BPEL process onto the canvas. The name and namespace can be of your choosing. Use the Synchronous template for ease of testing. We will expose this as a SOAP service and use the same message types as before - i.e. from the common.xsd we created earlier.
Double-click the BPEL process.
Drag a PartnerLink Web Service Construct into the right-hand swim lane. The name can be anything of your choosing. We now need the deployed WSDL for one of the services we built / deployed earlier (it doesn't matter which one). So, in the Create PartnerLink Wizard, we need to enter the WSDL URL. The easiest way to do this is to go back to the Enterprise Manager test page for Service_1 (or Service_2). On the test page you will see the WSDL query URL. It will look something like this:-
Copy and paste this URL into the Wizard. Click on PartnerLink Type. It will show as Process. Click on PartnerRole and select ProcessProvider. Click OK - i.e. leave My Role as "--Not Specified--".
Drag an Invoke Construct onto the canvas between the receive and reply activities.. Connect the invoke to the PartnerLink. Create input and output variables as input and output respectively. [ I chose short generic names for brevity ]
We now need a new schema definition. We'll start by creating a stub. Create a new schema definition in the xsd folder of the DynamicDriver project. Name it ws-addressing.xsd (although it could be called anything). Don't worry about its content yet.
In your favourite browser, enter this URL http://schemas.xmlsoap.org/ws/2003/03/addressing/
This will reveal the ws-addressing schema that you need. Use your browser's "view source" mechanism then copy and paste into your newly created ws-addressing.xsd
Now let's go back to the BPEL Editor and we'll create a new variable. Call it EndpointReference. Click the radio button labelled Element then browse for the EndpointReference element in the ws-addressing schema.
Drag an Assign construct onto the canvas immediately before the Invoke.
We now have to implement three copy activities within the Assign.
Firstly, copy this XML fragment into the EndpointReference variable:-
<EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing" xmlns:ns1="http://xmlns.oracle.com/AteamDynamic/Service/Process"><Address/><ServiceName>ns1:process_client_ep</ServiceName></EndpointReference>
Note that the ns1 namespace declaration and the ServiceName depend entirely on the developer having followed the naming conventions described herein.
We then need to copy the Endpoint part of the inputVariable to the Address part of the EndpointReference.
The third and final step for setting up the PartnerLink is simply to copy the EndpointReference to the PartnerLink. It should look like this:-
Unusually, this may be easier to read in source mode thus:-
[ Please note that at deployment (build) time, a warning will be emitted concerning the 2nd copy because of a type mismatch. This is expected and may be ignored ]
Now we need to populate the payload for the Web Service itself thus:-
The WS doesn't use the Endpoint value but we need to copy something as the schema dictates that this element is mandatory.
After the Invoke, we'll need to get the WS response like this:-
Now we can deploy the DynamicDriver Project and test it.
In Enterprise Manager, start by selecting the Service_1 Project and then the Test tab. There you will see the endpoint URL for this service. Copy this URL.
Now select the DynamicDriver Project then the Test tab. Paste the Service_1 URL into the Endpoint field followed by some arbitrary text in the Parameter field. Click Test Web Service. If all is well, you will see the parameter value echoed and a status of "Service 1" indicating that the correct WS has been called.
Repeat the test for Service_2.
The complete Application is available here