Recipe22.2.Applying Transactions


Recipe 22.2. Applying Transactions

Problem

You want to introduce transactional behavior to a method in your application.

Solution

Use the Director aspect-oriented design pattern to declare an abstract aspect that captures the generic behavior of controlling a transaction, as shown in Example 22-4. Extending the abstract transaction aspect, declare specialized subaspects for each transaction within your application.

Example 22-4. Declaring the generic behavior of a transaction in a reusable abstract aspect
public abstract aspect TransactionAspect  {    protected abstract pointcut transactionalCall( );        protected pointcut transactionBoundary( ) :        transactionalCall( ) && !cflowbelow(transactionalCall( ));        protected interface Transaction    {       public void commit( );       public void rollback( );    }        protected Transaction transaction;    before( ) : transactionBoundary( )     {        setupTransaction(thisJoinPoint.getArgs( ));    }        after( ) returning: transactionBoundary( )     {        transaction.commit( );    }        after( ) throwing: transactionBoundary( )     {        transaction.rollback( );      }        protected abstract void setupTransaction(Object[] args); }

Discussion

Transactions are used to group a selection of operations into a cohesive unit that either completes or, in the case where one step in the process fails, reverts back to its original state.

In Example 22-4, the TRansactionAspect first specifies the TRansactionCall( ) abstract pointcut. This pointcut is used by specialized subaspects to specify the methods within the target application that are to be treated as transactional.

The transactionBoundary() pointcut then builds on the transactionCall( ) pointcut to specify where the transaction starts and ends. The cflowbelow( ) pointcut is used to ignore any join points that may occur within the life of the transaction.

The TRansactionAspect needs to store and interact with transactions generically so the transaction interface is defined. The transaction interface provides a base for subaspects to implement their own transaction classes. A single TRansaction attribute is then used to indicate the current transaction being managed by the aspect.

Finally, three pieces of advice work with the TRansaction attribute at the different points within a transaction's lifecycle. The before() advice calls the abstract setupTransaction(Object[]) method so the transaction attribute can be correctly initialized with the appropriate transaction implementation. The after() returning advice will be executed if the join points selected by the TRansactionCall( ) pointcut return without raising an exception; this is a good time for the transaction to be committed. The after( ) throwing advice caters to the situation where a join point returns with an exception, so the transaction needs to be rolled back.

Example 22-5 shows how to specialize the transactionAspect for an example application where the transfer(..) method is selected by the implementation of the transactionalCall( ) pointcut to mark the beginning of a transaction.

Example 22-5. Implementing transactional behavior where a transfer occurs between two bank accounts within an example application
import com.oreilly.aspectjcookbook.Account; import com.oreilly.aspectjcookbook.InsufficientFundsException; public aspect TransferTransactionAspect extends TransactionAspect  {    protected pointcut transactionalCall( ) :        call(public void com.oreilly.aspectjcookbook.Bank.transfer(..));        private class TransferTransaction extends ThreadLocal implements     Transaction    {       private Account from;       private Account to;       private float value;              public TransferTransaction(Account from, Account to, float value)       {          this.from = from;          this.to = to;          this.value = value;       }              public void commit( )       {          System.out.println("Committing");          // Nothing to actually commit here, all the changes           // have been accepted ok       }              public void rollback( )       {          System.out.println("Rolling back");          try          {             to.debit(value);          }          catch(InsufficientFundsException ife)          {             System.err.println("Could not complete rollback!");             ife.printStackTrace( );          }       }    }        protected void setupTransaction(Object[] args)    {       this.transaction =           new TransferTransaction(                (Account) args[0],                 (Account) args[1],                 ((Float)args[2]).floatValue( ));    } }

See Also

This example was adapted from the presentation given by Ron Bodkin, New Aspects of Security, available at http://newaspects.com/presentations/; Java Enterprise in a Nutshell by William Crawford, Jim Farley and David Flanagan (O'Reilly) covers transactions in the enterprise Java application; the call(Signature) pointcut is covered in Recipe Recipe 4.1; the cflowbelow(Pointcut) pointcut is described in Recipe 10.2; the before( ) form of advice is covered in Recipe 13.3; the after( ) returning form of advice is covered in Recipe 13.6; the after( ) throwing form of advice is covered in Recipe 13.7; defining abstract aspects and pointcuts is explained in Recipe 15.4; the Director aspect-oriented design pattern is discussed in Recipe 23.3.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net