Pages

Saturday, July 18, 2009

Using an EJB Service / Reference in Soa Suite 11G

With Oracle Soa Suite 11G ( FMW11G R1 ) we can finally use the EJB adapter. This adapter can be used as a service or reference. This means we can start a BPEL process by calling a EJB session method or use an EJB to lookup or change data. Using an EJB as service or reference is very cool because it is fast ( RMI ) and we can use the same EJB's ( Multi Tier ) for your Java Web applications and your composites ( Who needs the Database Adapter now?)
Here is a picture of the composite application with an EJB adapter as Service and Reference.

In this blog I will explain you first, how the SDO EJB is created and then how we use this as a Reference and as a Service

Create SDO Eclipse EJB
First step is to create an EJB entity with Eclipselink as persistence provider. For this example I used the Employees table of the HR schema. Next step is to create an EJB Session Bean.
Here is an overview of my EJB model project.

Select the Session Bean and generate a service interface on this

Now it goes totally wrong with the JDeveloper wizard 11G R1.

First step is fix the packages names of the SDO and SDOImpl classes, then we can refactor these classes and move it to the entities package. With this as result.

Select the session bean again and generate for the second time the service interface. Now we will get the WSDL.

Move the EJB WSDL and XSD to the Session bean package. With this as result.

Open the Entity XSD and change the target namespace and xmlns namespace to the same name as the package name in my case /nl/whitehorses/hr/ejb/entities/.
before

after

Open the XSD of the WSDL and import the entity schema and fix the namespace.
Change /nl.whitehorses.hr.ejb.services/ to /nl/whitehorses/hr/ejb/services/ in every java, XSD or WSDL file

Create a Datasource to the HR schema in Weblogic and make sure you are using the XA Oracle Driver and target this Datasource to the Soa suite server.

Deploy the EJB to the Soa Suite instance.

Using the SDO Ejb as a reference in Soa Suite 11g
Open the composite application and drag the EJB adapter on the reference part of the composite.

Fill in the JNDI of the EJB on soa suite server , select the EJB jar and provide the Remote EJB interface class name.
Select the WSDL , Go the classes folder of the EJB model project and select the Session bean WSDL. This will copy the WSDL and the XSD to the local project folders and also import the jar. That's all , now you can invoke this in a BPEL process.

Using the SDO Eclipselink Ejb as a Service in Soa Suite 11g
We can use the same EJB as starting point of our composite application. This time Soa Suite only uses the interface and does nothing with the Session Bean methods.
Drag the EJB adapter to the Services side of the composite overview.

The Service ID is very important because we need this name in serviceFactory.createService, The rest is the same as in the reference part. Use this EJB Service in a BPEL process.

Now we only have to make a simple java class where we call this EJB composite service.




package nl.whitehorses.soa.ejb.service;

import commonj.sdo.helper.DataFactory;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

import nl.whitehorses.hr.ejb.entities.EmployeesSDO;
import nl.whitehorses.hr.ejb.services.HrEmployeeEJB;

import oracle.integration.platform.blocks.sdox.ejb.api.SOAServiceFactory;
import oracle.integration.platform.blocks.sdox.ejb.api.SOAServiceInvokerBean;

import oracle.jbo.common.sdo.SDOHelper;


