During a recent POC, the customer asked us to integrate with several of their backend EJBs, which hosted legacy code talking to backend systems. The EJB interfaces could not be changed, and had to be called a certain way to be successful. The customer was looking to phase out another set of "integration EJBs", written over the last few years that orchestrated their core backend EJBs. SOA Suite will allow them to drastically reduce their development time, and provide much better visibility into the processes as they run. Given their past experiences (writing their integration EJBs was painful and long winded), one of the key requirements was to support their legacy EJBs without writing code in the SOA environment. At first glance this seemed impossible, because we couldn't change anything on the EJB side. In addition many of the parameters to the interfaces contained either incomplete annotations or methods that didn't follow the JavaBeans spec. This was not previously a problem for them because all their EJBs ran in the same JVM and were making local Java calls
We decided to use a powerful yet obscure feature of SOA Suite to do the mapping. Chapter 49.7 of the SOA Suite Developer's guide mentions this marriage between EclipseLink MOXy and SOA Suite, but it does more than advertised, and works outside of the Spring Framework components. We decided to use this functionality to "fix" some of the things we had mapping issues with in the customer code. Additionally, we used the framework to do other helpful tasks, such as changing namespaces, fixing arrays, and removing unnecessary mappings.
In this article we'll cover the theory behind the use of this functionality, basic setup and usage, and several examples to get you started.
When we use an EJB Reference or a Spring component in SOA Suite we usually want to wire it to a non-Java resource. When we do this JDeveloper uses JAXB to create an XML representation of the parameters and return values of the methods in the Java interface we are using. In this article we will show how to override those mappings. Overriding the default generation of mappings allows us to specify target namespaces, rationalize the structure of the data and remove unneeded properties in the Java classes. Some things we may want to customize include:
SOA Suite allows us to describe in XML how we want a Java interface to be mapped from Java objects into XML. The file that does this is called an “Extended Mapping” (EXM) file. When generating a WSDL and its associated XML Schema from a Java interface SOA Suite looks for an EXM file corresponding to the Java Interface being generated from. Without this file the mapping will be the “default” generation, which simply attempts to take each field and method in the Java code and map it to an XML type in the resulting WSDL. The EXM file is used to describe or clarify the mappings to XML and uses EclipseLink MOXy to provide an XML version of Java annotations. This means that we can apply the equivalent of Java annotations to Java classes referenced from the interface, giving us complete control over how the XML is generated. This is illustrated in the diagram which shows how the WSDL interface mapping depends on the JavaInterface of the EJB reference or Spring component being wired (obviously), but is modified by the EXM file which in turn may embed or reference an XML version of JAXB annotations (using EclipseLink MOXy).
The mapping will automatically take advantage of any class annotations in the Java classes being mapped, but the XML descriptions can override or add to these annotations, allowing us fine grained control over our XML interface. This allows for changes to be made without touching the underlying Java code.
Using the mapper out of the box is fairly simple. Suppose you set up an EJB Reference or Spring component inside your composite. You'd like to call this from a Mediator or BPEL Process which expect to operate on a WSDL. Simply drag a wire from the BPEL process or Mediator to the EJB or Spring component and you should see a WSDL generated for you, which contains the equivalent to the Java components business interface and all required types. This happens for you, as the tool goes through the classes in your target.
But what if you get a "Schema Generation Error" or if the generated WSDL isn't correct. As discussed earlier there may be a number of changes we need or want to make to the mapping. In order to use an "Extended Mapping", or EXM file, we need to do the following:
<?xml version="1.0" encoding="UTF-8" ?>
<java-wsdl-mapping xmlns="http://xmlns.oracle.com/weblogic/weblogic-wsee-databinding">
<xml-schema-mapping>
<toplink-oxm-file file-path="./mappings.xml" java-package="soa.cookbook"/>
</xml-schema-mapping>
</java-wsdl-mapping>
<?xml version="1.0" encoding="UTF-8" ?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
<!-- Set target Namespace via namespace attribute -->
<xml-schema namespace=http://cookbook.soa.mapping/javatypes
element-form-default="QUALIFIED"/>
</xml-bindings>
<?xml version="1.0" encoding="UTF-8" ?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
<!-- Set target Namespace via namespace attribute -->
<xml-schema namespace=http://cookbook.soa.mapping/javatypes
element-form-default="QUALIFIED"/>
<java-types>
<java-type name="soa.cookbook.QuoteRequest">
<java-attributes>
<!-- Can remove mappings by making them transient via xml-transient element -->
<xml-transient java-attribute="product"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
The extended mapping file puts the SOA composite developer in control of his own destiny when it comes to mapping Java into XML. It frees him from the tyranny of Java developer specified annotations embedded in Java source files and allows the SOA developer to customize the mapping for his own needs. In this blog entry we have shown how to set up and use extended mapping in SOA Suite composites. In the next entry we will show some of the power of this mapping.
To use this effectively you need to download the following patch from MetaLink:
There is a sample application uploaded as EXMdemo.zip. Unzip the provided file and open the EXMMappingApplication.jws in JDeveloper. The application consists of two projects:
Key files to examine are listed below:
Sample request message
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body xmlns:ns1="http://cookbook.soa.mapping/types">
<ns1:quoteRequest>
<ns1:products>
<ns1:product>Product Number 1</ns1:product>
<ns1:product>Product Number 2</ns1:product>
<ns1:product>Product Number 3</ns1:product>
</ns1:products>
<ns1:requiredDate>2011-09-30T18:00:00.000-06:00</ns1:requiredDate>
<!-- provider should be “EJB” or “Spring” to select the appropriate target -->
<ns1:provider>EJB</ns1:provider>
</ns1:quoteRequest>
</soap:Body>
</soap:Envelope>
This blog article was co-written with my colleague Andrew Gregory. If this becomes a habit I will have to change the title of my blog!
Blaise Doughan, the Eclipse MOXy lead was extremely patient and helpful as we worked our way through the different mappings. We also had a lot of support from David Twelves, Chen Shih-Chang, Brian Volpi and Gigi Lee. Finally thanks to Simone Geib and Naomi Klamen for helping to co-ordinate the different people involved in researching this article.
This is great feature, I liked it so much. By any chance can we get this working outside SOA Suite, say I have an EJB or a POJO service, can we write configuration or mapping files which will do JAXB binding (which in turn can be used in a webservice)
Hi Laxman,
The EclipseLink MOXy external binding file can also be used outside SOA Suite. Below is an example where it is used to specify the JAXB metadata for a JAX-RS (RESTful) service:
- http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html
-Blaise
Blaise Doughan
Team Lead, EclipseLink JAXB (MOXy)