SOA Best Practices: The BPEL Cookbook

Using WSIF for Integration
by Matjaz B. Juric

Learn how BPEL processes can access Java classes and EJBs using WSIF.

 Review complete BPEL Cookbook index

 

Downloads for this article:
 Sample Code
 Oracle BPEL Process Manager and Designer
 Oracle JDeveloper 10.1.3 or later

 

Published October 2005

In real-world scenarios, a BPEL business process will often have to connect to an existing application or system. Of particular interest here is connectivity to J2EE artifacts, such as Java classes, Enterprise Java Beans (EJBs), Java Message Service (JMS), ERP systems accessible through Java Connector Architecture (JCA), JDBC databases, or other Java resources.

 

It is possible to convert these resources to a Web service, but that approach has several disadvantages:
  • The performance overhead of invoking Web service operations is several orders of magnitude larger than that of invoking native Java classes, and an order of magnitude larger than that of invoking EJBs or other native Java resources. (See sidebar.)
  • Web services invocations lack the important capability to propagate contexts during transactions. In contrast, when using Java resources directly transaction context can be propagated automatically, if the Java resource provides such support (as EJB and JCA do, for example).
Hence, the better approach is to access these external resources natively. Native connectivity to Java resources is not a standard feature of BPEL, but Oracle BPEL Process Manager offers a solution for this purpose— Web Services Invocation Framework (WSIF)—that does not require modifications or extensions to BPEL code. This capability greatly extends the reach of BPEL and makes it suitable for enterprise application integration (EAI).

 

In this installment of The BPEL Cookbook, you will learn how BPEL processes can access resources other than Web services using WSIF.

 

Understanding WSIF
Performance and Transactional Differences Between SOAP and WSIF Bindings

Invoking Java resources is usually faster than invoking Web services. Particularly when using plain Java classes, the performance of method invocations is several orders of magnitude better. Java classes are loaded in the application server process and BPEL processes can access their methods directly.

 

When using EJBs you in general have the choice of using local or remote interfaces. Local interfaces are almost as fast as plain Java classes. The difference arises from the fact that there is a certain overhead of the EJB container. If on the other hand you use remote EJB interfaces, then the performance penalty is larger (but according to my measurements still lower than with Web services, as I will explain shortly).

 

EJB remote interfaces are accessed through RMI-IIOP, which requires a stub on the client side and uses the skeleton on the server side. The remote method invocation has to pass several layers before it reaches the EJB, which takes time. Therefore when using remote interfaces you should use coarse-grained methods and become familiar with other J2EE patterns that influence performance. And keep in mind that some application servers optimize the communication with EJBs if they are deployed within the same application server.

 

With Web services the situation from the performance perspective is even more complicated. In general the communication with Web services is comparable to that with remote interfaces of EJBs. In contrast to EJBs, Web services use SOAP, which is less efficient than binary IIOP. Thus, more processing overhead related to constructing and parsing of SOAP messages and XML serialization is required on the caller and receiver sides. My test have revealed that invoking a Web service is ˜5 to ˜9 times slower than invoking a session bean.

 

Using WSIF to invoke Java resources also provides advantages with transactions. Java resources, such as EJBs and JCA, support transactions through JTA, which makes use of JTS. JTS is based on CORBA Object Transaction Service, which provides support for distributed transactions based on the X/Open DTP standard. Java resources, which support transactions through JTA (EJBs, JCA, etc.), can participate in distributed transactions using the 2PC (Two-Phase Commit) protocol.

 

WSIF supports automatic propagation of transactional context between involved Java resources using the XA interface (automatically exposed by JTS). This means that if you would use several transaction-aware resources from your BPEL process through WSIF (two EJBs, for example), the transaction context would be automatically propagated between resources. Should an exception occur the whole transaction would roll back automatically without the need to define a compensation handler in the BPEL process.

 

Without WSIF-enabled Java resources—or if using Web services only, or first converting Java resources to Web services—you could not take advantage of this feature. Rather, you would have to manually define compensation handlers for each Web service. This is very important for mission-critical processes and simplifies their design and development.

 

Consider a business process for buying books. This asynchronous process has three Web services: a Book Rating Web service, which returns the rating of a specific book ranging from 0 to 5 (best), and Web services for two identical Book Store services, which return the book price. The process selects the lower price and makes the book purchase. In this example fault handlers are defined and the process is divided into scopes (Check 1_BuyBook\BuyBook.bpel).

 

Assume that to obtain a book rating you would prefer to use a Java class, EJB (session bean), service from an enterprise information system that can be accessed through JCA, or a similar Java resource. To incorporate such resources (and possibly any other resources for which a binding exist) into BPEL processes using Oracle BPEL Process Manager, you need only modify the service binding (WSDL), not the BPEL process itself. Thus to replace the Book Rating Web service with a Java class, you only have to modify the WSDL of the Web service (more on that later).

 

WSIF, an Apache technology originally developed by IBM alphaWorks as a part of its Web Services Toolkit, is the underlying technology that makes this approach possible. It extends the Web services model by allowing you to describe services in WSDL, even if it's not a Web service that communicates through SOAP. WSIF also allows you to map such a service to the actual implementation and protocol.

 

In other words, you can bind the abstract description of any partner Web service used in the BPEL process to a corresponding resource, which can communicate using one of the supported WSIF bindings. The WSIF used by Oracle BPEL Process Manager 10.1.2 supports Java classes, EJB, JCA, HTTP GET and POST, and sockets; you can also define custom WSIF bindings and use practically any resource from BPEL.

 

This approach makes BPEL very useful for EAI as well as B2B. Enterprise information systems usually consist of many different software pieces, such as legacy applications accessible though JCA, EJBs, Web services developed on different platforms, and so on. To integrate all these pieces you have to deal with different protocols. For example, if software migrates to a different server or has been upgraded to use a new technology, you have to upgrade the integration code—unless you use WSIF.

 

WSIF offers other important benefits:
  • Invoking services through WSIF maintains the performance of native protocols. Thus, when invoking Java resources, native Java classes, EJBs, or any other resources, you do not have to pay the performance penalty of Web services.
  • WSIF enables automatic propagation of transactional contexts between invoked transaction-aware Java resources using Java Transaction API (JTA). That way Java resources can participate in distributed transactions.
To learn how WSIF works, here you'll modify our BPEL process for buying books and invoke a Java class and then an EJB. Remember that with WSIF you will only have to modify the WSDL of the service, not the BPEL code. Through the modifications in WSDL you will bind the call to the Java resource instead of a Web service.

 

First, we'll focus on using a Java class instead of the Book Rating Web service. To replace the Web service you need to have a Java class with the exact same interface as the Web service; this will require development of a Java class based on the WSDL contract. The other possibility would be to adapt the WSDL to an existing Java class (or other resource, let’s say EJB). The first approach is better, because it is a so-called contract-first approach. This way the interface of the service is adapted to the needs of the BPEL process and not vice versa.

 

Java-to-XML Bindings

 

To invoke a Java resource from BPEL you will need to use data from BPEL variables, which are sent as input parameters to Java resources, and to send data from Java back to BPEL. BPEL variables are XML and Java variables are not; therefore, you need a mapping between XML and Java.

 

To handle XML data from Java you have several options:
  • Handle XML manually through the DOM (Document Object Model) API. This way the input and output parameters of the corresponding Java methods are of type Element from the W3C DOM API for Java. Use DOM methods to manipulate XML directly.
  • Use automated Java to XML bindings. Java-to-XML binding enables automatic conversion of XML Schema types to Java types. To achieve this, interfaces and a set of Java classes are generated through which you manipulate the XML. This way XML is hidden and you can use it though interfaces (such as JavaBeans). Here you have two options:
    • Oracle BPEL Process Manager supports default Java-to-XML bindings through the use of XML façades.
    • Use of custom Java serializers. Oracle already provides custom serializers, which support JAXB (Java API for XML Bindings), XML Beans, and Axis Beans. You can also write your own serializers (more about that later).
. Let's have a look at the XML façades first.

 

XML Façades. XML façades are Oracle BPEL Process Manager's original Java-to-XML binding for WSIF and are an integral part of the product. XML façades are a set of Java interfaces and classes through which you can access and modify XML data stored in BPEL variables in a relatively easy way using get/set methods. In this manner you are not required to manipulate XML directly —furthermore, the XML is hidden behind the façade and you can manipulate the data through regular Java interfaces, a concept known as XML serialization. The idea behind XML façades is to provide support for basic data types through mapping to built-in types and to generate Java classes from XML Schemas for complex types.

 

The automatic mapping for the basic data types between XML Schema and Java types is shown below:

 

XML Schema Type Java Types
·xs:string · java.lang.String
· char
· java.lang.Character
xs:int, xs:integer
· int
· java.lang.Integer
· java.math.BigInteger
xs:long · long
· java.lang.Long
xs:short
· short
· java.lang.Short
xs:float
· float
· java.lang.Float
xs:double
· double
· java.lang.Double
· java.math.BigDecimal
xs:byte
· byte
· java.lang.Byte
xs:Boolean
· boolean
· java.lang.Boolean
dateTime java.util.Calendar
date java.util.Date

 

 

As you can see, most of the simple types can be mapped to either primitive or object types. This is useful as you can adapt the mapping to the actual types used in you Java code. In addition to simple types, you also need a way to map complex types, whether those defined in the <types> section of the WSDL or in the external XML Schemas (XSD) files. For example, in your Book Rating Web service WSDL, you'll notice an operation that takes as input the BookRatingRequestMessage, which is of type BookDscType. The BookDscType complex XML type is used for the BookRatingRequestMessage and for the corresponding BookRatingRequest BPEL variable:

                               
<xs:schema elementFormDefault="qualified"
            targetNamespace="http://oracle.com/service/bookrating/">

   <xs:complexType name="BookDscType">
     <xs:sequence>
       <xs:element name="Title" type="xs:string" />
       <xs:element name="ISSN" type="xs:string" />
       <xs:element name="Publisher" type="xs:string" />
       <xs:element name="Authors" type="xs:string" />
     </xs:sequence>
   </xs:complexType>

</xs:schema>

                            
The XML façade for this complex XML type provides an interface and a class through which you can access the elements (title, ISSN, publisher, authors) using Java getter methods. The XML façade also allows you to modify the element data using setter methods.

 

An XML façade for this variable consists of an interface (IBookDscType) and a class (BookDscType) which provides the following methods:
  • getTitle() and setTitle()
  • getISSN() and setISSN()
  • getPublisher() and setPublisher()
  • getAuthors() and setAuthors()
There is also a factory class ( BookDscTypeFactory) through which you can create the IBookDscType using the createFacade() method. XML façade makes the code simpler and easier to maintain; this is particularly true for larger variables with many member fields.

 

Oracle BPEL Process Manager provides a schema compiler utility called schemac. Using this utility you can generate XML façades. To generate the XML façade for BookRating.wsdl use the following command line:
                               
Z:\WSIF\2_JavaBindingClass>schemac BookRating.wsdl
----------------------------------------------------
Oracle XML Schema Processor Version 10.1.2.0.0
http://otn.oracle.com/bpel
Copyright (c) 2002-2004 - Oracle
(type schemac -help for help)
----------------------------------------------------

schemac> parsing schema file 'BookRating.wsdl' ...
schemac> Loaded schemas from wsdl located at BookRating.wsdl
schemac> generating XML business document ...
schemac> compiling XML business documents ...
Schemac completed successfully.

Z:\WSIF\2_JavaBindingClass>

                            
To use these classes from Java resources you will need to compile them into the following directory where the BPEL server can access them.

 

C:\OraBPELPM_1\integration\orabpel\system\classes

 

The schemac utility has several options. You can use the -d switch to define the directory where the generated façade classes should be stored. To see the façade source code use the -trace option. The schemac utility can also be used to generate XML Schemas out of Java classes. This is useful if you would like to adapt the service interface to an existing Java resource. You have to use the -R switch and provide the Java class name without the extension.

 

Developing the Java Class. To replace the Book Rating Web service with a Java class without modifying BPEL, you need a Java class that has the same interface (contract) as the original Book Rating Web services. This means that the Java class has to provide the operations with the identical functionality and that operations have to accept the same parameters and return the same result type—but the operation name needn't be identical.

 

Looking at the original WSDL you'll see that the Book Rating Web service provides an operation called BookRating, which takes an input and an output message and is thus synchronous:
                               
