Monday, April 8, 2013

API Improvements for Compensation-based Transactions

In a recent post I talked about API improvements we are introducing for applications that use ACID transactions. In this post I’ll cover what are we doing for users of compensation based transactions.

Even though we only have WS-BA for compensation-based transactions at the moment, we are still following the principle that the same transaction API should be used to develop the application, regardless of what transport is actually used to distribute the transaction. This will become more important when we support compensations over other technologies, such as REST or JBoss remoting.

Unfortunately there is no standard API for compensation based transactions, so we needed to develop our own. This API is still in the early stages of development. However, we are keen to get community feedback, so we made the early version available as part of our recent Narayana 5.0.0.M2 release.

I’ll cover the basics of the API in this post; so as to give you a feel for what we are proposing. You can take a look at the Narayana quickstarts for more complete examples. We also intend to blog more on this subject in the coming months as we develop our ideas further.

I’ve omitted a recap on compensation-based transactions and when you need them. This will be the subject of a future blog posting.

Example

Hopefully this example will give you an idea of how the new API works

The following code comprises part of a "Warehouse Service", implementad as an EJB exposed as a JAX-WS Web Service:


@Compensatable
@Stateless
//JAX-WS annotations omitted
public class WarehouseServiceImpl implements WarehouseService {
{
    @DataManagement private Map txDataMap;
    @PersistenceContext protected EntityManager em;

    @WebMethod
    @ServiceRequest
    public void shipItem(String item, String address) throws {
        //Use em to add order to DB
        txDataMap.put("orderID", orderID);
    }

    @Compensate
    private void cancelOrder() {
        Integer orderID = txDataMap.get("order");
        //Use em to lookup order by ID and cancel it
    }
}

The @Compensatable annotation is used to state that methods on the class should be invoked in a compensation-based transaction. This is similar to the @TransactionAttribute provided by JTA.
The ‘shipItem’ method represents the business logic of the service. It has a corresponding compensation handler which can be used to undo this work.

When ‘shipItem’ is invoked, a new entry is added to the database. This update is done in a regular JTA transaction that commits when the method completes successfully. The ID of the order is saved in the ‘txDataMap’ to be used later by the compensation handler.

The @DataManagement injected Map stores state for the lifetime of the transaction. The state is isolated to the transaction and is garbage collected when the transaction ends. In future releases, this data will also be available at recovery time.

@Compensate annotates the compensation handler for undoing the work done in the business method. In this example, the compensation action is to look up the ID of the order and then make an update to the DB to mark it as cancelled. This DB update is done in a separate transaction that commits when ‘cancelOrder’ completes successfully.

The current release only supports a single @Compensation method for all @ServiceRequest methods in the class. Subsequent releases will remove this limitation.

Getting Started

Hopefully you are now eager to get started and want to know where to go next! Here are our suggestions:

* Download and try the Quickstarts from here.
* Provide feedback and get help through our forum.
* Track the progress of issues here.
* Subscribe to this blog.
* Fork the Narayana repo and contribute. Of course, we always welcome community contribution. We can advise on good issues for new contributors, or you can suggest a feature that interests you.



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.

No comments: