This is one of the best posts I’ve seen in a long time about Oracle Fusion Middleware (SOA Suite) and the Oracle 12c database. It shows how to use Chef and Puppet and Docker to build a container running Oracle Fusion Middleware 12 with Oracle 12c. Excellent and truly useful!
As I found out the hard way several years ago the documentation for Oracle’s FTP adapter in SOA Suite 10.1.3 does not match the code. For public key authentication with ssh-dsa the preferredPKIAlgorithm property should be set to ssh-dsa according to the documentation, but the code expects ssh-dss. It turns out that this bug remains in 18.104.22.168. The documentation still insists on ssh-dsa and the code steadfastly uses ssh-dss. Some things never change.
We recently ran into a tricky problem with SOA Suite 11g: unused namespaces in XML files. Consider a simple input file like this one:
<?xml version="1.0" encoding="ISO-8859-1" ?> <a:A xmlns="http://www.example.org/A" xmlns:a="http://www.example.org/A" xmlns:b="http://www.example.org/B"> <b:B xmlns="http://www.example.org/B"> <Name>Name 1</Name> </b:B> </a:A>
Now, we want to transform it into an output file that consists of the element B. The transformation is simple:
<?xml version="1.0" encoding="ISO-8859-1" ?> <xsl:stylesheet version="1.0" xmlns:a="http://www.example.org/A" xmlns:b="http://www.example.org/B" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="a b"> <xsl:template match="b:B"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet>
Unfortunately the result is not so good:
<?xml version = '1.0' encoding = 'UTF-8'?> <b:B xmlns="http://www.example.org/B" xmlns:b="http://www.example.org/B" xmlns:a="http://www.example.org/A"> <Name>Name1</Name> </b:B>
The resulting file refers to namespace A. This is allowed by the XSLT specification, but some XML engines fail to read the resulting file as they choke on the unknown namespace. What to do?
Fortunately SOA Suite 11g supports XSLT 2, at least partly. Change version to 2.0 and add copy-namespaces to the copy-of statement:
<?xml version="1.0" encoding="ISO-8859-1" ?> <xsl:stylesheet version="2.0" xmlns:a="http://www.example.org/A" xmlns:b="http://www.example.org/B" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="a b"> <xsl:template match="b:B"> <xsl:copy-of select="." copy-namespaces="no"/> </xsl:template> </xsl:stylesheet>
This produces the desired result. XSLT 2 has many other useful features, so it is well worth investigating even though it is not fully supported in SOA Suite yet.
Outbound FTP adapters in Oracle SOA Suite normally use the default character encoding. Usually that means that all XML files are written in UTF-8. What do you do if you need to use something else, for example ISO-8859-1?
The logical solution would be to set an adapter property. In 22.214.171.124 there are three likely candidates: CharacterSet, Encoding and jca.message.encoding. Unfortunately none of them works. CharacterSet and Encoding only apply to attachments and are not even used by the adapter. The documentation states that they are meant for third-party applications that need to process the attachment. The jca.message.encoding is used, but only when the adapter reads files, not when it writes them.
What to do? The solution has been with us for a long time, the adapters in 10g worked in the same way. For native files the encoding can be specified in the schema with the nxsd:encoding attribute. It turns out that this works for normal XML files that have no need for native conversions too.
Simply add the following to the main XSD:
<xsd:schema xmlns:nxsd="http://xmlns.oracle.com/pcbpel/nxsd" nxsd:version="XSD" nxsd:encoding="ISO-8859-1" ...>
Problem solved, the adapter will use ISO-8859-1. A bit dirty (in particular when the schema is owned by someone else), but it works.
I have just completed a portable asynchronous JAX-WS web service that works with BPEL and WS-Addressing in Oracle Fusion Middleware 11g. I thought that it would be easy, but in fact it took several days to get it right; hence this blog entry.
First I got the web service up and running and working when invoked from SoapUI. That was not too bad. The main difficulty was how to get at the WS-Addressing headers in a portable way. The callback is invoked by another thread, possibly days after the original call and possibly from another physical machine, so I had to find and store the reply address and the message id. I used a SOAPHandler, as described in Asynchronous web services with WS-Addressing.
Unfortunately BPEL did not want to play. Luckily I found an excellent guide: Create an Asynchronous JAX-WS Web Service and call it from Oracle BPEL 11g. It noted that BPEL expects the WSDL of an asynchronous web service to be structured in a specific way:
- The asynchronous request operation and the callback operation must be on different ports in the same service.
- A parterLinkType section is required to associate the request and callback roles.
- The asynchronous operation must not have a return type (or it will be interpreted as a synchronous service).
- The callback operation should contain a single input that represents the value returned by the callback.
- The asynchronous method operation must specify a value for the soapAction attribute.
After that there were no problems. Along the way I found the following post, which was also quite interesting: Dynamic WSDL location with JAX-WS.
The unit test framework for SCA components that comes with Oracle Fusion Middleware 11g has many serious limitations. It deals poorly with failures, reducing the types of tests that can be created. Today I ran into another really frustrating limitation, but luckily I managed to find an acceptable workaround. Share and enjoy.
The composite under test is dead simple. An inbound DB adapter triggers a Mediator. It calls another Mediator which in turn invokes an outbound DB adapter. Each input record creates a similar output record.
I created a unit test with a fixed input and an assert for the output step. It worked, but the DB adapter inserted the record. Not what I wanted, but easy to fix – just add an emulation for the adapter, right? No.
It is not possible to add emulations for DB adapters, the add button in jDeveloper is disabled. Most likely this applies for the other adapter types as well. When a test runs all the adapters will run, updating other systems. Not at all a good idea for a continuous integration setup where the tests run all the time.
As usual with SOA Suite the solution involves handcrafting generated code. Edit the WSDL file for the output adapter. Find the wsdl:operation element and copy the wsdl:input element to a wsdl:output element. Edit the unit test. It is now possible to define an emulation, as jDeveloper thinks that the adapter is a synchronous web service. When the test has been saved, restore the original WSDL file again.
The code is as it was originally generated, but the tests work as they should without side-effects.
EJB3 web services are great. Simply slap on a @WebService annotation, deploy and it works. A few additional annotations can improve the interface. However, with WebLogic 11g the service endpoint becomes http://server:port/ClassName/ServiceName, where ClassName is the name of the session bean and ServiceName comes from the annotation. This is a bit ugly, the class name of the session bean is an implementation detail and should not be exposed.
Fortunately there is a solution and it keeps the code portable. First, define a generic webservices.xml file with the minimum required information for the web service:
<?xml version="1.0" encoding="UTF-8"?> <webservices xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2"> <webservice-description> <webservice-description-name>SomeService</webservice-description-name> <port-component> <port-component-name>SomeServicePort</port-component-name> <wsdl-port xmlns:ws="http://someserver.com/SomeService"> ws:SomeServicePort</wsdl-port> <service-endpoint-interface> com.someserver.ws.SomeServiceRemote </service-endpoint-interface> <service-impl-bean> <ejb-link>SomeService</ejb-link> </service-impl-bean> </port-component> </webservice-description> </webservices>
Then add a weblogic-webservices.xml file:
<?xml version = '1.0' encoding = 'UTF-8'?> <weblogic-webservices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-webservices http://www.bea.com/ns/weblogic/weblogic-webservices/1.0/weblogic-webservices.xsd" xmlns="http://www.bea.com/ns/weblogic/weblogic-webservices"> <webservice-description> <webservice-description-name> SomeService </webservice-description-name> <webservice-type>JAXWS</webservice-type> <port-component> <port-component-name>SomeServicePort</port-component-name> <service-endpoint-address> <webservice-contextpath>/SomeService</webservice-contextpath> <webservice-serviceuri>/SomeOperation</webservice-serviceuri> </service-endpoint-address> <wsdl> <exposed>true</exposed> </wsdl> </port-component> </webservice-description> </weblogic-webservices>
This will bind the web service to the address http://server:port/SomeService/SomeOperation.