<portType name="BookRatingPT">
  <operation name="BookRating">
    <input message="tns:BookRatingRequestMessage" />
    <output message="tns:BookRatingResponseMessage" />
  </operation>
</portType>

The signatures of both messages are as follows:
<message name="BookRatingRequestMessage">
  <part name="book" type="tns:BookDscType" />
</message>

<message name="BookRatingResponseMessage">
  <part name="rating" type="xs:int" />
</message>

                            
The input parameter to the operation is of type BookDscType. To map the BookDscType to Java use the corresponding XML façade, which you generated earlier using the schemac tool. The return type of the operation is the BookRatingResponseMessage message, which is of type xs:int. xs:int type maps to java.lang.Integer . (It could also map to int or java.math.BigInteger, but you are using java.lang.Integer here.)

 

You are now ready to write the Java equivalent class for the Book Rating Web service. Call the new Java class BookRatingJava, which will have a single method called getBookRating. The method body will be oversimplified—you will print a notification to the server console and return the rating of 4. (In a real-world example, you could calculate the rating based on data in the database, for example.) The code is shown below. Note how you can access the book title and ISSN using getTitle() and getISSN() methods respectively: package com.oracle.rating;
                               
import com.oracle.service.bookrating.*;

public class BookRatingJava {

  public Integer getBookRating (BookDscType book) {

    System.out.println("Book rating for "+book.getTitle()+" ("+book.getISSN()+"): 4.");

    return new Integer(4);

  }
}

                            
The console output is added here to verify that the process really calls the Java class and not the Web service.

 

Defining WSIF Bindings in WSDL. To "persuade" the BPEL process to use the Java class instead of the Web service you have to define the WSIF bindings to the Java class. You will do this in the Book Rating WSDL, where you will add the binding section.

 

Each WSIF binding consists of two parts. First, you have to define the actual binding, where you specify:
  • Type of binding used (Java class, EJB, JCA, and so on)
  • Mapping of types, where you specify the mapping of XML types to the destination types (for Java resources these are Java types). You have to define the mapping for all complex types; simple types are mapped automatically based on the table presented earlier.
  • Mapping of operations, where you have to specify for each WSDL operation (defined under <portType> tag) the corresponding operation in the destination resource (for example, the name of the method of a Java class)
Second, you have to specify the service you will be using. Here you specify the exact name of the resource. If it is a Java class specify its full name (including the package name).

 

In a real-world scenario, you may have a resource, such as a Java class or an EJB, for which a WSDL will not exist. Then you have to go through the following steps:
  1. Define the Java to XML bindings, where you select how to map input parameters and return value to XML. You can use XML façades and simplify the work using the schemac tool with the –R switch, which will generate XML Schema based on a Java class.
  2. Define the signature for each operation and the corresponding input and output messages. Later in this article, you will also see how to handle faults.
  3. Add the WSIF binding.
  4. Add the <partnerLinkType> declaration in order to use the WSDL from BPEL process.
Particularly in the first two steps you can use a tool or a wizard for automatic conversion of resources to Web services. Such tools are available for most environments. Of course you do not actually convert the resource to Web service, but can make use of the generated WSDL (with additional modifications).

 

WSIF Binding for Java Class. Let's now define the WSIF binding for Book Rating Java class. Start by defining the two namespaces used by WSIF providers in the root element of the WSDL document, the <definitions> tag. The format namespace is used to define the type mappings and the java namespace to define the operation mappings and the full name of the Java class:
                               
<?xml version="1.0" encoding="utf-8" ?>
<definitions xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:tns="http://oracle.com/service/bookrating/"
             targetNamespace="http://oracle.com/service/bookrating/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"
             xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/"
             xmlns:java="http://schemas.xmlsoap.org/wsdl/java/" >
...

                            
Next, add the binding section. This section is usually located after port type declarations and before partner link types. Here you define a Java binding for the BookRatingPT port type:
  1. Define the type mapping from XML to Java. The input parameter XML type BookDscType is mapped to the com.oracle.service.bookrating.BookDscType Java class. Please note that you do not have to provide the mapping for output XML xs:int type, because it maps automatically to java.lang.Integer.
  2. Also define that the WSDL operation BookRating is mapped to the Java method getBookRating(). Please note that the name of the WSDL operation and the method name of the Java class do not need to be equal, but the types of input and return parameters do:
                                       
    ...
    <binding name="JavaBinding" type="tns:BookRatingPT">
    
        <java:binding/>
    
        <format:typeMapping encoding="Java" style="Java">
    
          <format:typeMap typeName="tns:BookDscType"
                  formatType="com.oracle.service.bookrating.BookDscType" />
    
        </format:typeMapping>
    
        <operation name="BookRating">
    
          <java:operation methodName="getBookRating"/>
    
          <input/>
          <output/>
        </operation>
    
      </binding>
    ...
    
                                    
Next, specify the service used. Define that the service is provided by the Java class. The Book Rating service will use the com.oracle.rating.BookRatingJava Java class:
                               
...
  <service name="BookRating">

    <port name="JavaPort" binding="tns:JavaBinding">

      <java:address className="com.oracle.rating.BookRatingJava"/>

    </port>

  </service>

                            
The rest of the Book Rating WSDL (including partner link types) has not changed.

 

Testing the Example. You are almost ready to test the example and verify that the BPEL process will use the Java class instead of the original Web service. Remember, you have modified the WSDL only; you have not made any changes to the BPEL process code.

 

You will use the original BPEL code and the same partner link and invoke the BookRatingJava Java class with the usual <invoke> activity used for invoking the Web service. Recall the BPEL code for the invocation of the Book Rating service:
                               
...
          <!-- Synchronously invoke the Book Rating Web Service -->
          <scope name="BookRatingInvoke">

            <faultHandlers>

              <catchAll>
                <!-- If book rating is not available assign 0 -->
                <assign>
                  <copy>
                    <from expression="number(0)"/>
                    <to variable="BookRatingResponse" part="rating"/>
                  </copy>
                </assign>
              </catchAll>

            </faultHandlers>

            
                                 <invoke partnerLink="BookRating"                   portType="bkr:BookRatingPT"                   operation="BookRating"                   inputVariable="BookRatingRequest"                   outputVariable="BookRatingResponse" />

          </scope>
