<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<body link="#355491" alink="#4262a1" vlink="#355491" style="background: #e2e2e2; margin: 0; padding: 20px;">

<div>
        <table cellpadding="0" bgcolor="#FFFFFF" border="0" cellspacing="0" style="border: 1px solid #dadada; margin-bottom: 30px; width: 100%; -moz-border-radius: 6px; -webkit-border-radius: 6px;">
                <tbody>
                        <tr>

                                <td>

                                        <table border="0" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF" style="border: solid 2px #ccc; background: #dadada; width: 100%; -moz-border-radius: 6px; -webkit-border-radius: 6px;">
                                                <tbody>
                                                        <tr>
                                                                <td bgcolor="#000000" valign="middle" height="58px" style="border-bottom: 1px solid #ccc; padding: 20px; -moz-border-radius-topleft: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 5px; -webkit-border-top-left-radius: 5px;">
                                                                        <h1 style="color: #333333; font: bold 22px Arial, Helvetica, sans-serif; margin: 0; display: block !important;">
                                                                        <!-- To have a header image/logo replace the name below with your img tag -->
                                                                        <!-- Email clients will render the images when the message is read so any image -->
                                                                        <!-- must be made available on a public server, so that all recipients can load the image. -->
                                                                        <a href="https://community.jboss.org/index.jspa" style="text-decoration: none; color: #E1E1E1">JBoss Community</a></h1>
                                                                </td>

                                                        </tr>
                                                        <tr>
                                                                <td bgcolor="#FFFFFF" style="font: normal 12px Arial, Helvetica, sans-serif; color:#333333; padding: 20px;  -moz-border-radius-bottomleft: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px;"><h3 style="margin: 10px 0 5px; font-size: 17px; font-weight: normal;">
    Drools Spring Integration, errors in DroolsSpringTransactionManager
</h3>
<span style="margin-bottom: 10px;">
    created by <a href="https://community.jboss.org/people/jbize">John Bize</a> in <i>jBPM</i> - <a href="https://community.jboss.org/message/751900#751900">View the full discussion</a>
</span>
<hr style="margin: 20px 0; border: none; background-color: #dadada; height: 1px;">

<div class="jive-rendered-content"><p>I have an application that integrates jBPM, Spring, Hibernate/JPA, JPA2, and Richfaces4.&#160; It's mostly working ok, except sometimes I am/was getting NullPointer exceptions from the DroolsSpringTransactionManager.&#160; I'm using drools-spring 5.3.1.Final.&#160; This class is apparently a (broken?) wrapper class around (in my case), the org.springframework.orm.jpa.JpaTransactionManager.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>Looking at the source code, I observed several things. There is an obvious bug in the begin() method in that if the call to getStatus() returns STATUS_NO_TRANSACTION, which it will if the wrapped tm (ptm) is null, it immediately dereferences the null ptm. (this.ptm.getTransaction(td)).&#160; I'm not too woried about this one as it seems rather unlikely.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p>What's happening for me (in the getStatus() method) is that it's making the call "transaction = this.ptm.getTransaction(td);" which is occasionally throwing an "IllegalStateException: Transaction already active," wrapped in an outer RuntimeException and dropping down to the finally block.&#160; There, the still null transaction is committed, throwing an NPE that masks the original exception.&#160; To mitigate this, I added a catch RuntimeException and if the cause is an IllegalStateException, I return STATUS_UNKNOWN.&#160; In the finally block, I also ensure that I don't try to commit a null transaction.</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><span>Clearly this code is fragile, and </span><a class="jive-link-external-small" href="https://issues.jboss.org/browse/JBRULES-2791" target="_blank">https://issues.jboss.org/browse/JBRULES-2791</a><span> is probably correct, but </span><strong>can anyone suggest why I'm sometimes getting the "IllegalStateException: Transaction already active" exceptions in the first place.&#160; I am using 4 separate persistence units (and transaction managers), two for basic components of my application, one for the jBPM process tables, and one for the LocalTaskManager Task tables.</strong></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p><span>Copying the code from: </span><a class="jive-link-external-small" href="https://github.com/droolsjbpm/droolsjbpm-integration/blob/master/drools-container/drools-spring/src/main/java/org/drools/container/spring/beans/persistence/DroolsSpringTransactionManager.java" target="_blank">https://github.com/droolsjbpm/droolsjbpm-integration/blob/master/drools-container/drools-spring/src/main/java/org/drools/container/spring/beans/persistence/DroolsSpringTransactionManager.java</a><span>, my mitigating changes are in red (typed, not copied):</span></p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p><pre class="jive-pre"><code class="jive-code">
public class DroolsSpringTransactionManager
&#160;&#160;&#160; implements
&#160;&#160;&#160; TransactionManager {

