Ajax component events may be wrapped in a transaction as I pointed out in “Transaction Handling for Ajax Components in Tapestry-5.x“. But on some occasions an Ajax component event is surrounded by a component event. So the code in the ControllerUtil
of article “Transaction Handling in Tapestry5” will lead to ‘transaction already active’ problems, since we try to begin a transaction in the nested ajax component event although there is already an active transaction attached to the current thread. We can overcome this situation by checking, whether an active transaction is present and begin/commit/rollback a new transaction iff not. This behavior is similar to the default transaction attribute REQUIRED
in Java EE.
Here is the new code in ControllerUtil
:
public static UserTransaction beginTransaction() throws SystemException, NamingException, javax.transaction.NotSupportedException { UserTransaction tx = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction"); // Start a transaction only if it is not already active. if(tx.getStatus() != Status.STATUS_ACTIVE) { tx.begin(); return tx; } return null; } public static void commitTransaction(UserTransaction tx) throws IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException, SystemException, javax.transaction.RollbackException { if (tx != null) { tx.commit(); } } public static void rollbackTransaction(UserTransaction tx) throws IllegalStateException, SystemException { if (tx != null) { tx.rollback(); } }