...
                              
                            
Before you can test the example we have to do a few "book-keeping" activities. First, you have to get sure that the BPEL process will use the modified WSDL. To achieve this, modify the bpel.xml file and specify that the BookRating.wsdl file should be taken from the current directory and not from the Web service itself:
                               
<?xml version="1.0" encoding="UTF-8"?>
<BPELSuitcase>
  <BPELProcess src="BuyBook.bpel" id="BuyBookJavaBinding">
    <partnerLinkBindings>
      <partnerLinkBinding name="Client">
        <property name="wsdlLocation">
           BuyBook.wsdl
        </property>
      </partnerLinkBinding>
      
                                 <partnerLinkBinding name="BookRating">         <property name="wsdlLocation">             BookRating.wsdl         </property>       </partnerLinkBinding>
      <partnerLinkBinding name="BookStore1">
        <property name="wsdlLocation">
            http://localhost:9700/orabpel/default/BookStore1/BookStore1?wsdl</property>
      </partnerLinkBinding>
      <partnerLinkBinding name="BookStore2">
        <property name="wsdlLocation">
            http://localhost:9700/orabpel/default/BookStore2/BookStore2?wsdl</property>
      </partnerLinkBinding>
    </partnerLinkBindings>
  </BPELProcess>
</BPELSuitcase>
                              
                            
Then generate the XML façade using the schemac utility and compile the BookRatingJava class. You have to deploy the XML façade and the Java class to the C:\OraBPELPM_1\integration\bpelpm\orabpel\system\classes directory, where the BPEL server can locate and use them. The easiest way is to modify the build.xml which should invoke the scemac compiler, the javac compiler, and the bpelc compiler:
                               
<?xml version="1.0"?>
<project name="BuyBookJavaBinding" default="all" basedir=".">
    <property name="deploy" value="default"/>
    <property name="rev" value="1.0"/>

     
                                 <target name="CompileJava">         <schemac input="${basedir}/BookRating.wsdl" out="${home}/system/classes"/>         <javac srcdir="${basedir}/src" destdir="${home}/system/classes"/>     </target> 

    <target name="main">
        <bpelc home="${home}" rev="${rev}" deploy="${deploy}"/>
    </target>

    <target name="all" depends="CompileJava, main"/>

</project>
                              
                            
After starting the obant utility you should get the following output:
                               
Z:\WSIF\2_JavaBindingClass>obant

Z:\WSIF\2_JavaBindingClass>SETLOCAL
Buildfile: build.xml

CompileJava:
  [schemac] schemac> parsing schema file 'Z:\WSIF\2_JavaBindingClass/BookRating.
wsdl' ...
  [schemac] schemac> Loaded schemas from wsdl located at Z:\WSIF\2_JavaBindingCl
ass/BookRating.wsdl
  [schemac] schemac> generating XML business document ...
  [schemac] schemac> compiling XML business documents ...
    [javac] Compiling 1 source file to C:\OraBPELPM_1\integration\orabpel\system
\classes

main:
    [bpelc] validating "Z:\WSIF\2_JavaBindingClass\BuyBook.bpel" ...
    [bpelc] BPEL suitcase deployed to: C:\OraBPELPM_1\integration\orabpel\domain
s\default\deploy

all:

BUILD SUCCESSFUL
Total time: 17 seconds

Z:\WSIF\2_JavaBindingClass>ENDLOCAL

Z:\WSIF\2_JavaBindingClass>

                            
Next, use the BPEL Console to start the process. In the visual flow window you can observe the execution of the process. Note that the <invoke> activity has been used in BPEL and that the book rating is 4, in contrast to the original Book Rating Web services, which returned 5:

 

figure 1

 

To be absolutely sure that the BPEL Process Manager has invoked the Java class, the BPEL Process Manager console window will show the following output:
                               
05/10/19 19:35:36 Book rating for Business Process Execution Language (1-904811-
18-3): 4.

                            
Exception Handling

 

When invoking Java resources from BPEL we need a way to propagate Java exceptions to BPEL. With WSIF we can map Java exceptions to WSDL faults and handle them using BPEL fault handlers. For the mapping the exception serializer is responsible. Oracle BPEL Process Manager provides a default exception serializer, or you can write our own custom serializer.

 

To demonstrate how Java exceptions can be propagated to BPEL we will extend our example. First, use the default serializer and then extend the example with a custom serializer. Go through the following steps:
  1. Define a user exception in Java.
  2. Modify the BookRatingJava Java class to throw the exception.
  3. Define the corresponding fault in the WSDL. This includes the definition of XML Schema type for the fault message, the fault message, and addition of the <fault> message to the WSDL <operation> description.
  4. Define the WSIF binding for the exception.
Define User Exception in Java. First, define a user exception for signaling that a book, for which the rating has been acquired, does not exist. You will name the exception BookDoesNotExistException. The code below shows the exception in Java:
                               
package com.oracle.rating;

public class BookDoesNotExistException extends Exception
{
  String detailDesc;
  String bookTitle;

  public BookDoesNotExistException(String message, String detailDesc, String bookTitle)
  {
    super(message);
    this.detailDesc = detailDesc;
    this.bookTitle = bookTitle;
  }

  public String getDetailDesc()
  {
    return detailDesc;
  }

  public String getBookTitle()
  {
    return bookTitle;
  }
}

                            
Throw Java Exception. Next, modify the BookRatingJava Java class. You will throw the exception if the ISSN of the book equals to 999:
                               
package com.oracle.rating;

import com.oracle.service.bookrating.*;

public class BookRatingJavaUserException {

  public Integer getBookRating (BookDscType book) throws BookDoesNotExistException {

    if  
                                 (book.getISSN().equals("999"))        throw(new BookDoesNotExistException("Book does not exist",                                            "Book (ISSN="+book.getISSN()+") does not exist",                                            book.getTitle()));

    System.out.println("Book rating for "+book.getTitle()+" ("+book.getISSN()+"): 4.");

    return new Integer(4);

  }
}
                              
                            
Define Fault in WSDL. In the next step, you will define the corresponding fault in WSDL. Java exception will be propagated to this fault. As you will use the default exception serializer, you have to use a specific complex type which has two elements: faultstring and detail. You will add this complex type to the <types> section of the Book Rating WSDL:
                               
