Archive for June, 2014

Web Services Atomic Transactions in ColdFusion

June 20, 2014

In order to be able to perform web services atomic transactions, we need to run the ColdFusion code
on a Java Application Server that supports WS-AT. Obviously the Tomcat that ships with ColdFusion does not
support it (out of the box). One could try to plugin the Atomikos transaction manager, but for the purpose of
this test, we decided to deploy ColdFusion on WebLogic and benefit from the WS-AT support that is offered by WebLogic.

In the example below, we will wrap 2 web service invocations in a transaction managed by WebLogic’s transaction manager.
The methods persistDetachedContact in WebServiceA and removeDetachedContactDetail in WebServiceB both require WSAT10,
which means that they can not be invoked if there is no transaction context.

// load webservice classes
wsclassA = CreateObject(“java”,”eu.alrighty.marbie.WebServiceA”);
wsclassB = CreateObject(java”,”eu.alrighty.marbie.WebServiceB”);

// load web service wsdl’s
wsdlUrlA = wsclassA.getClass().getClassLoader().getResource(“META-INF/wsdls/WebServiceAService.wsdl”);
wsdlUrlB = wsclassB.getClass().getClassLoader().getResource(“META-INF/wsdls/WebServiceBService.wsdl”);

// prepare transactional feature
feature = CreateObject(“java”,”weblogic.wsee.wstx.wsat.TransactionalFeature”);
ta = CreateObject(“java”,”weblogic.wsee.wstx.wsat.Transactional”);
flowtype = CreateObject(“java”,”weblogic.wsee.wstx.wsat.Transactional$TransactionFlowType”).SUPPORTS;
version = CreateObject(“java”,”weblogic.wsee.wstx.wsat.Transactional$Version”).WSAT10;
feature.setFlowType(flowtype);
feature.setVersion(version);

// get webLogic Transaction Manager
ctx = CreateObject(“java”,”javax.naming.InitialContext”);
tx = ctx.lookup(“java:comp/UserTransaction”);

// instantiate webService stubs through wsdl’s
wsa = CreateObject(“java”,”eu.alrighty.marbie.WebServiceAService”).init(wsdlUrlA);
wsb = CreateObject(“java”,”eu.alrighty.marbie.WebServiceBService”).init(wsdlUrlB);

// start the transaction
tx.getTM().begin();

// find a contact person from webService A, and create a new contact person with it (increase Id);
contacts = wsa.getWebServiceAPort([feature]).findAllContacts();
contact = contacts[ArrayLen(contacts)];
contact.setId(IncrementValue(contact.getId()));
writeDump(contact.getId())

// find a contact detail from webService B, and create a new contactdetail with it (increase Id);
contactdetails = wsb.getWebServiceBPort([feature]).findAllContactdetails();
contactdetail = contactdetails[ArrayLen(contactdetails)];
contactdetail.setId(IncrementValue(contactdetail.getId()));
writeDump(contactdetail.getId());

// add contact to webService A
writeDump(wsa.getWebServiceAPort([feature]).persistDetachedContact(contact));
// add the contact detail to webService B
writeDump(wsb.getWebServiceBPort([feature]).removeDetachedContactDetail(contactdetail));

// (optionally) dump some information on the status of the transaction
writeDump(tx.getTM().getTransaction().getStatus());

// commit the transaction
tx.getTM().commit();

In the code above, a contact person is added to a database through web service A, running on a
WebLogic A. Secondly, a (non existing) contact detail is removed from a database through web service B, running on a
WebLogic B. Since the second command can not be executed, the first one is properly rolled back, and the test
ends leaving the data in the database to its’ original state.

(Thanks to Petar Banicevic for helping me out with the weblogic transaction manager).