Tuesday, June 7, 2011

Invoking SOA Composite as part of a global transaction

Scenario: Java client calls SOA Suite composite to process an order as part of a global transaction. The SOA composite is expose as an EJB service. The composite contains 1 BPEL process that itself calls an EJB service to update our Orders DB.

I'm using SCOTT's schema and have already created a datasource on WLS for it.

name: scottDS
jndi: jdbc/scottDS



Step 1. Create DB Table - test
Create table test (id number(2), quantity number(2));

Step 2. Create a stateless session EJB to update this table
create a new application/project in JDev and include a statelsss session EJB 2.1











Step 2.1 - Add the following business method

public String callDB(int id, int quantity) {
Connection connection = null;
DataSource dataSource = null;

try
{
/*
* 1. Create an InitialContext.
* 2. From the initial context, lookup the logical datasource reference
that is in the deployment descriptor.
*/
InitialContext initialcontext = new InitialContext();
dataSource = (DataSource)initialcontext.lookup("jdbc.scottDS");

System.out.println("***** Got Datasource...");
// Check to see if the datasource is valid
if(dataSource==null)
{
System.err.println("*** DataSource retrieved is null, did you add the code?");
throw new ServletException("DataSource retrieved is null");
}

connection = dataSource.getConnection();
Statement stmt = connection.createStatement();
String insert = "insert into test values(" + id + "," + quantity + ")";
System.out.println("INSERT = " + insert);
stmt.executeUpdate(insert);

ResultSet rset = stmt.executeQuery("Select to_char(sysdate) from dual");
while (rset.next())
{
System.out.println("*** Date = " + rset.getString(1));

}
}

catch (Exception e)
{
System.err.println("*** init() Exception, " + e.getMessage());
System.err.println(e);
}
return "Ok";

}

Step 3 - Deploy and view the JNDI tree

specify jndi name before deploying -





Step 4 - Create a new SOA App in Jdeveloper

Create a SOA Composite app
Add the ejb jar from the previous project to the apps classpath.
(We really only need the interface!)










Create the following input xsd





Create a synchronous BPEL process



Create an EJB reference






Wire up



Add the Invoke to the BPEL process



Add the required Assigns, before and after








Step 5 - Expose the composite as an EJB Service








Make InputOrder and OrderType serializable



Deploy and view in JNDI tree

Step 6 Create the EJB client in the SOA project

package demoejbtxsoa;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import java.util.Hashtable;

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

import processorder.demo_ejb_tx_soa.demo_ejb_tx_soa_app.com.oracle.xmlns.InputOrder;
import processorder.demo_ejb_tx_soa.demo_ejb_tx_soa_app.com.oracle.xmlns.OrderType;
import processorder.demo_ejb_tx_soa.demo_ejb_tx_soa_app.com.oracle.xmlns.ProcessOrder;
import processorder.demo_ejb_tx_soa.demo_ejb_tx_soa_app.com.oracle.xmlns.ProcessResponse;


public class MyEJBClient {
public static void main(String [] args) throws Throwable {
try {
final Context context = getInitialContext();

Proxy proxy = (Proxy)context.lookup("ejb/SOAEJBService");

// preparing the method to be called on the remote EJB
Method method =
ProcessOrder.class.getDeclaredMethod("process", new Class[] {InputOrder.class});
InputOrder id = new InputOrder();
id.setId(23);
id.setCustName("NiallC");
id.setQuantity(7);
OrderType ot = new OrderType();
ot.setComments("Good Customer");
ot.setProduct("Oracle SOA Suite 11g");
ot.setProductGroup("FMW");
ot.setProductKey(new Long(12345));

id.setOrder(ot);

InvocationHandler handler = Proxy.getInvocationHandler(proxy);

ProcessResponse response = (ProcessResponse)handler.invoke(proxy, method, new Object[] { id });


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

private static Context getInitialContext() throws NamingException {
Hashtable env = new Hashtable();
// WebLogic Server 10.x connection details
env.put( Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory" );
env.put(Context.PROVIDER_URL, "t3://127.0.0.1:7001");
env.put(Context.SECURITY_PRINCIPAL, "weblogic");
env.put(Context.SECURITY_CREDENTIALS, "welcome1");

return new InitialContext( env );
}
}

Run the client -

Check the DB




Step 7 JTA enable...

Add the following code to the EJB Client -

import javax.transaction.UserTransaction;

public final static String JTA_USER_XACT = "javax.transaction.UserTransaction";

UserTransaction ut = (UserTransaction)context.lookup(JTA_USER_XACT);
ut.begin();

//ut.rollback();
ut.commit();



Define BPEL to participate in the global TX.

Add this property to BPEL specification in composite.xml






Test

commit()





rollback()





No comments: