Level: Introductory Manish Verma (mverma@secf.com), Center Head and VP Delivery, Second Foundation
30 Sep 2005 Learn to build transaction-aware applications and Web services. Manish Verma shows you how Web services transactions are different from normal transactions, and demonstrates how to create Web services that can participate in transactions.
The problem of long-running transactions
Transactions are an important building block in all serious business applications. A transaction is a unit of work that involves one or more resources and is either completed in its entirety or is not done at all. Participating resources are locked for the duration of the transaction. Depending on the readiness of all the participating resources, the changes made to the resources are either committed or rolled back, and the lock is released.
To further illustrate the concept of a transaction, consider a scenario where you buy a book on an e-commerce site. Two main tasks happen in this scenario:
- You order the book.
- Your credit card gets charged
Keep in mind that these tasks must happen in unison or not at all -- after all, you do not want to end up in a situation where you do not order the book, but your credit card still is charged. Conversely, the merchant does not want to end up with the processed book order but the credit card is rejected. Proper transactions ensure that no undesirable situations arise. Either both the actions happen successfully or neither happen at all.
Increasingly, Web services are key additions to business applications and third-party integration. A complex business process that accesses multiple Web services needs a reliable mechanism for stringing together the various Web services. This ensures that no part of the business process gets out of sync with the other parts.
Let me start with a commonly used example -- the travel agency. A customer intends to create a travel plan through an online travel agency. To
do this, the online travel application calls the following three Web services:
- Air ticket booking
- Hotel reservation
- Taxi reservation
 |
ACID properties
ACID properties consist of the following:
- Atomicity -- All the processes participating in the transaction (henceforth referred to as "participants") must confirm or cancel.
- Consistency -- A consistent result is obtained.
- Isolation -- Effects are not visible until all the participants confirm or cancel. Intermittent status of various participants is not visible to the external world.
- Durability -- Effects of the transaction are stored.
|
|
These three services are available from three separate vendors. If any one of these three services fails, the customer does not wish to proceed with the transaction (again, either all three services must succeed or none at all). The only way that the developer can guarantee this is to include all the three of these processes in a single transaction.
So far so good! This establishes the need for a transaction. Next, I will explain how the transaction required for the above example is different from a normal transaction. By "normal transaction," I mean a transaction that conforms to the ACID properties.
If you bound these Web services together with an ACID-based traditional transaction, you would run into the following scenarios:
- The resources used by the Web services would be locked for an indefinite period of time, until all participating services have executed.
- One central transaction manager would take control of all the services to coordinate their actions. As a result, the services would lose control over their resources.
 |
Denial of Service (DoS) attacks
DoS attacks aim to prevent legitimate access of a service by its users. For example, when an ACID-based transaction coordinates the functions of various Web services, a rogue process might start a transaction involving various Web services, and then keep the services waiting for a task to finish -- which might never happen. As a result, those Web services are unavailable for other processes.
|
|
These scenarios expose the Web services to Denial of Service (DoS) attacks. Critical resources of the participating organizations might become unavailable, which can lead to considerable economic and financial loss.
To overcome the shortcomings of traditional transactions, developers have created a new way to manage transactions in the Web services world. In this solution, no resources are locked and coordinators and compensating tasks replace the external manager. I’ll explain this in more detail next.
The proposed solution: Compensation-based transactions
The proposed solution of compensation-based transactions has the following salient features:
- Ability to manage consistency of data across applications without locking resources
- Coordination of various transaction participants without giving complete authority to a central transaction manager
- Ability to work in scenarios where participants' availability and/or response is not guaranteed
The above features are made available in a solution that is based on Web Services-Coordination/Web Services-Transaction (WS-C/T) specifications. IBM, Microsoft, and BEA jointly developed these specs. In the next sections, I'll explain these specifications and then provide you with a step-by-step guide to creating transaction-aware Web services.
An overview of WS-C/T
This solution has two distinct pieces: Web Services -- Coordination (WS-C) and Web Services -- Transaction (WS-T).
WS-C specifies all of the required basic transaction infrastructure support. It includes the following:
-
Creation of a coordinator for a specific coordination protocol: The responsibility of the coordinator is to send messages back and forth between the participants. The coordination protocol defines the types of messages that the participant and the coordinator exchange, as well as the sequence of those messages -- essentially the state transition.
-
Registration of participants with the coordinator: Participants register themselves with the coordinator to receive messages.
-
Propagation of context: The coordinator takes the responsibility to pass the transaction-related context information between participants.
WS-T defines two distinct transactional models:
-
Atomic transaction (AT): ATs are similar to traditional transactions with ACID properties. This model supports transactions that are short-lived. (Refer to the example of buying a book on an e-commerce site, in "The problem of long-running transactions.")
-
Business activity (BA): The BA transactional model is of most relevance here. This model is specifically designed for long-running interactions. It allows participants to take part in a transaction without getting their resources locked. The model provides a mechanism that informs the participants to take appropriate action if the transaction outcome is different from the type of action sought by the participant. (Refer to the travel itinerary example in the section "The problem of long-running transactions"; I will continue to develop this example in the remainder of the article.)
In the next section, I'll take you through the mechanics of creating transactional Web services and the client application that accesses them.
In the trenches: Creating transaction-aware Web services
 |
Arjuna XML Transaction Service
Arjuna XML Transaction Service is a middleware solution that supports processing of applications in distributed computing environments. Using this software, you can ensure the accuracy and completeness of your business processes. It supports the WS-AtomicTransaction and WS-BusinessActivity specifications.
|
|
First, here's a list of the software you'll need for this process:
- Arjuna XML Transaction Service 1.0. (evaluation copy)
- JBoss 3.2.5
- Ant 1.6.2
First, deploy Arjuna on the JBoss application server per the instructions provided with the Arjuna software. You might also try the demo app to ensure that the deployment is successful.
To demonstrate creation of transactional Web services, I'll take you through the following steps:
- Create two Web services using Arjuna XML Transaction Service.
- Write a client application that calls both of these Web services in a transaction.
- Deploy the Web services and the client application on the JBoss app server. Access the client application to see the transactional behavior of the two Web services.
Step 1. Create two Web services using Arjuna XML Transaction Service
Web services that you create with Arjuna XML Transaction Service have two distinct parts:
- The transaction-aware service deals with the business logic.
- The participant handles the transaction protocols.
The Web services that I create here are very simple; the business logic simply prints a message on the JBoss console.
Listings 1 and 2 show the code of the service and the participant, respectively, for one of the Web services.
Listing 1. Transaction-aware service
public class PersistDataOne {
public boolean writeToFileOne(boolean passFail) {
PersistDataOneMgr dataManager =
PersistDataOneMgr.getSingletonInstance();
BusinessActivityManager activityManager =
BusinessActivityManagerFactory.businessActivityManager();
// get the transaction context of this thread:
String transactionId = null;
try {
transactionId = activityManager.currentTransaction().toString();
} catch (com.arjuna.wst.SystemException e1) {
e1.printStackTrace();
}
System.out.println("PersistDataOne transaction id ="
+ transactionId);
// invoke the back-end business logic:
dataManager.writeToFileOne(transactionId, passFail);
PersistDataOneParticipant persistDataOneParticipant =
new PersistDataOneParticipant(
transactionId,
passFail);
// enlist the Participant for this service:
BAParticipantManager participantManager = null;
try {
participantManager =
activityManager.
enlistForBusinessAgreementWithParticipantCompletion
(persistDataOneParticipant,
new Uid().toString());
} catch (Exception e) {
System.err
.println("writetoFileOne: Participant enlistment failed");
e.printStackTrace(System.err);
return false;
}
try {
participantManager.completed();
} catch (Exception e2) {
e2.printStackTrace();
}
return passFail;
}
}
|
In Listing 1, the service further calls business logic from another class named PersistDataOneMgr. This class is included in the accompanying source bundle.
Take a closer look at the service class -- three significant things are happening:
-
BusinessActivityManager is instantiated. This is the transaction coordinator and it allows the participants to be registered with it.
- The business method
writeToFileOne is invoked on service class PersistDataOneMgr.
- The corresponding participant
PersistDataOneParticipant of the service PersistDataOneMgr is registered with the transaction coordinator. This is used to compensate the tasks in case of transaction failure.
Listing 2 is the code of the participant, which implements all the lifecycle methods that manage the transaction protocols. Listing 2 implements the method of the transaction protocol -- BusinessAgreementWithParticipantCompletionParticipant. (For more about transaction protocols, see Business Activity -- Transaction protocols.)
One of the lifecycle methods is compensate. This method is invoked by the transaction coordinator when the transaction fails. It is invoked on the participants of those services that actually succeed; the objective is to get the successful participants to their original state, since the transaction as a whole has failed. Reversing the work of successful participants is application specific. (For more on the various protocols, see Business Activity -- Transaction protocols.)
Listing 2. Participant
public class PersistDataOneParticipant
implements
BusinessAgreementWithParticipantCompletionParticipant {
public PersistDataOneParticipant(String txID, boolean passFail) {
dataManager = PersistDataOneMgr.getSingletonInstance();
TransactionID = txID;
PASS_FAIL = passFail;
}
public void close() throws WrongStateException, SystemException {
System.out.println("PersistDataOneParticipant.close");
}
public void cancel() throws WrongStateException, SystemException {
System.out.println("PersistDataOneParticipant.cancel");
}
public void compensate() throws WrongStateException, SystemException{
System.out.println("PersistDataOneParticipant.compensate");
}
public String status() {
return Status.STATUS_ACTIVE;
}
public void unknown() throws SystemException {
}
public void error() throws SystemException {
}
private static String TransactionID;
private static boolean PASS_FAIL;
private static PersistDataOneMgr dataManager;
}
|
Step 2. Write a client application that calls both these Web services in a transaction
 |
