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
}
}
@Stateless
//JAX-WS annotations omitted
public class WarehouseServiceImpl implements WarehouseService {
{
@DataManagement private Map
@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.
No comments:
Post a Comment