cf 
https://issues.apache.org/jira/browse/GERONIMO-4576 
https://issues.apache.org/jira/browse/OPENEJB-1091 

For a long time we've known of this problem where an exception thrown by a 
transaction synchronization that causes a transaction to be marked for rollback 
only is lost.  When the user or openejb tries to commit the transaction the 
transaction manager throws a RollbackException which currently doesn't have any 
information about the original exception.

People have complained about this for a long time.... now we're trying to fix 
it.

There are two parts AFAICT.  I think in openejb we just need to take the 
TransactionRolledBackException we are currently throwing and call initCause 
with the RollbackException from the tm.  In TransactionPolicy this would be 
something like

        } catch (RollbackException e) {

            txLogger.info("The transaction has been rolled back rather than 
commited: " + e.getMessage());
            // TODO can't set initCause on a TransactionRolledbackException, 
update the convertException and related code to handle something else 
            Throwable txe = new 
javax.transaction.TransactionRolledbackException("Transaction was rolled back, 
presumably because setRollbackOnly was called during a synchronization: 
"+e.getMessage());
--            throw new ApplicationException(txe);
++            throw new ApplicationException(txe.initCause(e);

In the transaction implementation we need to keep track of the exception that 
caused us to mark rollback only and then use it as the cause of the 
RollbackException, e.g.

private Exception markRollbackCause;

...
RollbackException rollbackException = new RollbackException("Unable to commit: 
transaction marked for rollback");
 if (markRollbackCause != null) { 
rollbackException.initCause(markRollbackCause); 
}
 throw rollbackException; 

...

    private void markRollbackCause(Exception e) {
        if (markRollbackCause == null) {
            markRollbackCause = e;
        }
    }

(this tm code is committed in rev 1073479 in my sandbox tm)

At the moment if a sync throws an exception, we keep calling the other syncs, 
and it would be possible for other ways of marking rollback only due to an 
exception to occur more than once as well.  So there's a question as to whether 
we should only record the first cause of rollback only or if we should keep 
track of a list of causes.  The code above only tracks the first  cause.  I'm 
really not sure what to think about this and would appreciate comments.

Thoughts?

thanks
david jencks

p.s. "we" includes Ashish Jain and David Blevins and possibly others.... we 
finally got moving on this due to a customer complaint.  Better late than never 
:-)

Reply via email to