This blog contains best practices for interfacing Java to external systems through Oracle BPEL components. Java will often be used to integrated functionality within the SOA framework since the framework allows wiring of Java code in order to perform various operations during human task assignment, and execution, as an example. And since these Java classes are embedded in the framework, and these classes may need to pull data from databases, Active Directory, REST services, WSDLs, etc., what is the best way to do this? You guess it: Direct Bindings.

Why use direct bindings? First of all, a direct binding creates a simple RMI interface between Java code and a BPEL process. Besides the speed and efficiency one gets from RMI, using direct bindings leverages the capabilities already available within the SOA framework. There’s no need to go outside the SOA framework to get assignment data (in this example) from a database or other data source. Using SOA libraries, BPEL and SOA adapters everything needed is already available.

Note that our use case has to do with implementing a very specialized version of role or parameter-based team assignments. Another assignment strategy is give here for creating parametric roles using business rules. However there are many other use cases that can be applied that don’t have to do with assignments at all. Dynamic Bindings can and should be used whenever you want to interact with BPEL code from within Java.

Design by Interface First

The first step is to create an interface that will be used between the BPEL process and Java code. In this blog we will implement an interface that will be used to return a list of assignments for a given work team. The work team will be determined from the project the team is working on and other project properties such as the work area and activity type. The work team will contain a list of BPM application roles or a particular individual in a role. 

Input Requirements

  • projectId – string
  • workArea – string  
  • activityType – string

Output Requirements

The output will be a list of assignments. Since the task assignment may contain direct assignments or role-based assignments, this will support both.

    List of Assignments

  • assignment – string
  • type – string

Example Interface Schema

 

<?xml version=”1.0″ encoding=”UTF-8″?>

<schema xmlns_tns=”http://xmlns.oracle.com/default/DynamicTaskAssignment/GetProjectTaskAss…

        targetNamespace=”http://xmlns.oracle.com/default/ynamicTaskAssignment/GetProjectTaskAssi…

        http://www.w3.org/2001/XMLSchema”>http://www.w3.org/2001/XMLSchema“>

 <element name=”process”>

    <complexType>

       <sequence>

          <element name=”projectId” type=”string”/>

          <element name=”processActivityKey” type=”string”/>

          <element name=”workAread” type=”string”/>

     </sequence>

    </complexType>

 </element>

 <element name=”processResponse”>

     <complexType>

         <sequence>

              <element name=”dynamicRoleNamesList” type=”tns:DynamicRoleNamesListType”/>

         </sequence>

      </complexType>

 </element>

 <complexType name=”DynamicRoleNamesListType”>

       <sequence>

            <element name=”dynamicRoleName” type=”tns:DynamicRoleNameType” minOccurs=”0″ maxOccurs=”unbounded”/>

        </sequence>

 </complexType>

 <complexType name=”DynamicRoleNameType”>

     <sequence>

           <element name=”assignment” type=”string”/>

            <element name=”type” type=”tns:AssignmentTypes”/>

      </sequence>

 </complexType>

 <simpleType name=”AssignmentTypes”>

        <restriction base=”string”>

            <enumeration value=”USER”/>

            <enumeration value=”APPLICATION_ROLE”/>

        </restriction>

    </simpleType>

</schema>

The BPEL Process And Direct Binding

 

Now we create the BPEL process and edit the schema template created when the BPEL process is created. This screen shot shows the BPEL creation wizard. Here we are creating a BPEL process, called GetDynamicAssignment in a composite called DynamicAssignments. This has to be a synchronous process, and we will not be needing it to be exposed as a SOAP service, so the check-box can be cleared.

BPEL Process Creation Wizard

Although we will not be using it as a SOAP service, you may want to create it with a SOAP service for testing purposes. Below, we will create it without the SOAP Service, since the creation of the BPEL process will generate the WSDL and message schemas we need in either scenario. 

