The basic principle behind a Service Oriented Architecture is to orchestrate functional building blocks, primarily web services, in order to achieve a solution which fulfills the given requirements. In order to create a robust solution using Oracle SOA Suite several best practices emerged, one being decoupling web services in order to overcome dependencies during server/composite startup. A general approach for achieving this best practice is to use abstract and concrete WSDLs in combination.
An example for a working reference definition within the composite could look like follows:
<reference name="FooBarService" ui:wsdlLocation="oramds:/apps/com/foo/v1/bar.wsdl"> <interface.wsdl interface="http://foo.com/BarService#wsdl.interface(BarService)"/> <binding.ws port="http://foo.com/BarService#wsdl.endpoint(BarService/FooBarEndpoint)" soapVersion="1.1" location="http://foo.com:7001/soa-infra/services/foo/bar/FooBarEndpoint?WSDL"> </binding.ws> </reference>
On a recent project we ran into some problems while implementing this best practice as some web services we had to consume not only protected their operations but also their WSDLs using basic authentication web security. Although we were able to access the operations by providing the security credentials within WebLogic Server using the Credential Store Framework (CSF), the solution never managed to successfully access the secured WSDL files.
After trying several approaches to overcome this problem, we implemented a workaround by storing an abstract WSDL within the shared MDS project as well as a concrete WSDL within the composite project in order to access the affected web services. We stored the concrete WSDLs within a wsdl folder in the project.
In our project environment we used the classical three tier development using a development, integration and production system. One crucial point to mention here is that the endpoint address (soap:address) element has to be removed from the WSDL’s service definition. This amendment is required in order to prevent WebLogic from invoking the wrong endpoint address. WebLogic uses a simple endpoint resolution strategy, first trying to invoke the endpoint defined in the reference definition (endpointURI property and binding.ws location attribute) and afterwards trying to invoke the endpoint defined within the concrete WSDL. By removing the endpoint definition within the concrete WSDL one does not have to amend it using configuration plans on deployment:
<wsdl:service name="BarService"> <wsdl:port name="FooBarEndpoint" binding="tns:FooBarEndpoint"/> </wsdl:service>
Having these preconditions prepared, the reference definition has to be amended:
<reference name="FooBarService" ui:wsdlLocation="oramds:/apps/com/foo/v1/bar.wsdl"> <interface.wsdl interface="http://foo.com/BarService#wsdl.interface(BarService)"/> <binding.ws port="http://foo.com/BarService#wsdl.endpoint(BarService/FooBarEndpoint)" soapVersion="1.1" location="wsdl/BarService.wsdl"> <wsp:PolicyReference URI="oracle/wss_http_token_client_policy" orawsp:category="security" orawsp:status="enabled"/> <property name="csf-key" type="xs:string" many="false">FooBarServiceCredentials</property> <property name="endpointURI" type="xs:string" >http://foo.com:7001/soa-infra/services/foo/bar/FooBarEndpoint</property> </binding.ws> </reference>
As one can see the reference element ui:wsdlLocation property references the abstract WSDL stored within the MDS repository. In contrast to the first listing, the binding.ws element location property references the concrete WSDL copy stored within the project’s wsdl folder. Using this approach the abstract WSDL will be used during server/composite start up and the concrete WSDL copy during web service invocation. Finally, the endpointURI property is introduced into the example in order to set the concrete endpoint URL during runtime. Of course the concrete WSDL copy within the project has to be updated if the web service definitions change.