<xs:complexType name="BookDoesNotExistExceptionType">
  <xs:sequence>
    <xs:element name="faultstring" type="xs:string" />
    <xs:element name="detail" type="xs:string" />
  </xs:sequence>
</xs:complexType>

                            
Next, define the corresponding message:
                               
<message name="BookDoesNotExistException">
  <part name="exception" type="tns:BookDoesNotExistExceptionType" />
</message>

                            
Finally, add the fault message to the BookRating operation signature:
                               
<portType name="BookRatingPT">
  <operation name="BookRating">
    <input message="tns:BookRatingRequestMessage" />
    <output message="tns:BookRatingResponseMessage" />
     
                                 <fault name="BookDoesNotExistException" message="tns:BookDoesNotExistException" />
  </operation>
</portType>
                              
                            
The default exception serializer will create the fault element and fill the faultstring with the content returned by Exception.getMessage() and the detail element with the content returned by Exception.toString().

 

Define WSIF Binding for Exception. Now you are ready to add the exception to the WSIF binding. You have to define the type mapping for the BookDoesNotExistExceptionType XML type, which in our case will map to the corresponding Java exception class—to the com.oracle.rating.BookDoesNotExistException. You also have to add the fault message name ( BookDoesNotExistException) to the operation mapping part:
                               
<binding name="JavaBinding" type="tns:BookRatingPT">
  <java:binding/>
  <format:typeMapping encoding="Java" style="Java">
    <format:typeMap typeName="tns:BookDscType"
                    formatType="com.oracle.service.bookrating.BookDscType" />
    
                                 <format:typeMap typeName="tns:BookDoesNotExistExceptionType"                     formatType="com.oracle.rating.BookDoesNotExistException" />
  </format:typeMapping>
  <operation name="BookRating">
    <java:operation methodName="getBookRating"/>
    <input/>
    <output/>
     
                                 <fault name="BookDoesNotExistException"/>
  </operation>
</binding>
                              
                            
For this example to work you have to compile Java classes and deploy them to the C:\OraBPELPM_1\integration\orabpel\system\classes directory, where the BPEL server can access them. The easiest way is to use the obant utility with the example:
                               
Z:\WSIF\3_JavaBindingUserExceptionDefaultSerializer>obant

Z:\WSIF\3_JavaBindingUserExceptionDefaultSerializer>SETLOCAL
Buildfile: build.xml

CompileJava:
  [schemac] schemac> parsing schema file 'Z:\WSIF\3_JavaBindingUserExceptionDefa
ultSerializer/BookRating.wsdl' ...
  [schemac] schemac> Loaded schemas from wsdl located at Z:\WSIF\3_JavaBindingUs
erExceptionDefaultSerializer/BookRating.wsdl
  [schemac] schemac> generating XML business document ...
  [schemac] schemac> compiling XML business documents ...
    [javac] Compiling 2 source files to C:\OraBPELPM_1\integration\orabpel\syste
m\classes

main:
    [bpelc] validating "Z:\WSIF\3_JavaBindingUserExceptionDefaultSerializer\BuyB
ook.bpel" ...
    [bpelc] BPEL suitcase deployed to: C:\OraBPELPM_1\integration\orabpel\domain
s\default\deploy

all:

BUILD SUCCESSFUL
Total time: 18 seconds

Z:\WSIF\3_JavaBindingUserExceptionDefaultSerializer>ENDLOCAL

Z:\WSIF\3_JavaBindingUserExceptionDefaultSerializer>

                            
After starting the example from the BPEL console and entering ISSN of 999, you get the following output:

 

figure 2

 

Custom Exception Serializers. If you are not happy with the structure of the WSDL fault (which consists of the faultstring and detail elements) and would prefer to have more control over the mapping of Java exceptions to WSDL faults, you can use custom exception serializers. A custom exception serializer is a Java class that maps the exception and its attributes to the complex type used for the WSDL fault. To see how custom serializer is developed, go through the following steps:
  1. Define a custom complex type used for the WSDL fault message.
  2. Write a custom exception serializer to propagate the Java exception to WSDL fault.
  3. Register the custom exception serializer.
First, define the XML Schema custom complex type to represent the Java exception that will include all three exception attributes, message, detail description, and book title. You will replace the default complex type with this type in the <types> section of the Book Rating WSDL:
                               
<xs:complexType name="BookDoesNotExistExceptionType">
  <xs:sequence>
    <xs:element name="message" type="xs:string" />
    <xs:element name="detailDesc" type="xs:string" />
    <xs:element name="bookTitle" type="xs:string" />
  </xs:sequence>
</xs:complexType>

                            
The custom exception serializer is a Java class, which defines how the Java exception maps to the WSDL fault complex type. The exception serializer has to map the Java exception attributes to the corresponding XML elements of the fault message, and has to implement the following interface:
                               
public interface IExceptionSerializer {

        public Element serialize(Throwable ex,
                             String messageName,
                             String namespaceURI);
}

                            
For our example, you will name the custom exception serializer BookDoesNotExistExceptionSerializer and extend the existing ExceptionSerializer class. Using DOM API we will map the three attributes of the Java exception (message, detail description, book title) to the above presented XML Schema type ( BookDoesNotExistExceptionType):
                               
package com.oracle.rating;

import org.w3c.dom.Element;

import com.collaxa.xml.XMLHelper;
import com.oracle.bpel.xml.util.ExceptionSerializer;
import com.oracle.bpel.xml.util.IExceptionSerializer;

public class BookDoesNotExistExceptionSerializer extends ExceptionSerializer
                implements IExceptionSerializer {

        public Element serialize(Throwable ex, String messageName, String namespaceURI) {

                if(ex instanceof BookDoesNotExistException)
                {
                        BookDoesNotExistException brEx = (BookDoesNotExistException)ex;

                        Element exceptionElement =
                         XMLHelper.createRootElement(messageName, namespaceURI,"tns");

                        Element messageElement =
                         XMLHelper.createElement("message","tns",namespaceURI);
                        messageElement.setNodeValue(brEx.getMessage());
                        exceptionElement.appendChild(messageElement);

                        Element detailElement =
                         XMLHelper.createElement("detailDesc","tns",namespaceURI);
                        detailElement.setNodeValue(brEx.getDetailDesc());
                        exceptionElement.appendChild(detailElement);

                        Element bookElement =
                          XMLHelper.createElement("bookTitle","tns",namespaceURI);
                        bookElement.setNodeValue(brEx.getBookTitle());
                        exceptionElement.appendChild(bookElement);

                        return exceptionElement;

                }
                return super.serialize(ex, messageName, namespaceURI);
        }

}

                            
The final step is to register the custom exception serializer with the Oracle BPEL Process Manager. This step will instruct the BPEL Process Manager to use your custom serializer instead of the default serializer. To do so, define the exceptionSerializer property in the bpel.xml deployment descriptor:
                               