public class callejb {
public callejb() {
super();
}

public static void main(String[] args) {
try {
// very important to load every schema you use in the EJB
try {
SDOHelper.INSTANCE.defineSchema("nl/whitehorses/hr/ejb/entities/", "EmployeesSDO.xsd");
SDOHelper.INSTANCE.defineSchema("nl/whitehorses/hr/ejb/services/", "HrEmployeeEJBBeanWS.xsd");


} catch (Exception ex) {
ex.printStackTrace();
}

Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");

// soa suite server
props.put(Context.PROVIDER_URL, "t3://localhost:8001");
InitialContext ctx = new InitialContext(props);
SOAServiceInvokerBean invoker = (SOAServiceInvokerBean)ctx.lookup("SOAServiceInvokerBean#oracle.integration.platform.blocks.sdox.ejb.api.SOAServiceInvokerBean");

//-- Create a SOAServiceFactory instance
SOAServiceFactory serviceFactory = SOAServiceFactory.newInstance(invoker);

// use the Service Id in the EJB service adapter
HrEmployeeEJB hrEmployeeEJB = serviceFactory.createService("EmployeeService", HrEmployeeEJB.class);



EmployeesSDO employeesSDO = ( EmployeesSDO )DataFactory.INSTANCE.create(EmployeesSDO.class);
employeesSDO.setDepartmentId(1L);
employeesSDO.setEmail("aaa@aa.nl");
employeesSDO.setEmployeeId(1L);
employeesSDO.setFirstName("edwin");
employeesSDO.setJobId("aa");
employeesSDO.setLastName("biemond");
employeesSDO.setPhoneNumber("123");
employeesSDO.setSalary(1000);

EmployeesSDO resultEmployeesSDO = hrEmployeeEJB.persistEmployeesSDO(employeesSDO);

} catch (Exception ex) {
ex.printStackTrace();
}
}


}



Here is the result of a EJB service instance.

Here the link to official EJB adapter documentation. ( This can be a lot better )
Download here the EJB project I used and here the Soa Suite project.