Please note: Testing your BPEL process without a SOAP service may be an issue. You may want to wrap this code with another BPEL process and expose it as a web service, or don’t replace the SOAP service with a direct binding until you are finished testing it. When you are ready, you can delete the  SOAP service (or Direct Binding service) and replace it with one or the other as you test it or interact with it via Java. The following images shows how this can be done.

 

Deleting SOAP Service or Direct Binding

Next we create the direct binding (or web service interface) by dragging a new direct binding object over from the component pallet to the Exposed Service region of the composite editor. 

Creating Direct Binding From Component Pallet

The direct binding creation wizard will pop up, and you can enter the name of the direct binding service and reference the BPEL wsdl, GetDynamicAssigment.wsdl, created during the BPEL process creation step above.

Direct Binding Creation Wizard

After you click ok, you will need to link the direct binding to the BPEL process using the partner link already generated during BPEL process creation.

Linking to the BPEL Process

We now have a BPEL process that you can use within Java to leverage any service adapters available, such as for a database or web service. For our use case, the team assignments are stored in a database, so we will edit the template schema created for the BPEL process and use a database adapter to pull data from team assignments tables based on the project ID, work area and process-type inputs. This is basic SOA implementation, so details are not provided here.  

 

BPEL Process Shell

The next thing we will describe is how to call invoke this service and marshal data into the request and back out of the response using JAXB classes and Oracle’s SOA Management API.

Java Code

This section describes the Java code that we will use to execute the BPEL process through the direct binding interface. Since we are using RMI, we will need to pass payload data between the BPEL process and our code using org.w3c.dom.Element classes. In this example, we will marshal and unmarshal data into org.w3c.dom classes using JAXB. You can use JDeveloper to create JAXB class or the following command line.

xjc .xsdGetProjectTaskAssignments.xsd -p org.avio.assignments.domain -d .src

This will create the following Java classes in the org.avio.assignments.domain package:

  • AssigmentTypes.java
  • DynamicRoleNamesListTypes.java
  • DynamicRoleNameTypes.java
  • ObjectFactory.java
  • Package-info.java
  • Process.java
  • ProcessResponse.java

Oracle’s Direct Binding and RMI Java Libraries

Oracle’s documentation for using the Direct Bindings is documented here. https://docs.oracle.com/cd/E36909_01/dev.1111/e10224/invocapi.htm

Implementing this, however, is rather complex. It requires the following:

  • An RMI connection
  • The distinguishing name (DN) to the default composite version
  • An org.w3c.dom Process request
  • The BPEL process end-point
  • An org.w3c.dom Process Response

To simplify the RMI interface (using Soa Management API or more specifically, the Locator class as documented here https://docs.oracle.com/cd/E28280_01/apirefs.1111/e10659/toc.htm) we define this Java method, getCurrentLocator() that will be used in our code sample. It returns an RMI locator to the SOA system.

 

 private Locator getCurrentLocator(String providerUrl, String adminUserName, 

                                           String adminPassword) throws Exception {

        Hashtable jndiProps = new Hashtable();

        jndiProps.put(Context.PROVIDER_URL, providerUrl);

        jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,

                      “weblogic.jndi.WLInitialContextFactory”);

        jndiProps.put(Context.SECURITY_PRINCIPAL, adminUserName);

        jndiProps.put(Context.SECURITY_CREDENTIALS, adminPassword);

       return LocatorFactory.createLocator(jndiProps);

}

The two method addressed below,  getDefaultCompositeByNameabove() and executeCompositeServiceEndpoint(), use the getCurrentLocator method.

    

Finding the Active Composite Version