&#160;&#160;&#160; Logger&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = LoggerFactory.getLogger( getClass() );
&#160;&#160;&#160; private AbstractPlatformTransactionManager ptm;

&#160;&#160;&#160; TransactionDefinition&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; td&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = new DefaultTransactionDefinition();
&#160;&#160;&#160; TransactionStatus&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; currentTransaction = null;

&#160;&#160;&#160; public DroolsSpringTransactionManager(AbstractPlatformTransactionManager ptm) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.ptm = ptm;
&#160;&#160;&#160; }

&#160;&#160;&#160; public boolean begin() {
&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( getStatus() == TransactionManager.STATUS_NO_TRANSACTION ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // If there is no transaction then start one, we will commit within the same Command
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // it seems in spring calling getTransaction is enough to begin a new transaction
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; currentTransaction = this.ptm.getTransaction( td );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return true;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return false;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch ( Exception e ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger.warn( "Unable to begin transaction",
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException( "Unable to begin transaction",
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160; }

&#160;&#160;&#160; public void commit(boolean transactionOwner) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( transactionOwner ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // if we didn't begin this transaction, then do nothing
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.ptm.commit( currentTransaction );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; currentTransaction = null;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch ( Exception e ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger.warn( "Unable to commit transaction",
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException( "Unable to commit transaction",
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160; }

&#160;&#160;&#160; public void rollback(boolean transactionOwner) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( transactionOwner ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.ptm.rollback( currentTransaction );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; currentTransaction = null;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch ( Exception e ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger.warn( "Unable to rollback transaction",
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException( "Unable to rollback transaction",
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160; }

&#160;&#160;&#160; /**
&#160;&#160;&#160;&#160; * Borrowed from Seam
&#160;&#160;&#160;&#160; */
&#160;&#160;&#160; public int getStatus() {
&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( ptm == null ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return TransactionManager.STATUS_NO_TRANSACTION;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger.debug( "Current TX name (According to TransactionSynchronizationManager) : " + TransactionSynchronizationManager.getCurrentTransactionName() );
&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( TransactionSynchronizationManager.isActualTransactionActive() ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; TransactionStatus transaction = null;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( currentTransaction == null ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; transaction = ptm.getTransaction( td );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( transaction.isNewTransaction() ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return TransactionManager.STATUS_COMMITTED;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; transaction = currentTransaction;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger.debug( "Current TX: " + transaction );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // If SynchronizationManager thinks it has an active transaction but
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // our transaction is a new one
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // then we must be in the middle of committing
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( transaction.isCompleted() ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( transaction.isRollbackOnly() ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return TransactionManager.STATUS_ROLLEDBACK;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return TransactionManager.STATUS_COMMITTED;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // Using the commented-out code in means that if rollback with this manager,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; //&#160; I always have to catch and check the exception 
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; //&#160; because ROLLEDBACK can mean both "rolled back" and "rollback only".
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // if ( transaction.isRollbackOnly() ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; //&#160;&#160;&#160;&#160; return TransactionManager.STATUS_ROLLEDBACK;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // }
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return TransactionManager.STATUS_ACTIVE;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
{color:#f00}
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (RuntimeException e) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( e.getCause() instanceof IllegalStateException ) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger.debug( "IllegalStateException in getStatus()", e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return TransactionManager.STATUS_UNKNOWN;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; logger.debug( "Unexpected Exception in getStatus()", e );
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw e;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
{color}
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } finally {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ( currentTransaction == null ) {
{color:#f00}
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (transaction != null) {
{color}
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ptm.commit( transaction );
{color:#f00}
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
{color}
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
&#160;&#160;&#160;&#160;&#160;&#160;&#160; return TransactionManager.STATUS_NO_TRANSACTION;
&#160;&#160;&#160; }

&#160;&#160;&#160; public void registerTransactionSynchronization(TransactionSynchronization ts) {
&#160;&#160;&#160;&#160;&#160;&#160;&#160; TransactionSynchronizationManager.registerSynchronization( new SpringTransactionSynchronizationAdapter( ts ) );
&#160;&#160;&#160; }
}
</code></pre><p style="min-height: 8pt; height: 8pt; padding: 0px;">&#160;</p></div>

<div style="background-color: #f4f4f4; padding: 10px; margin-top: 20px;">
    <p style="margin: 0;">Reply to this message by <a href="https://community.jboss.org/message/751900#751900">going to Community</a></p>
        <p style="margin: 0;">Start a new discussion in jBPM at <a href="https://community.jboss.org/choose-container!input.jspa?contentType=1&containerType=14&container=2034">Community</a></p>
</div></td>
                        </tr>
                    </tbody>
                </table>


                </td>
            </tr>
        </tbody>
    </table>

</div>

</body>
</html>