Mapping the results of a BPEL process
The applications that integrate with BPEL processes are most interested in the results. As we saw in the asynchronous scenario recipes, as a result, we receive SOAP Header and SOAP body within SOAP message. The XML presentation is not very useful for Java applications. The better solution would be to instead have Java applications consume the Java Bean classes. For that purpose, different tools exist that enable efficient XML to Java mapping.
In this recipe, we will examine how to map the results of a BPEL process to Java-based clients.
Getting ready
We will need to extend the client proxy from the Calling an asynchronous BPEL process recipe, so we need to have the asynchronous BPEL process deployed and the client proxy ready.
First, we will update the response of the asynchronous BPEL process to include more XSD schema elements as follows:
<element name = "processResponse"> <complexType> <sequence> <element name = "result" type = "string"/> <element name = "postalcode" type = "int"/> <element name = "temperature" type = "double"/> <element name = "person"> <complexType> <sequence> <element name = "name" type = "string"/> <element name = "lastname" type = "string"/> </sequence> </complexType> </element> </sequence> </complexType> </element>
If we now call an asynchronous BPEL process, we will receive more information. Also, the information is nested in the response.
How to do it…
- We will start this recipe by generating the Java Bean class that corresponds to the body of the SOAP response message. We use the
wsimport
command as follows:C:\>wsimport -keep -p org.packt.async.generated -Xnocompile -d C:\Temp\gen\ http://medion:7001/soa-infra/services/default/HelloWordlAsync/helloworldasyncprocess _client_ep?WSDL parsing WSDL... generating code... C:\>
In the directory
C:\temp\gen
, the skeleton classes of the corresponding WSDL document are now generated. If we check the content of the directory, we see that there are many more files in it. There are also request classes as well as a client proxy to initiate the BPEL process. For our recipe, we only need theProcessResponse.java
file, so we move only this file into our JDeveloper project. In JDeveloper, we create another Java package as shown in the following screenshot: - We then copy the
ProcessResponse.java
file into the project. Now, our project layout consists of the following classes: - We now have to adapt the
ClientProxy
class in order to support the mapping of the result to our Java client. In the AXIS package, there is a utility class,BeanUtil
, which is used for the deserialization of the XML content into Java classes. We start by preparing the variable of the result as follows:ProcessResponse responseBean;
- We then deserialize the XML content of SOAP message body element through the
BeanUtil
utility class as follows:try { responseBean = (ProcessResponse)BeanUtil.deserialize(ProcessResponse.class, msg.getFirstElement(), new DefaultObjectSupplier(), null); } catch (AxisFault e) { onError(e); }
- The XML content of the response from the asynchronous BPEL process is now accessible through the Java Bean as follows:
<processResponse Process"> <result>Hello Jurij</result> <postalcode>1430</postalcode> <temperature>37.5</temperature> <person> <name>Jurij</name> <lastname>Laznik</lastname> </person> </processResponse>
How it works…
The response from the BPEL process presents an XML document wrapped with the SOAP message. The XML format is not very friendly for programming in Java. That is why few implementations arise with the intent to simplify the transformation of XML to Java.
Implementation |
Description |
---|---|
JAXB |
Java Architecture for XML Binding. The essential tools of JAXB are as follows:
|
JAX-WS |
Java API for XML Web Services. The important tools of JAX-WS are as follows:
|
JAX-RPC |
Obsolete: replaced by JAX-WS |
All the implementations mentioned here work with the same basic concept of serialization, deserialization, marshalling, and unmarshalling. In general, serialization and deserialization presents a way of transforming the data structures in a way that we can store them or transfer them between applications or over a network. The synonym for serialization, when we transform Java objects, is marshalling. Consequently, the synonym for the opposite operation, that is deserialization, is called unmarshalling.
The following mapping is used when we convert from XSD schema types to corresponding Java data types:
XML Schema Type |
Java Data Type |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
While the preceding table shows the default mapping between XML data types and Java data types, it is also possible to customize the mapping, usually through the configuration mapping file.
There's more…
Applications written in Java usually do not operate with XML documents. If we want to call a BPEL process, we must also create a request. Until now, we used to build the request with the help of the XML document builder as follows:
OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace("http://xmlns.oracle.com/HelloWorldAsync/HelloWordlAsync/HelloWorldAsyncProcess", ""); OMElement method = fac.createOMElement("process", omNs); OMElement value = fac.createOMElement("input", omNs); method.addChild(value); //value.setText("Jurij"); value.setText("FAULT");
In the request, we have to know all the information, such as namespace, names of the XML tags, and, of course, the data itself.
To simplify the creation of a request, we can utilize the JAXB tools. First, we will take the Process.java
class that we created with the wsimport
tool. We include the class into the JDeveloper project. We need to add namespace info to the annotations in the class file as follows:
@XmlRootElement(name = "process", namespace = "http://xmlns.oracle.com/HelloWorldAsync/HelloWordlAsync/HelloWorldAsyncProcess") @XmlElement(required = true, namespace = "http://xmlns.oracle.com/HelloWorldAsync/HelloWordlAsync/HelloWorldAsyncProcess")
We can now also change the createPayLoad()
method in the ClientProxy.java
class. We create an XML document from the DocumentBuilderFactory
class as follows:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().newDocument();
Then, we create a JAXB context with the following:
JAXBContext jc = JAXBContext.newInstance(Process.class);
Finally, we create marshaller
and serialize the request class as follows:
Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false); marshaller.marshal(req, doc);
The difference between the previous version of createPayLoad()
and the newer version is that the previous version lacks transparency and clarity in the code. We can now fill the request data in the following way:
Process req = new Process(); req.setInput("JURIJ");
And call it as follows:
createPayLoad(req)
See also
- To learn more about the web services request and the response message structure, refer to the Introduction section of Chapter 2, Calling Services from BPEL of this book. More information about the tools we used in this recipe is also available in that chapter.
- Refer to http://docs.oracle.com/javase/7/docs/technotes/tools/share/wsimport.html for more information about the
wsimport
tool. - Also, refer to https://jaxb.java.net/ for more information about the JAXB reference implementation documentation.