29 comments:

  1. Marko said

    when i try to call ejb service from one-way bpel process eclilispelink throws an exception during parameter deserialization (parameter extends SDODataObject).
    ejb call from (a)synch bpel process is working.

    ReplyDelete
  2. Hi Marko.

    Interesting, I will take a look.

    thanks edwin

    ReplyDelete
  3. Hi,

    I am facing a problem while calling an EJB method having complex type as input,

    Employee persistEmployee(Employee employee)

    It says “Binding Component failed to invoke method persistEmployeeSDO”

    From the logs, I see ClassCastException has occured

    Caused by: java.lang.ClassCastException: org.eclipse.persistence.sdo.helper.ListWrapper cannot be cast to org.eclipse.persistence.sdo.SDODataObject
    at org.eclipse.persistence.sdo.SDOResolvable.readExternal(SDOResolvable.java:258)
    at commonj.sdo.impl.ExternalizableDelegator.readExternal(ExternalizableDelegator.java:83)
    at org.eclipse.persistence.sdo.SDOExternalizableDelegator.readExternal(SDOExternalizableDelegator.java:60)

    But, I am able make a call EJB method having simple type as input
    Employee getEmployee(Long empId).

    Any inputs on this.

    Thanks in Advance,
    Vidya

    ReplyDelete
  4. Hi Vidya,

    Can you remove the List variables ( manytoone etc ) from the employee entity , lets see if it works with a simple entity

    thanks Edwin

    ReplyDelete
  5. Hi Edwin,

    I don't see any list variables in employee entity.

    Still i am facing same issue.

    Thanks,
    Vidya

    ReplyDelete
  6. Hi,

    Does retrieving from the ejb works. ( only a persist problem )

    Can you make a testcase for me or for Oracle support.

    you can send it to biemond at gmail dot com

    thanks

    ReplyDelete
  7. Hi,

    I had sent you Test Case to your gmail mail id.

    Thanks,
    Vidya

    ReplyDelete
  8. Hi Vidya,

    it is working with me , I send your testcase back with some working bpel examples

    hope this helping .

    thanks Edwin

    ReplyDelete
  9. Hi Edwin,

    Thanks for your support once again.

    I observed one strange thing. If my composite contains a synchronous BPEL process, then I am able to invoke a persistEmployee method successfully. Your test case also contains a synchronous BPEL process.

    I don't have any clue why it is working for synchronous BPEL process and not working for asynchronous BPEL process.

    Any inputs on this?

    Thanks,
    Vidya

    ReplyDelete
  10. Hi guys,
    we have same problem, this example won't work if bpel is asynch or instanced by file adapter. if you replace input parameters with simple types ejb method call will work in sync or asynch or bpels instanced by file adapter. this is not a problem with method result,results can be SDO objects in any case.

    this issue is raised on metalink without response for a month.

    if you like i can send you example projects for described scenarios

    ReplyDelete
  11. Hi Edwin,

    Can you confirm if running the callejb class will persist the employee data in the database?
    I have tried running it without errors but the data was not persisted. Did I miss something?

    Regards,
    Pino

    ReplyDelete
  12. Hi,

    that should work, can you check modelunit of the persistence.xml
    if you use the transaction manager of the application server and use a datasource.

    and can you put the logging on fine ( persistence.xml ) then you can see in the console of the wls server the SQL output. you should see the update statement.

    thanks

    ReplyDelete
  13. I can test the getemployeenameprocess
    in the enterprise manager and the corresponding SQL and SysOut statements are reflected in the console, but running the main method of callejb class does not invoke the persistEmployeesSDO() session bean method even though the steps in the BPEL were executed.

    Pino

    ReplyDelete
  14. Hi

    Can you check two things for me , make a entity and try to call the remote persist method not the sdo one and look in the database

    and in PS1 somehow the jndi name in the composite.xml reference is mixed up with a wrong element
    this is the right one

    <reference name="EmployeeReferenceService"
    ui:wsdlLocation="HrEmployeeEJBBeanWS.wsdl">
    <interface.wsdl interface="/nl/whitehorses/hr/ejb/services/#wsdl.interface(HrEmployeeEJBBeanWS)"/>
    <binding.ejb javaInterface="nl.whitehorses.hr.ejb.services.HrEmployeeEJB"
    jarLocation="ejbSdoHr.jar"
    jndiName="AdfEjbHr-model-HrEmployeeEJB#nl.whitehorses.hr.ejb.services.HrEmployeeEJB"/>
    </reference>

    ReplyDelete
  15. Hi Edwin,

    I did not have problems with the EmployeeReferenceService (Reference swimlane). In that, I was able to have a test case where the persistEmployeeSDO() works.

    My problem is in the EmployeeService (Service swimlane). When I run your client calledejb the BPEL activities were executed successfully, but the persistEmployeesSDO() was not invoked even though that I had already fix the jndiName attribute( I actually copied the whole &ltbinding.ejb&gt of the EmployeeReferenceService and applied it to the EmployeeService).

    Another thing- What to use for the jarLocation? "ejbSdoHr.jar" or "sdo_svc_model.jar"

    Right now, I am suspecting that the problem is on how the EmployeeService and BPELProcess2 is being bound.

    I will try to do some more tweaking and will let you know of any result.

    Regards,
    Pino

    ReplyDelete
  16. Ok, Now I know what you mean.

    indeed , the ejb service does nothing , in that case you will use the ejb interface as starting point , after that bpel takes it over. and BPEL you can do what you want.

    Only the ejb reference does the retrievel , merge and persists.

    thanks

    ReplyDelete
  17. Hi Edwin,
    Can you please expalin JNDI of the EJB on soa suite server.
    And after creating datasource for HR schema in weblogic console, do we need to update that any where?

    Regards
    PavanKumar.M

    ReplyDelete
  18. Hi,

    can you explain your problem.

    The datasource will be used in the EJB. ( persistence.xml ) .

    the same datasource can be used in a db or aq resource adapter.

    thanks

    ReplyDelete
  19. Hi Edwin,

    I am using 11g PS2. I have created EJB and created data source as you mentioned. In bpel i am calling remove operation of EJB. I am getting binding fault saying "Invocation Exeption: :" as summary.
    I have tested StandaloneEJB and it is ok. Seems some configuration issues.
    Please show me the way.

    Regards
    PavanKumar.M

    ReplyDelete
  20. Hi,

    Can you check the reference part in the composite , sometimes the wizard is not working well ( uses wrong attributes). check the jndiName attribute if it contains the jndi name.

    thanks

    ReplyDelete
  21. Hi Edwin,

    We followed the steps to use an EJB Service. We have deployed and can successfully call a SOA composite. We've added an EJB Adapter to provide an additional method of calling the composite. When trying to call the composite EJB, we get:

    java.lang.reflect.UndeclaredThrowableException
    at $Proxy1.getRetail(Unknown Source)
    at testejbclient.callejb.main(callejb.java:61)
    Caused by: java.lang.ClassNotFoundException: o0.v1.services.rules.co.com.GetRetail
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)

    more details of the exception at http://forums.oracle.com/forums/thread.jspa?threadID=2194850&tstart=0

    Regards,
    Subha

    ReplyDelete
  22. Hi,

    Can you check if you made a service interface jar and use that everywhere and dont include the bean, only the interface and entities.

    thanks

    ReplyDelete
  23. Hi Edwin,

    FYI. There must be a lot of changes in 11.1.1.5 because I got a lot of issues when I run your sample client "callejb.java" in JDeveloper 11.1.1.5. The same is true with my own samples that I have made. Aside from the missing classes, I am stuck with the following error:

    "Caused by: oracle.mds.config.MDSConfigurationException: MDS-01330: unable to load MDS configuration document
    MDS-01329: unable to load element "persistence-config"
    MDS-01370: MetadataStore configuration for metadata-store-usage "mstore-usage_1" is invalid.
    MDS-01259: The metadata store "oracle.mds.persistence.stores.file.FileMetadataStore" cannot be instantiated.
    oracle/dms/instrument/Noun"

    FYI and regards,
    Rommel Pino

    ReplyDelete
  24. Hi Pino,

    Indeed, it seems like a bug. I think its need the some kind of configuration for the DMS which is located in the SOA MDS.

    I think it should not use DMS ( I think it is something for performance ) or detect that is not necessary.

    Maybe Oracle made some different client classes for this or it has to remove the dependency to DMS

    can you check the jars

    thanks

    ReplyDelete
  25. Sorry to resurrect this post but we are facing the similar class cast exception
    --------------------------------
    java.lang.ClassCastException: org.eclipse.persistence.sdo.helper.ListWrapper cannot be cast to org.eclipse.persistence.sdo.SDODataObject
    --------------------------------
    as we have upgraded SOA Middle from 11.1.1.2 (PS1) to 11.1.1.5 (PS4).
    What we detect is that ${wn.bea.home}/modules/org.eclipse.persistence_1.0.0.0_1-2-0.jar changed to
    ${wn.bea.home}/modules/org.eclipse.persistence_1.1.0.0_2-1.jar

    and
    for commonj.sdo_1.0.0.0_1-0.jar, it is still available and a new is available that we are using instead commonj.sdo_2.1.0.jar.

    Are we right to use the new one (2.1.0) or should we stick to 1.0.0.0_1-0 or is it another thing ?

    Regards,
    Guillaume

    ReplyDelete
  26. Hi,

    I also use the latest eclipselink and it is working fine for jpa.

    Do you use it for soa suite or for deploying adf bc sdo web services.

    Nowadays you can call the ejb session bean without any sdo.

    sdo wizard in jdev was very buggy and is now a little bit better.


    thanks

    ReplyDelete
  27. Hi Pino,

    I have a Question, I have one composite which is having BPEL component and Calling the EJB webserive as referece.

    Bpel is calling one method of the EJB serive, if that method give exception then how to handle and i want to retry to call that method to get the output.

    so now how can write the retry exception mechanism in bpel.

    Advance Thanks,
    Ramu

    ReplyDelete
    Replies
    1. Hi,

      I think you get a binding error which you can handle in BPEL with catch all or the specific error catch or do it in the fault framework

      plus with transactions you can better set the EJB method to requires new else you will see the error when BPEL finishes and then it is too late.

      Thanks

      Delete
  28. Hi,
    The wizard to create service interface in JDeveloper 11g R1 does not work. It does not create .xsd files etc. How can I pass this step?

    thx,
    Parisa

    ReplyDelete