<partnerLinkBinding name="BookRating">
  <property name="wsdlLocation">
      BookRating.wsdl
  </property>
   
                                 <property name="exceptionSerializer">       com.oracle.rating.BookDoesNotExistExceptionSerializer   </property>          
</partnerLinkBinding>
                              
                            
As with the previous example you have to compile Java classes and deploy them to the C:\OraBPELPM_1\integration\orabpel\system\classes directory. Use the obant utility:
                               
Z:\WSIF\3_JavaBindingUserExceptionCustomSerializer>obant

Z:\WSIF\3_JavaBindingUserExceptionCustomSerializer>SETLOCAL
Buildfile: build.xml

CompileJava:
  [schemac] schemac> parsing schema file 'Z:\WSIF\3_JavaBindingUserExceptionCust
omSerializer/BookRating.wsdl' ...
  [schemac] schemac> Loaded schemas from wsdl located at Z:\WSIF\3_JavaBindingUs
erExceptionCustomSerializer/BookRating.wsdl
  [schemac] schemac> generating XML business document ...
  [schemac] schemac> compiling XML business documents ...
    [javac] Compiling 3 source files to C:\OraBPELPM_1\integration\orabpel\syste
m\classes

main:
    [bpelc] validating "Z:\WSIF\3_JavaBindingUserExceptionCustomSerializer\BuyBo
ok.bpel" ...
    [bpelc] BPEL suitcase deployed to: C:\OraBPELPM_1\integration\orabpel\domain
s\default\deploy

all:

BUILD SUCCESSFUL
Total time: 21 seconds

Z:\WSIF\3_JavaBindingUserExceptionCustomSerializer>ENDLOCAL

Z:\WSIF\3_JavaBindingUserExceptionCustomSerializer>

                            
After starting the example from the BPEL console and entering ISSN of 999, you'll get the following output. Notice the different fault structure:

 

figure 3

 

Custom Java Serializers. A custom Java serializer is a class that implements the IJavaSerializer interface. It has to provide the implementation of two methods: serialize and deserialize.
                               
public interface IJavaSerializer {

        public Element serialize(Object obj, Class type, String name, String namespaceURI,
                             String prefix, Map classMap) throws Exception;
        public Object deserialize(Element el, Class type) throws Exception;
}

                            
Similar to custom exception serializers, you have to deploy the compiled class to the C:\OraBPELPM_1\integration\orabpel\system\classes directory and define the javaSerializer property in the bpel.xml deployment descriptor:
                               
<partnerLinkBinding name="helper">
    <property name="wsdlLocation">HelperService.wsdl</property>
     
                                 <property name="javaSerializer">com.oracle.bpel.xml.util.MyCustomSerializer</property>
</partnerLinkBinding>
                              
                            
Oracle provides three custom serializers out of the box: for Java API for XML Bindings (JAXB), XML Beans, and Axis Beans.

 

JAXB is a part of Java Web Services Developer Pack and provides a conceptually similar approach to XML façades, but differs in several details. To use JAXB serialization with Oracle BPEL Process Manager, take the following steps:
  1. Add the JAXB JAR files, located in the JWSDP installation directory (for example c:\jwsdp-1.5\jaxb\lib) to the environment variable BASE_OB_CLASSPATH in the obsetenv.bat file found in C:\OraBPELPM_1\integration\orabpel\bin and to the application.xml file found in C:\OraBPELPM_1\integration\orabpel\system\appserver\oc4j\j2ee\home\confi.
  2. Copy the JAXBSerializer.class (see sample code download) into C:\OraBPELPM_1\integration\orabpel\system\classes\com\oracle\bpel\xml\util directory.
  3. Copy the Java classes produced by the JAXB compiler (xjc) to the C:\OraBPELPM_1\integration\orabpel\system\classes directory.
You also have to define which serializer your BPEL project will use. You do that in the bpel.xml file, where you have to define the javaSerializer property:
                               
<partnerLinkBinding name="helper">
  <property name="wsdlLocation">HelperService.wsdl</property>
   
                                 <property name="javaSerializer">com.oracle.bpel.xml.util.JAXBSerializer</property>
</partnerLinkBinding>
                              
                            
XML Beans are another approach for Java to XML bindings, originally developed by BEA, which donated the project to the Apache community. In contrast to XML façades and JAXB, XML Beans provide an approach that does not completely hide XML from Java developers. Instead, it provides Java interfaces with getter/setter methods and additional methods (with x appendix) through which you can manipulate XML directly if needed. XML Beans are also aware of XML Infoset—when XML is converted to Java objects the whole XML Infoset is available to the developer.

 

Similar to JAXB, you have to make a few configuration steps in order to use XML Beans:
  1. Add the XML Beans JAR files (xbean.jar from BEA Weblogic) to the environment variable BASE_OB_CLASSPATH in the obsetenv.bat file found in C:\OraBPELPM_1\integration\orabpel\bin and to the application.xml file found in C:\OraBPELPM_1\integration\orabpel\system\appserver\oc4j\j2ee\home\config.
  2. Copy the XMLBeansSerializer.class (see sample code download) into C:\OraBPELPM_1\integration\orabpel\system\classes\com\oracle\bpel\xml\util directory.
  3. Copy the Java classes produced by the XML Beans compiler to the C:\OraBPELPM_1\integration\orabpel\system\classes directory
  4. Set path to the xbean.jar in the build.xml file used with the ANT utility ( obant).
You also have to define that BPEL project should use the XML Bean serializer in the bpel.xml file:
                               
<partnerLinkBinding name="xmlBeansService">
  <property name="wsdlLocation">XMLBeansService.wsdl</property>
   
                                 <property name="javaSerializer">         com.oracle.bpel.xml.util.XMLBeanJavaSerializer   </property>
