(or how to have the same WLI XMLCache functionality in BPEL PM)
Part one : Get the data from the cache
Source :
Excellent article from Simone : http://www.oracle.com/technetwork/topics/soa/dynamic-data-lookup-endpoints-geib-092046.html
When I read Simone’s article, I thought it was nice but I also thought that it did not go as far as I expected. In her example, she took a typical database example, with a set of data, identified by an ID. It’s a very interesting feature, but it does not meet exactly my requirement ...
That’s why I’m going to write (with Simone’s permission :D) a little addendum which will help WLI users to transpose their good old WLI XMLCache to BPEL PM DVM.
The need for such a configuration is pretty obvious : I want to be able to deploy my project in several different environments without updating the code to reflect a changing server URL : typically, in a development environment, it would be an Apache and in a production environment, it would be an Alteon or a Big-Ip, for instance.
In my case, I decided to divide my configuration into two different DVM. The first one is only composed of what’s going to change (URLs mostly …) and the other one will contain the “immutable” parts, that is to say the things that won’t change from an environment to another (context paths here).
To know how to create a DVM, please refer to Simone’s article.
Here is the first DVM :
Property | Value |
ServiceEntrypoint | http://IPAddress:port |
To get the value of the “ServiceEntrypoint” property, I will have to use a BPEL function :
dvm:lookupValue1M("environment.dvm", "Property", 'ServiceEntrypoint', "Value") which will return “http://ipaddress:port/”
Here is the second one :
ServiceName | ContextPath |
TestWS | /contextPath |
By the way, pay attention to to way you are filling data : columns are lines here :)
To get the context of my service, the function is the same as the one we used above :
dvm:lookupValue1M("servicepaths.dvm", "ServiceName", TestWS, "ContextPath") which will return “/contextPath”
Now we have the way to retrieve our two values, we can go in our BPEL Process.
Here are the thing to perform.
1) Define variables
<variable name="serviceEntrypoint" type="xsd:string"/>
<variable name="contextPath" type="xsd:string"/>
<variable name="endpoint" type="xsd:string"/>
No magic here : a endpoint value which will receive the concatenation of the serviceEntrypoint and a contextPath.
2) Define a namespace in your BPEL process
xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
To be able to use DVMs. And if you are copying directly the code from the article, JDev won’t import for you the “xsd” namespace, then add it manually :
3) Concatenate the information
In an Assign activity, concatenate the result of these two functions in a single string :
<assign name="Endpoint">
<copy>
<from expression='dvm:lookupValue1M("environment.dvm", "Property", "ServiceEntrypoint", "Value")'/>
<to variable="serviceEntrypoint"/>
</copy>
<copy>
<from expression='dvm:lookupValue1M("servicepaths.dvm", "ServiceName", "TestWS", "ContextPath")'/>
<to variable="contextPath"/>
</copy>
<copy>
<from expression="concat(bpws:getVariableData('serviceEntrypoint'), bpws:getVariableData('contextPath'))"/>
<to variable="endpoint"/>
</copy>
</assign>
I guess the code is clear enough …
Part two : design a test webservice
I guess you know how to do it, so I won’t spend much time explaining it.
Just design a small webservice “HelloWorld” or whatever to have something to call from our BPEL Process :)
Once deployed, get the generated contextPath by going to the WLS console, in the section deployment, the name should be “AppName-ProjectName-context-root”
Click on the “+” next to your deployment and locate your webservice and click on it.
In the section “Testing”, click once again on the “+” just next to the webservice and you will have the choice to launch the TestClient or to display the WSDL.
In both cases, what’s important for us is the contextPath : /Blog-XMLCache-context-root/HelloWorldPort
Part three: assigning the URL to the partnerLink endpoint
Sources :
- (thread forum Oracle) http://forums.oracle.com/forums/thread.jspa?messageID=859569
- Blogpost http://blogs.oracle.com/dasoa/entry/11g_dynamic_partnerlink_example
- Official doc : http://download.oracle.com/docs/cd/E19182-01/821-0539/cnfg_bpel-se-dynamic-ptnrlink_c/index.html
A big thanks to Deepak who provided the GoDynamic example which helped me go through that mist.
Create a simple partnerLink toward the Webservice
First thing of all, we need to define a partnerLink. To do so, drag a partnerLinkfrom the palette in the right swimlane. It will start an assistant : just fill the information and enter the WSDL location :
http://localhost:7001/Blog-XMLCache-context-root/HelloWorldPort?WSDL
Click elsewhere and as soon as JDev detects the mouseOut event, it will display the WS port. Select the partnerRole and you’re done.
Drag and drop an “Invoke” activity and wire it to the partnerLink :
Once done, JDev may complain since the input var has not been initialized. Add a copy operation in the Assign activty, for instance :
But it doesn’t really matter, especially since I didn’t define any input for my webmethod. Anyway.
Update the partnerLink endpoint
To be able to change dynamically the endpoint of your partnerLink, we will need to use a XML element “EndpointReference”. That element is defined in a specific XSD which you need to import.
1) Import the ws-addressing.xsd in your XSD directory
This file is located in your JDev home :
[JDEV_HOME]/jdeveloper/integration/seed/soa/shared/common/ws-addressing.xsd
For instance, if you’re using the VB appliance, this file will be there :
/oracle/jdevhome/jdeveloper/integration/seed/soa/shared/common/ws-addressing.xsd
2) Define a namespace in your BPEL process
xmlns:dpl="http://schemas.xmlsoap.org/ws/2003/03/addressing"
3) Define an import in the WSDL of your BPEL process
<import namespace="http://schemas.xmlsoap.org/ws/2003/03/addressing" schemaLocation="xsd/ws-addressing.xsd"/>
4) Declare a variable, matching your namespace prefix
<variable name="endPointReference" element="dpl:EndpointReference"/>
5) Define an “Assign” activity
In a Assign activity, define those operations :
<assign name="PartnerLink">
<copy>
<from>
<EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing" xmlns:ns1="http://services.sap.com">
<Address/>
<ReferenceProperties/>
<ServiceName/>
</EndpointReference>
</from>
<to variable="endPointReference"/>
</copy>
<copy>
<from variable="endpoint"/>
<to variable="endPointReference" query="/dpl:EndpointReference/dpl:Address"/>
</copy>
<copy>
<from variable="endPointReference"/>
<to partnerLink="HelloWorldService"/>
</copy>
</assign>
Where “endpoint” is the wanted URL (in my case, I constructed it from a double DVM lookup)
6) Call your partnerLink through an Invoke activity
Everything is in the title :)
Now, you should have a BPEL process like that :
And from the composite view :
To sum up, we have a start node, then the first Assign activity, which gets the configuration information from the cache (DVM). Then a second assign activity that creates an empty “Endpoint” and copies the result of the previous assign (a concatenated string, representing the endpoint of our webservice) in the “address” property of the “Endpoint” variable.
Part four: testing our BPEL process
Okay, let’s roll ! Please note that I replaced “/contextPath” by the real context path of my service in the “ServicePaths.dvm” file.
As my project is hybrid (composed of a webservice & of a BPEL process), you will have to deploy it twice. Once as a webservice project and the other one … ok, I guess you see the point.
Once done, go on the EM and test your BPEL process.
Normally, you should have a successful test :
But now, if we change the server port to “8001”, in the “environment” DVM (either directly in the code, or through the SOA Composer), let’s see what’s happening :
Or if we take a closer look to the “DynamicPartnerLink” :
So, WLI users, here is a “simple” way to replace your good old XMLCache ! Hope it will help some WLI fellows :)