Pages

Thursday, June 3, 2010

JEJB Transport and manipulating the Java Response in OSB 11g

With the JEJB Transport you are able to pass POJO's through an OSB Proxy or Business Service( for the outside world it behaves like a remote EJB). JEJB Transport works like the EJB Transport but the request and response objects are not translated to XML so you can't use XQuery etc. To make things not too hard, OSB 11g makes a XML presentation of the request method and its parameters, which you can use in the Proxy Service.
An example of a Remote interface request method
<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <ns:getEmployeesFindByKey xmlns:ns="http://www.openuri.org/">
    <ns:arg0>199</ns:arg0>
  </ns:getEmployeesFindByKey>
</soap:Body>  
Returning a java response message can be easy and difficult. The easy way is to use the same Java Interface in the Proxy and Business Service, then you don't have to do anything ( the BS will pass the result POJO to the Proxy, which returns it to the EJB client). This can be handy for logging the requests or use the OSB server as an EJB proxy.
An other use case can be, that you want to manipulate the response ( Enrichment ) or want to replace the EJB by Web Services. Thne you don't need to change the Applications which uses these remote EJB's.
In this blogpost I will show you how you can achieve this with a Java CallOut in the response pipeline.
Here is an example of a JEJB response.
<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <ns:getEmployeesFindByKeyResponse xmlns:ns="http://www.openuri.org/">
    <ns:return>
      <con:java-content ref="jcid:-15bb3fe4:128fee47f9f:-7f96"
                        xmlns:con="http://www.bea.com/wli/sb/context"/>
    </ns:return>
  </ns:getEmployeesFindByKeyResponse>
</soap:Body>  
Because the response is a java object you can't see the response. The only thing you can do is to pass the java object ( con:java-content element ) to a Java CallOut parameter and in this static method you can do for example a System printout
Before I start you need to know the basics about the EJB and JEJB Transport so please read my previous blogpost and then continue.

This is a overview picture what  I will do in this blogpost.
It starts with the EJB client which looks up the Remote EJB of the Proxy Service and calls the getEmployeesFindByKey and getEmployeesFindAll method.
The Proxy Service has a JEJB Transport with a Remote Interface and has a Routing Table for the two interface methods. In case of the getEmployeesFindAll method the Proxy calls a HTTP Business service and with the getEmployeesFindByKey method it calls a JEJB Business Service.
The HTTP Business Service call a Rest Service on the Oracle XmlDB which returns all the employees in XML.
The JEJB Business Service call a remote EJB on a Weblogic Server this returns an Employee Entity.
The result of these two Business Service will be handled by the Java CallOut. In case of the getEmployeesFindByKey method the Java CallOut changes the email address of the Employee. The result of the HTTP Business Service is a XML with employees so the Java CallOut needs to convert these Employees to a List of Employee Entities

Here is the Message Flow of the Proxy Service. The Routing Table reads the operation variable. 
This is the Java Class with the static method which will be used in the Java CallOut. I will be using the static employeeReference method. This method has 3 parameters, the first operation parameter is important to determine what kind of conversion I need to do. The Direction parameter is used for logging and the body parameter contains the response of the Business Service. This will be converted to Employee Entities. For XML to Java I will be using JAXB.
package nl.whitehorses.hr.ejb.services;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import nl.whitehorses.hr.ejb.entities.Employees;
import nl.whitehorses.osb.model.jaxb.EMPLOYEES;

import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;

public class EmployeeCon {

  public EmployeeCon() {
  }