</partnerLinkBinding>
                              
                            
The third well-known approach for Java to XML bindings is Axis Beans, and you can use them with Oracle BPEL Process Manager, too.

 

Similar to the previous two examples you have to make a few configuration steps in order to use Axis Beans:
  1. Add the Axis Beans JAR files (axis.jar from Axis version 1.2) to the environment variable BASE_OB_CLASSPATH in the obsetenv.bat file found in C:\OraBPELPM_1\integration\orabpel\bin and to the application.xml file found in C:\OraBPELPM_1\integration\orabpel\system\appserver\oc4j\j2ee\home\config.
  2. Copy the serializer classes from AxisSerializer.zip (see sample code download) into C:\OraBPELPM_1\integration\orabpel\system\classes\ directory.
  3. Copy the Java classes produced by Axis Beans to the C:\OraBPELPM_1\integration\orabpel\system\classes directory.
You also have to define that BPEL project should use the Axis Bean serializer in the bpel.xml file:
                               
<partnerLinkBinding name="AxisBeansService">
  <property name="wsdlLocation">AxisBeansService.wsdl</property>
   
                                 <property name="javaSerializer">         com.oracle.bpel.xml.util.AxisJavaSerializer   </property>
</partnerLinkBinding>
                              
                            
WSIF Binding for EJBs

 

Now you know how to use a Java class instead of a Web service through WSIF bindings. In a similar manner, you can use EJB, particularly the stateless session beans. To demonstrate the WSIF EJB binding we will extend our example. You will include an additional activity in our BPEL process; after invoking the Book Rating service you will invoke the Publisher Rating service. Through WSIF binding you will use a session bean instead of a Web service. Assume that the session bean already exists. To achieve this goal you will go through several steps:
  • Define the WSDL for the session bean.
  • Add the partner link type to the WSDL.
  • Supplement the BPEL process to invoke the Publisher Rating service.
  • Add the WSIF binding to EJB.
WSDL for Session Bean. The session bean that we will use has the following remote component interface:
                               
package com.oracle.ratingSB;

import java.rmi.RemoteException;
import javax.ejb.EJBObject;

public interface PubRating extends EJBObject
{
    public int getAvgPubRating (String name) throws RemoteException;

}

                            
You can see that it provides a method called getAvgPubRating, which takes a string as input and returns an integer. You will not show the home interface, the implementation class, and the deployment descriptors here (see sample code).

 

Now define the corresponding WSDL document, which is very simple and defines two messages ( PubRatingRequestMessage and PubRatingResponseMessage). They are used in the operation PubRating as input and output. The operation is declared within the PubRatingPT port type:
                               
<?xml version="1.0"?>
<definitions xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:tns="http://oracle.com/service/pubrating/"
             targetNamespace="http://oracle.com/service/pubrating/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"
             xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/"
             xmlns:ejb="http://schemas.xmlsoap.org/wsdl/ejb/" >

  <message name="PubRatingRequestMessage">
    <part name="name" type="xs:string" />
  </message>

  <message name="PubRatingResponseMessage">
    <part name="rating" type="xs:int" />
  </message>

  <portType name="PubRatingPT">
    <operation name="PubRating">
      <input name="PubRatingRequest" message="tns:PubRatingRequestMessage" />
      <output name="PubRatingResponse" message="tns:PubRatingResponseMessage" />
    </operation>
  </portType>
</definitions>

                            
Add Partner Link Type. To use the WSDL you have to add the partner link type. The operation is synchronous; therefore you need only one role:
                               
<plnk:partnerLinkType name="PubRatingLT">
  <plnk:role name="PubRatingService">
    <plnk:portType name="tns:PubRatingPT" />
  </plnk:role>
</plnk:partnerLinkType>

                            
Supplement BPEL Process. Now you are ready to supplement the BPEL process to invoke the Publisher Rating service. First, define a new partner link:
                               
<partnerLink name="PubRating"
             partnerLinkType="pbr:PubRatingLT"
             partnerRole="PubRatingService"/>

                            
Then add the interaction with the Publisher Rating service as a new scope just after the Book Rating scope. Please notice that here you only add new functionality to BPEL:
                               
<scope name="RetrievePublisherRating">

  <variables>
      <variable name="PubRatingRequest" messageType="pbr:PubRatingRequestMessage"/>
      <variable name="PubRatingResponse" messageType="pbr:PubRatingResponseMessage"/>
  </variables>

  <faultHandlers>

      <catchAll>

        <sequence>
          <assign>
            <copy>
              <from expression="string('Unable to retrieve publisher rating')" />
              <to variable="Fault" part="error" />
            </copy>
          </assign>

          <invoke partnerLink="Client"
                  portType="buy:ClientCallbackPT"
                  operation="ClientCallbackFault"
                  inputVariable="Fault" />
        </sequence>

      </catchAll>

  </faultHandlers>

  <sequence>

    <assign>
      <copy>
        <from variable="BookPurchase" part="book" query="/book/bkr:Publisher"/>
        <to variable="PubRatingRequest" part="name"/>
      </copy>
    </assign>

    <invoke partnerLink="PubRating"
            portType="pbr:PubRatingPT"
            operation="PubRating"
            inputVariable="PubRatingRequest"
            outputVariable="PubRatingResponse" />

  </sequence>

</scope>

                            
Add WSIF Binding for EJB. WSIF EJB binding is similar to Java class binding, the major difference being that you have to specify the details regarding the mapping of WSDL operations to EJB methods.

 

Shown below is the WSIF EJB binding excerpt from the Publisher Rating service WSDL file. You have first defined the type mapping and then specified which method should be used for the PubRating operation ( getAvgPubRating()). Please notice that you have specified the message part names for parameters ( name) and for return ( rating). You have also specified the input and output message names ( PubRatingRequest and PubRatingResponse respectively):
                               
<binding name="EJBBinding" type="tns:PubRatingPT">
  <ejb:binding/>
  <format:typeMapping encoding="Java" style="Java">
    <format:typeMap typeName="xs:string" formatType="java.lang.String" />
    <format:typeMap typeName="xs:int" formatType="int" />
  </format:typeMapping>
  <operation name="PubRating">
    <ejb:operation
       methodName="getAvgPubRating"
       parameterOrder="name"
       interface="remote"
       returnPart="rating" />
    <input name="PubRatingRequest"/>
    <output name="PubRatingResponse"/>
  </operation>