Business Activity -- Transaction protocols
A participant can conform to two transaction protocols for business activity transactions:
-
BusinessAgreementWithParticipantCompletionParticipant --
In this protocol a participant can unilaterally choose to exit the transaction. However, if the participant wants to continue in the transaction, it must be able to compensate for the work it has done. In such a case, the participant sends a Complete message to the coordinator and waits for either a Close message (indicating successful completion) or a Compensate message (indicating that the transaction has failed).
-
BusinessAgreementWithCoordinatorCompletion --
This protocol is similar to BusinessAgreementWithParticipantCompletionParticipant with one difference -- a participant cannot exit the transaction of its own free will. A participant must get a Complete message from the coordinator to take any further action.
|
|
To keep things simple for this demonstration, the second Web service is basically identical to the first; the only differences are the names of the methods and the messages that it prints. I have omitted the code listing for the second service. You can see the entire working sample code for this application in the download file, x-transws_wstransaction.zip.
When you create the client application, it must do two things:
- Demarcate transaction boundaries; typically using begin, commit, or rollback
- Call Web services business logic within the transaction boundaries
Arjuna XML Transaction client APIs take care of the first item. The APIs provide a mechanism that defines the transaction boundaries: The begin method on the class UserBusinessActivity is used to define the start of the transaction; the close method on the same class defines the completion of the transaction; and the cancel method on the same class signals cancellation of the transaction.
As for calling the Web services business logic, your application can adopt any mechanism to call the Web services from within the transaction boundaries -- that is, to talk to the Web services you can use the Web services client-side APIs provided by any vendor. However, the transactional context must be embedded in the message that the client application sends to the Web service; also, the client application should be able to extract the transactional context from the response messages.
The sample application does not do anything about manipulating the transactional context in the client application's messages, and you do not need to be concerned about that either, for now. The reason: Arjuna XML Transaction Service comes with a filter that takes care of the insertion and extraction of the transactional context from the client messages, if the client library is Apache AXIS.
One limitation of version 1.0 of Arjuna XML Transaction APIs is that the client must reside in a container that can host servlets.
Now to the actual brass-tacks. Using Apache’s WSDL2Java utility, you create the client-side stubs for the Web services. To use the utility, you need the WSDL of the two Web services. You get this WSDL by deploying the Web services in JBoss.
Once you have the client-side stubs of the Web services, you put together a client application as shown in Listing 3.
Note that in the method runBusinessActivity, the class UserBusinessActivity of the Arjuna XML Transaction client API is used to define the transaction boundaries. Within these boundaries, one method each of the two Web services persistOne.writeToFileOne(onePassFail) and persistTwo.writeToFileTwo(twoPassFail) are called.
You are not done yet with the client application. To see the transaction behavior of the Web services, you have to create two scenarios:
- Both of the Web services successfully complete their business logic.
- The second Web service fails, so you can verify that the first one actually compensates for the work that it did.
To create these scenarios, you just need to change the value of two parameters in the client application, PersistDataClient.
For the first scenario, both the variables onePassFail and twoPassFail must be set to true. Deploy the entire solution and run the client application. You will see the transaction complete successfully. You can see this in the log messages on the JBoss console.
To create the second scenario, set the variable onePassFail to true and twoPassFail to false. This ensures that the first Web service passes successfully while the second fails. Deploy the application and run the client, as described in the next section. Note that the first Web service completes successfully, the second one fails, and then the first Web service’s compensation method is called.
Step 3. Deploy the Web services and access the client application
Here you need to deploy the Web services and the client application on the JBoss app server, and access the client application to see the transactional behavior of the two Web services.
To make it easy for you to experiment with the application, I have created an Ant script to build and deploy the application on the JBoss server. The build file is included in the download package, x-transws_wstransaction.zip.
However, you need to change the path settings in the build file to suit your installation.
Experimentation ideas
I suggest that you try the following experiments to take the demo of this article a step further, and to get a deeper insight into the topic:
- Play with the parameters as described in Step 3 to see the changing behavior of the transaction.
- Enhance the sample application to include more complex business logic.
- Deploy multiple instances of JBoss, have multiple Web services on different JBoss instances, and then string them together into a single transaction.
Conclusion
Many developers have grown comfortable with ACID-based transactions, but with business software growing more complex, such transactions no longer address all scenarios. Hence, you might need a different transaction type for scenarios in which:
- Transactions are long running
- Transaction participants are not under the control of a single authority
- The outcome of a transaction might differ from the individual participant's outcome
This article has examined an alternative transaction type, the compensation-based transaction. Now that you've studied the demo application presented here, you're ready to roll out compensation-based transactions in current and future business applications.
Download | Description | Name | Size | Download method |
|---|
| Web services transactions source code | x-transws_wstransaction.zip | 20 KB | HTTP |
|---|
Resources Learn
Get products and technologies
About the author  | 
|  | Manish Verma heads Second Foundation's software development center in India. Manish has 13 years' experience in all aspects of the software development lifecycle, and has designed integration strategies for client organizations running disparate systems. Manish's integration expertise is founded on his understanding of a host of technologies, including various legacy systems, .NET, Java technology, and the latest middleware. Prior to Second Foundation, Manish worked as a software architect and technical lead at Quark Inc., Hewlett Packard, Endura Software, and The Williams Company. You can contact Manish at mverma@secf.com. |
Rate this page
|