Since several versions of composite, DynamicAssignments may be deployed, we will need to get the composite DN of the default composite version. The composite DN takes the form of partition/compositename!version, or “default/DynamicAssignments!3.2.0. We have this method, getDefaultCompositeByName, to return the default Composite. 

 

    public Composite getDefaultCompositeByName(String compositeNameStr,

                                               String providerUrl,

                                               String adminUserName,

                                               String adminPassword) throws Exception {

        CompositeFilter cFilter = new CompositeFilter();

        CompositeDN compositeDN = new CompositeDN(compositeNameStr);

        cFilter.setPartition(compositeDN.getDomainName());

        cFilter.setCompositeName(compositeDN.getCompositeName());

        List<Composite> composites =

            locatorFactory.getCurrentLocator(providerUrl, adminUserName,

                                             adminPassword).getComposites(cFilter);

        for (Composite composite : composites) {

            if (composite.isDefaultRevision())

                return composite;

            }

        return null;

    }

Executing the BPEL Process From Java

The execution of the BPEL process requires the default composite, obtained above, the WSDL port and operation, and the payload as a org.w3c.dom.Element. The RMI call requires us to wrap the payload in a Message class, and here again we use Oracle Java libraries, XMLMessageFactory, to create the payload we need. This is all wrapped by the Java method shown below that returns the response as a org.w3c.dom.Element class. 

 public Element executeCompositeServiceEndpoint(Composite composite,

                                                   String port,

                                                   String operation,

                                                   String payloadName,

                                                   Element payloadElem,

                                                   String providerUrl,

                                                   String adminUserName,

                                                   String adminPassword) throws Exception {

       Map<String, Element> partData = new HashMap<String, Element>();

        partData.put(payloadName, payloadElem);        

        Message<Element> request = XMLMessageFactory.getInstance().createMessage();

        Payload<Element> payload = PayloadFactory.createXMLPayload(partData);

        request.setPayload(payload);

        DirectConnection connection =

            locatorFactory.getCurrentLocator(

                    providerUrl, adminUserName,

                    adminPassword).createDirectConnection(composite.getCompositeDN(),port);               

        Message<Element> response = connection.request(operation, request);

        ByteArrayOutputStream sw = new ByteArrayOutputStream();

        Node n = response.getPayload().getData().values().iterator().next();

        return (Element) n;

}

Making the Call

The last step ties this all together in the following Java method, getProjectTaskAssignments. This method takes as an argument the JAXB request class, Process.class, and connect properties. It then converts the request to a dom Element, gets the default composite, executes the BPEL process, and returns the response from the BPEL process in the JAXB ProcessResponse class.

 

private ProcessResponse getProjectTaskAssignments(

          Process request,

          String providerUrl,

          String adminUserName,

          String adminPassword) {

                        

            // Create the Request Using the JAXB class, Process.class

            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

            dbf.setNamespaceAware(true);

            DocumentBuilder db = dbf.newDocumentBuilder();

            Document document = db.newDocument();

            JAXBContext jc = JAXBContext.newInstance(Process.class);              

             // Marshal the Process.class object into a W3C.Document object

             Marshaller marshaller = jc.createMarshaller();

             marshaller.marshal(request, document);

             Element requestRoot= document.getDocumentElement();

   

           // Get the default composite version

            Composite dbComposite =

                    soaAdminService.getDefaultCompositeByName(“default/DynamicAssignment”,

                                                                     providerUrl,

                                                                     adminUserName,

                                                                     adminPassword);

            

            response =

                    soaAdminService.executeCompositeServiceEndpoint(dbComposite,

                                                                           “GetProjectTaskAssignments_client_db”,

                                                                           “process”,

                                                                           “payload”,

                                                                           requestRoot,

                                                                           providerUrl,

                                                                           adminUserName,

                                                                           adminPassword);

            

           jc = JAXBContext.newInstance(ObjectFactory.class); 

           Unmarshaller u = jc.createUnmarshaller();

           ProcessResponse processResponse= (ProcessResponse)u.unmarshal(response);

            return processResponse;

}

Conclusion

Notice that all this code uses components and libraries contained in Oracle SOA Fusion Middleware. If you are consuming these Java classes from within a BPM or BPEL composite, then you won’t need to include any external libraries. If you are using JDev to create other SOA composite, then all the libraries will be included during design time. During deployment and run-time, you’ll just need to include the Java classes and methods described above.