</binding>

                            
In the services binding you have to specify additional details of the EJB such as JNDI name, JNDI provider URL, and initial context factory. The JNDI provider URL is specific for each deployment. In this case it would be ormi://localhost/SessionBean. You can use the obant utility to replace the [jndiProviderURL] with the actual address at the time of deployment (please look in the build.xml file for details):
                               
<service name="PubRatingPT">
  <port name="EJBPort" binding="tns:EJBBinding">
    <ejb:address className="com.oracle.ratingSB.PubRatingHome"
                 jndiName="ejb/session/PubRating"
                 initialContextFactory="com.evermind.server.rmi.RMIInitialContextFactory"
                 jndiProviderURL="[jndiProviderURL]"/>
  </port>
</service>

                            
Now you are almost ready to deploy the example and test it. Don't forget to add the wsdlLocation property to the bpel.xml deployment descriptor:
                               
<partnerLinkBinding name="PubRating">
  <property name="wsdlLocation">PubRatingBinded.wsdl</property>
</partnerLinkBinding>

                            
Please notice that you could use the deployment descriptor to add additional properties required by EJB, such as java.naming.security.principal and java.naming.security.credentials if your EJB would require authentication and authorization:
                               
<partnerLinkBinding name="PubRating">
  <property name="wsdlLocation">PubRatingBinded.wsdl</property>
   
                                 <property name="java.naming.security.principal">admin</property>   <property name="java.naming.security.credentials">welcome</property>    
</partnerLinkBinding>
                              
                            
To test the example you first have to deploy the session bean and then the BPEL process. Again, use obant, which automates the procedure:
                               
Z:\WSIF\4_JavaBindingEJB>obant

Z:\WSIF\4_JavaBindingEJB>SETLOCAL
Buildfile: build.xml

deploySessionBean:

build_ear:

deployIas:

deployOc4j:
     [java] Notification ==> Application Deployer for SessionBean STARTS [ 2005-
10-19T19:47:00.891CEST ]
     [java] Notification ==> Undeploy previous deployment
     [java] Notification ==> Copy the archive to C:\OraBPELPM_1\integration\orab
pel\system\appserver\oc4j\j2ee\home\applications\SessionBean.ear
     [java] Notification ==> Unpack SessionBean.ear begins...
     [java] Notification ==> Unpack SessionBean.ear ends...
     [java] Notification ==> Initialize SessionBean.ear begins...
     [java] Notification ==> Initialize SessionBean.ear ends...
     [java] Notification ==> Application Deployer for SessionBean COMPLETES [ 20
05-10-19T19:47:19.470CEST ]


bindingWsdl:
     [copy] Copying 1 file to Z:\WSIF\4_JavaBindingEJB

setJndiUrlOrclej2ee:

setJndiUrlIas:

setJndiUrlOc4j:
     [echo] Replacing token [jndiProviderURL] by ormi://virtualxp/SessionBean in
 Z:\WSIF\4_JavaBindingEJB/PubRatingBinded.wsdl

main:
    [bpelc] validating "Z:\WSIF\4_JavaBindingEJB\BuyBook.bpel" ...
    [bpelc] BPEL suitcase deployed to: C:\OraBPELPM_1\integration\orabpel\domain
s\default\deploy

all:

BUILD SUCCESSFUL
Total time: 28 seconds

Z:\WSIF\4_JavaBindingEJB>ENDLOCAL

Z:\WSIF\4_JavaBindingEJB>

                            
After starting the BPEL process from the console, you should see that the Publisher Rating service has been invoked:

 

figure 4

 

To be absolutely sure that the EJB has been invoked, have a look at the BPEL server console windows; you should see the following output:
                               
05/10/19 19:50:51 Tutalii: C:\OraBPELPM_1\integration\orabpel\lib\orabpel.jar ar
chive
05/10/19 19:50:54 Avg. publisher rating for Packt Publishing: 5.

                            
Generating WSIF Bindings from JDeveloper

 

Writing WSIF bindings by hand can be quite complicated; therefore, Oracle JDeveloper 10.1.3 (available in Early Access release at the time of this writing) provides a wizard for automatic generation of WSDL and WSIF for existing Java resources, such as Java classes and EJBs. This greatly reduces the effort to invoke Java resources from BPEL and make BPEL even more attractive for integration.

 

Based on a Java class or EJB you have to start the wizard for the creation of a Java Web service. The screen shoots apply to Java class example:

 

figure 5

 

Select the JAX-RPC Web service type, which is Java EE 1.4 compliant.

 

figure 6

 

Next, select the Java class or the stateless session bean you would like to use. Check the WSIF binding option (to generate WSIF binding).

 

figure 7

 

Next select the SOAP message format, where you can use Document/Wrapped, Document/Literal, RPC/Literal, or RPC/Encoded representations.

 

figure 8

 

Next, specify custom mappings between XML types and their Java equivalent classes and the corresponding serializers.

 

figure 9

 

Specify the namespaces used by the Web services.

 

figure 10

 

Finally, select the methods, which should be exposed through WSDL:

 

figure 11

 

The wizard offers additional steps where you specify the optional class loaders, JAX-RPC handler classes, service state (stateful), and additional classes used by the service. In most cases you will not need to specify these, so you can conclude the wizard by pressing the Finish button and look at the generated WSDL, where you will find the WSIF bindings, similar to those written by hand. Refer to the JDeveloper documentation for more information on the wizard.

 

Conclusion

 

As you've learned through various examples here, WSIF offers EAI-like capabilities as well as the flexibility to configure partner services of BPEL processes in an easy and flexible way. Clearly, WSIF extends the usability of BPEL to existing resources and makes BPEL an even more valuable technology for SOA.

 


Matjaz Juric Matjaz B. Juric holds a Ph.D. in computer and information science and serves as a content developer and consultant for the BPEL and SOA consulting company BPELmentor.com. He is the author of the book Business Process Execution Language for Web Services (Packt Publishing). He is also the coauthor of J2EE Design Patterns Applied, Professional J2EE EAI, Professional EJB, and NET Serialization Handbook, and has contributed to Web Services Journal, Java Developer's Journal, and other publications.

 

Send us your comments