  public static Object employeeReference(String operation, String direction, Object body)
throws JAXBException {  
      System.out.println(direction+" operation "+operation); 

      if ( operation.equalsIgnoreCase("getEmployeesFindByKey") ) {

         System.out.println("body input class: "+body.getClass().getName());
         Employees employee = (Employees)body;
         employee.setEmail("edwin@edwin.nl");
         return employee;

      } else if ( operation.equalsIgnoreCase("getEmployeesFindAll") ) { 

          System.out.println("body input class: "+body.getClass().getName());
          XmlAnyTypeImpl employeesXml = (XmlAnyTypeImpl)body;
        
          JAXBContext jaxbContext = 
JAXBContext.newInstance ("nl.whitehorses.osb.model.jaxb");
          Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
          EMPLOYEES employees2 =
(EMPLOYEES)unmarshaller.unmarshal(employeesXml.newInputStream());

          List<Employees> employees = new ArrayList<Employees>();
          for ( EMPLOYEES.ROW item : employees2.getROW() ) {
              Employees employee = new Employees();
              employee.setEmployeeId(item.getEMPLOYEEID().longValue());  
              employee.setFirstName(item.getFIRSTNAME());  
              employee.setLastName(item.getLASTNAME());  
              employee.setEmail(item.getEMAIL()); 
              if ( item.getCOMMISSIONPCT() != null ){
                employee.setCommissionPct(item.getCOMMISSIONPCT().doubleValue());
              }
              if ( item.getDEPARTMENTID() != null) {
                employee.setDepartmentId(item.getDEPARTMENTID().longValue());
              }
              employee.setJobId(item.getJOBID());  
              employee.setPhoneNumber(item.getPHONENUMBER()); 
              if ( item.getSALARY() != null ){
                employee.setSalary(item.getSALARY().doubleValue());
              }

              employees.add(employee);
          }
          return employees;
      }    
      return body;
  }
    
}
First Import the Java CallOut jar into your OSB Project. This must contain the Class with the static method and the Employee Entity.  
Lets start with the easy one ( the getEmployeesFindByKey method) by adding a Java CallOut to the response pipeline. Use the $operation variable for the operation parameter and the ctx:java-content element for the body parameter.The return of the method will be copied to the $result variable.
Because of the JEJB Business Service ( returns the right body content ) I only need to replace the original java content with the result variable.

The getEmployeesFindAll method is a bit different because it uses the HTTP Business Service which returns a body which is not compatible with the JEJB Trasnport. So the body parameter of the Java CallOut has a different expression which matches with the response of the HTTP Business Service.
You need to assign a new JEJB Transport body to the $body variable
The expression of the Assign
That's all and now you can lookup the Remote EJB on the OSB Server and call one of the available methods.

7 comments:

  1. Hi, excuse me, but you always help us, and I really appreciate if you could help me to resolve an issue. I´m developing a custom worklist application with jdeveloper and SOA Suite 11g. I make a little example using a java class with main method and works well, but If I try to deploy to integrated web server raises the following error:

    The application uses the following libraries:

    bpm-infra.jar
    bpm-services.jar
    wlfullclient.jar
    wsclient_extended.jar

    If I remove the libraries from project then the deploy works. But when run raises diverse errors about not find some libraries.

    Please help me !!

    ReplyDelete
  2. Hi,

    In jdeveloper you have two deployment options. first on your project ( war deployment). this is the bad one because it does not load the ADF library.

    So you need to deploy from the application menu.( ear ) , this will load the weblogic-application.xml with the adf shared library.

    I think you still need to add bpm-infra.jar, bpm-services.jar to the web-inf/lib.

    hope this helps

    ReplyDelete
  3. I am in a dilemma very similar to your issue, I need to pass as argument a complex object to a java callout, this complex object contains a collection of objects and I want to iterate over this collection to create a list of those objects, so I wanted to ask if you could add the sbconfig jar of your post

    thanks

    ReplyDelete
  4. Hi,

    Ok here we go

    http://www.sbsframes.nl/jdeveloper/jejb_config.jar

    thanks

    ReplyDelete
  5. Hi,
    thank you for your very helpful post. I got a question.
    returning a byte[] from a Java Callout generates a element, while returning a byte[] from a JEJB generates a element. Is there any way to get a directly from a JEJB?

    ReplyDelete
    Replies
    1. Sorry. In my previous comment some words has been stripped-off automatically. Here it is again.

      Returning a byte[] from a Java Callout generates a binary-content element, while returning a byte[] from a JEJB generates a java-content element. Is there any way to get a binary-content directly from a JEJB?

      Delete
    2. Hi,

      Sorry don't know but what is your use case , maybe you can use the EJB adapter instead , this uses jax-ws mapping conversion

      Thanks

      Delete