Applying Transactions to the Ticket Broker Application
Now, write an aspect to wrap calls to transactional methods with transaction management calls:
import org.codehaus.aspectwerkz.joinpoint.JoinPoint;
import com.devx.ticketbroker.dao.HibernateUtil;
public class TransactionAspect
{
public Object aroundTransactionalAdvice(JoinPoint joinPoint)
throws Throwable
{
Object result;
System.out.println(
"AspectWerkz aspect beginning transaction");
HibernateUtil.beginTransaction();
try
{
result = joinPoint.proceed();
System.out.println(
"AspectWerkz aspect Committing transaction");
HibernateUtil.commitTransaction();
}
catch (Throwable e)
{
System.out.println(
"AspectWerkz aspect rolling back transaction");
HibernateUtil.rollbackTransaction();
throw e;
}
return result;
}
}
This aspect simply uses a helper object to invoke functionality in Hibernate to begin, commit, and roll back transactions. It defines the behavior to be executed around calls to transactional methods. Next, write a pointcut to specify which methods need to be wrapped with this advice.
<aspectwerkz>
<system id="AspectWerkzExample">
<package name="com.devx.ticketbroker.aspect">
<aspect class="TransactionAspect">
<pointcut name="transactionalMethods"
expression="execution(@transaction *
*..*.*(..))" />
<advice name="aroundTransactionalAdvice" type="around"
bind-to="transactionalMethods" />
</aspect>
</package>
</system>
</aspectwerkz>
As shown above, the
transactionalMethods pointcut selects all executions of methods marked with the
@transaction attribute. It's bound to the TransactionAspect class as "around" advice, meaning that the TransactionAspect will intercept execution of all methods marked for transaction support, and will surround those method calls with the appropriate transaction logic.
Lastly, you must invoke the AspectWerkzC as part of your build process to weave the transaction aspect into your application:
...
<target name="aspectwerkzc" depends="compile, annotationc">
<aspectwerkzc verbose="false"
definition=
"${project.build.outputDirectory}/aspectwerkz.xml"
classpathref="dependency.classpath">
<target path="${project.build.outputDirectory}" />
</aspectwerkzc>
</target>
...
A re-run of the Ant test now succeeds, because all calls to
purchaseTicket are now transactional:
test:
[junit] Running
com.devx.ticketbroker.dao.impl.CustomerAccountDAOTest
[junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.687 sec
[junit] Running com.devx.ticketbroker.dao.impl.EventDAOTest
[junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.625 sec
[junit] Running com.devx.ticketbroker.service.impl.TicketServiceTest
[junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.625 sec
BUILD SUCCESSFUL
As this article shows, combining annotations with aspects is indeed possible in a pre-Java 5 world, and the combination can be a very powerful tool for managing cross-cutting concerns in your application.