JtaTransactionManager should use setRollbackOnly instead of rollback for non-local
transactions
-----------------------------------------------------------------------------------------------
Key: JBRULES-2937
URL:
https://issues.jboss.org/browse/JBRULES-2937
Project: Drools
Issue Type: Bug
Security Level: Public (Everyone can see)
Affects Versions: 5.2.0.M1
Environment: WinXP, Oracle Java 1.6.0_20, 32bit, JBoss AS 6.0.0.Final, jBPM
5.0.0
Reporter: Vlastimil Menčík
Assignee: Mark Proctor
This problem concerns the {{drools-persistence-jpa}} module and its
{{org.drools.persistence.jta.JtaTransactionManager}}.
The {{JtaTransactionManager}} has a notion of local transactions. These are the JTA
transactions that it itself started using
[
UserTransaction.begin()|http://download.oracle.com/javaee/6/api/javax/tra...].
If a JTA transaction is already active when {{JtaTransactionManager.begin()}} is called,
then the execution continues in this JTA transaction and a new one is not started.
Let's call such JTA transaction non-local.
The problem is that {{JtaTransactionManager.rollback()}} treats local and non-local JTA
transactions the same way and calls
[
UserTransaction.rollback()|http://download.oracle.com/javaee/6/api/javax/...]
in both cases. In case of a non-local transaction is this behaviour IMHO wrong, because
the rollback should be a responsibility of the same client that started the JTA
transaction.
Imagine the following situation (jBPM process execution):
{code}
StatefulKnowledgeSession session = ...
UserTransaction ut = ...
ut.begin();
try {
session.startProcess("my.process"); // the process execution may cause an
exception (most likely in some WorkItemHandler)
ut.commit();
} catch (Exception e) {
ut.rollback(); // now this throws an IllegalStateException, because
JtaTransactionManager already rolled back the transaction
}
{code}
There is of course a workaround: the client code has to check
[
status|http://download.oracle.com/javaee/6/api/javax/transaction/UserTran...]
of the JTA transaction and must not call {{rollback()}}, if the transaction was already
rolled back by the {{JtaTransactionManager}}.
IMHO the relevant JtaTransactionManager code should call
[
UserTransaction.setRollbackOnly|http://download.oracle.com/javaee/6/api/j...]
for non-local transactions:
{code}
public void rollback() {
boolean wasLocal = localTransaction; // localTransaction is a private boolean field of
JtaTransactionManager already present in current implementation
localTransaction = false;
try {
wasLocal ? this.ut.rollback() : this.ut.setRollbackOnly();
} catch ( Exception e ) {
logger.warn( "Unable to rollback transaction", e);
throw new RuntimeException( "Unable to rollback transaction", e );
}
}
{code}
--
This message is automatically generated by JIRA.
For more information on JIRA, see:
http://www.atlassian.com/software/jira