Sunday, April 14, 2013

Simplified XTS Context Propagation

In this blog post I'd like to introduce a new feature from our recent Narayana 5.0.0.M2 release. It was developed by our newest addition to the Transactions Team, Gytis Trikleris. This feature simplifies the way you write clients for WS-AT and WS-BA enabled Web services.

Previously the developer was responsible for setting up the client side handler chain. This has proven problematic as the code is rather cumbersome and it's easy to make a mistake. Here's an example of what the client code used to look like:



import org.jboss.jbossts.txbridge.outbound.JaxWSTxOutboundBridgeHandler;
import org.jboss.jbossts.txbridge.outbound.JaxWSHeaderContextProcessor;
...
MyService client = service.getPort(portName, MyService.class);

BindingProvider bindingProvider = (BindingProvider) client;

List handlers = new ArrayList(); 
handlers.add(new JaxWSTxOutboundBridgeHandler()); 
handlers.add(new JaxWSHeaderContextProcessor()); 

bindingProvider.getBinding().setHandlerChain(handlers);


In this example, the application has begun a JTA transaction and is now invoking a Web service. The service supports WS-AT, and the developer would like the JTA transaction to be distributed to this service. Therefore, the developer carefully constructs a client side handler chain and ensures that the bridging handler is invoked before the XTS handler. Get this order wrong and the bridging will fail. This code is required for every Web service port that needs to propagate a WS-AT or WS-BA transaction.

We still support the above way of writing clients and the behaviour of XTS in that case has not changed. However, we now have some additional ways to enable a distributed transaction over Web services.

Enable Globally

You can now enable transaction propagation for all Web service calls that are invoked within a JTA, WS-AT or WS-BA transaction. This is done with the 'defaultContextPropagation' property in the XTS subsystem config of the standalone-xts.xml.


<?xml version="1.0" encoding="UTF-8"?>
<subsystem xmlns="urn:jboss:domain:xts:1.0">
   <xts-environment url="..." />
   <default-context-propagation enabled="true" />
</subsystem>


As this is enabled by default (for standalone-xts.xml), calls to all Web services that support WS-AT or WS-BA will automatically receive the transaction context allowing them to participate in the distributed transaction.

The transaction context is simply ignored if the service does not support WS-AT or WS-BA. This is done by setting MustUnderstand=”false” on the 'CoordinationContext' SOAP header. Unfortunately, this may cause issues when invoking WS-AT or WS-BA enabled Web services on other vendors’ application servers. This is because the WS-Coordination specification states that MustUnderstand must be set to true. If you are affected by this issue, you will need to explicitly enable the transaction propagation as described in the next section.

There is a slight overhead associated with having an unused WS-AT transaction in place. We intend to investigate this as part of https://issues.jboss.org/browse/JBTM-1515



Enable/Disable per Web service port

The default context propagation policy can also be overridden on a per Web Service port basis. This allows the developer to easily state which Web Service clients must and must-not propagate the transaction context.

In the following example, the developer states that the current JTA transaction must be distributed over the Web Service calls on this port:



import org.jboss.jbossts.txbridge.outbound.JTAOverWSATFeature;
...
MyService client = service.getPort(portName, MyService.classnew JTAOverWSATFeature());


This is done through the standard JAX-WS WebServiceFeature facility. A JAX-WS WebServiceFeature allows meta-information to be added to a port that describe cross-cutting behaviour, such as logging, security or compression. In our case we use the 'JTAOverWSATFeature' to state that any JTA (or WS-AT) transaction should be distributed via calls on this client. Calls to this service will fail if the Web service does not support WS-AT or WS-BA (in this case, XTS sets MustUnderstand=true on the 'CoordinationContext' SOAP header as the developer has explicitly stated that it is required).

The developer may also state that the transaction must-not be distributed over calls to this Web service. This is done by setting the 'JTAOverWSATFeature' feature to disabled:



import org.jboss.jbossts.txbridge.outbound.JTAOverWSATFeature;
...
MyService client = service.getPort(portName, MyService.classnew JTAOverWSATFeature(false));


The use of 'JTAOverWSATFeature' overrides whatever default context propagation is set to in the standalone-xts.xml.

Feedback

We've tried to come up with a solution that doesn't impact existing applications, whilst also being as intuitive as possible for developers of new applications. If you are having difficulties with this approach or if it simply doesn't make sense, please get in touch in the usual ways (comments on this post or via the forum).


Acknowledgements

I'd like to say a bit thank you to Alessio Soldano and the JBossWS team. They provided a lot of advice and also added new features to the JBossWS SPI to support these features.

1 comment:

Alessio Soldano said...

You're welcome Paul :-) Nice post btw!