1 2 Previous Next 17 Replies Latest reply on Apr 20, 2012 5:35 AM by gigazhang

    Drools, Spring integration and JTA in container

    bodi bajk Newbie

      Hey,

       

      I'm trying to setup JTA in Drools - Spring: META-INF/persistence.xml(JTA, jta-data-source) and Spring descriptor.

       

      some examples:

      http://erich.soomsam.net/2007/04/24/spring-jpa-and-jta-with-hibernate-and-jotm/

      http://www.mail-archive.com/rules-users@lists.jboss.org/msg17133.html 

       

      Unfortunately org.drools.persistence.session.SingleSessionCommandService class dosn't work with  JTA (org.springframework.transaction.jta.JtaTransactionManager)

       

      In the second case, when I using RESOURCE_LOCAL persistence unit, it works.

       

      Is it possible setup drools configuraion with JTA?

        • 1. Drools, Spring integration and JTA in container
          Mauricio Salatino Master

          It should work, because it works with JTA Bitronix, can you create an isolated test case using spring JTA, I will be glad to see the error and fixit in the repository.

          • 2. Re: Drools, Spring integration and JTA in container
            bodi bajk Newbie

            Maybe the problem is in my configuration:

             

             

            .....

             

            <drools:ksession id="jpaSingleSessionCommandService" type="stateful" kbase="knowledgeBase">

                                <drools:configuration>

                                          <drools:work-item-handlers>

                                                    <!-- ....  -->

                                          </drools:work-item-handlers>

                                          <drools:jpa-persistence>

                                                    <drools:transaction-manager ref="transactionManager"/>

                                                    <drools:entity-manager-factory ref="entityManagerFactory"/>

                                          </drools:jpa-persistence>

                                </drools:configuration>

                      </drools:ksession>

             

              .....

             

            <jee:jndi-lookup id="entityManagerFactory" jndi-name="java:/org.drools.persistence.jpa.local"/>

             

            <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">

                    <property name="transactionManagerName" value="java:/TransactionManager"/>

                    <property name="userTransactionName" value="UserTransaction"/>

            </bean>

            .....

             

             

             

            During deployment, application throws NullpointerException in class: SingleSessionCommandService

             

             

            because when invoked initTransactionManager(Environment env) method:

             

             

            Object tm = env.get( EnvironmentName.TRANSACTION_MANAGER );

            ....

            if ( tm.getClass().getName().toLowerCase().contains( "jpa" ) ) {

                                // configure spring for JPA and local transactions

                                cls = Class.forName( "org.drools.container.spring.beans.persistence.DroolsSpringJpaManager" );

                                con = cls.getConstructors()[0];

                                this.jpm =  ( JpaManager) con.newInstance( new Object[] { this.env } );

                            } else {

                                // configure spring for JPA and distributed transactions 

             

                            }

             

             

            jpm is null,

            because  tm.getClass().getName().toLowerCase().contains( "jpa" )  is not true, in my case (org.springframework.transaction.jta.JtaTransactionManager)

            • 4. Re: Drools, Spring integration and JTA in container
              bodi bajk Newbie

              Yes, because env.get( EnvironmentName.TRANSACTION_MANAGER ) return instance of JtaTransactionManager

              • 5. Re: Drools, Spring integration and JTA in container
                Mauricio Salatino Master

                Can you isolate a failing test? I will take a look at the problem if you want.

                Greetings.

                • 7. Re: Drools, Spring integration and JTA in container
                  Mauricio Salatino Master

                  Perfect let me have a look on that..

                  Greetings

                  • 8. Drools, Spring integration and JTA in container
                    bodi bajk Newbie

                    I think it works with JTA Bitronix, but without Spring.

                    • 9. Re: Drools, Spring integration and JTA in container
                      Perit Bezek Newbie

                      I have same problem. As  "bodi bajk" correctly addressed, my problem is also about the line tm.getClass().getName().toLowerCase().contains( "jpa" ) Is there any recent development/fix on this subject?

                      • 10. Re: Drools, Spring integration and JTA in container
                        Alex Manly Newbie

                        I have this same problem.

                         

                        In the spring config I create the Transaction manager as follows:

                         

                         

                        {code:xml}

                            <jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/rd-domain-pu" />

                         

                            <tx:jta-transaction-manager />

                        {code:xml}

                         

                        This creates a transaction manager with the type:

                         

                        org.springframework.transaction.jta.JtaTransactionManager

                         

                        My drools spring config is this:

                         

                        {code:xml}   

                        <drools:kbase id="kbase1">

                                <drools:resources>

                                    <drools:resource id="cloneFlow" type="DRF" source="classpath:Clone.rf"/>

                                    <drools:resource id="approvalFlow" type="DRF" source="classpath:Approval.rf"/>

                                  </drools:resources>

                         

                                <drools:configuration>

                                    <drools:mbeans enabled="true" />

                                    <drools:event-processing-mode mode="STREAM" />

                                </drools:configuration>

                            </drools:kbase>

                         

                            <drools:ksession id="jpaSingleSessionCommandService" type="stateful" kbase="kbase1" name="stateful-session">

                                <drools:configuration>           

                                    <drools:jpa-persistence>

                                        <drools:transaction-manager ref="transactionManager" />

                                        <drools:entity-manager-factory ref="entityManagerFactory" />

                                        <drools:variable-persisters>

                                            <drools:persister for-class="javax.persistence.Entity" implementation="org.drools.persistence.processinstance.persisters.JPAVariablePersister"/>

                                            <drools:persister for-class="java.io.Serializable" implementation="org.drools.persistence.processinstance.persisters.SerializableVariablePersister"/>

                                        </drools:variable-persisters>

                                    </drools:jpa-persistence>

                                    <drools:work-item-handlers>

                                        <drools:work-item-handler name="Human Task" ref="humanTaskHandler"/>

                                    </drools:work-item-handlers>

                                    <drools:keep-reference enabled="true" />

                                    <drools:clock-type type="REALTIME" />

                                </drools:configuration>

                                <drools:script>

                                    <drools:start-process process-id="1"/>

                                    <drools:fire-all-rules/>

                                </drools:script>

                            </drools:ksession>

                        {code:xml}

                         

                        No when the spring context is loaded I get the same error and the problem is the initTransactionManager method in SingleSessionComand:

                         

                        The problem is the class does start with "org.springframework" (in the first if statement.  But the class does not contain "jpa" in the second if statement.  Which means the line comment: //configure spring for JPA and distributed transactions

                         

                        {code}

                        public void initTransactionManager(Environment env) {

                                Object tm = env.get( EnvironmentName.TRANSACTION_MANAGER );

                                if ( tm != null && tm.getClass().getName().startsWith( "org.springframework" ) ) {

                                    try {

                                        Class<?> cls = Class.forName( "org.drools.container.spring.beans.persistence.DroolsSpringTransactionManager" );

                                        Constructor<?> con = cls.getConstructors()[0];

                                        this.txm = (TransactionManager) con.newInstance( tm );

                                        logger.debug( "Instantiating  DroolsSpringTransactionManager" );

                         

                                        if ( tm.getClass().getName().toLowerCase().contains( "jpa" ) ) {

                                            // configure spring for JPA and local transactions

                                            cls = Class.forName( "org.drools.container.spring.beans.persistence.DroolsSpringJpaManager" );

                                            con = cls.getConstructors()[0];

                                            this.jpm =  ( JpaManager) con.newInstance( new Object[] { this.env } );

                                        } else {

                                            // configure spring for JPA and distributed transactions

                                        }

                                    } catch ( Exception e ) {

                                        logger.warn( "Could not instatiate DroolsSpringTransactionManager" );

                                        throw new RuntimeException( "Could not instatiate org.drools.container.spring.beans.persistence.DroolsSpringTransactionManager", e );

                                    }

                                } else {

                                    logger.debug( "Instantiating  JtaTransactionManager" );

                                    this.txm = new JtaTransactionManager( env.get( EnvironmentName.TRANSACTION ),

                                                                          env.get( EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY ),

                                                                          tm );

                                    this.jpm = new DefaultJpaManager(this.env);

                                }

                            }

                        {code}

                         

                        Does anyone from Drools development know when the code will support a  "org.springframework.transaction.jta.JtaTransactionManager" class?

                         

                        Thanks in advance

                        • 11. Re: Drools, Spring integration and JTA in container
                          Fabio Wang Newbie

                          Hi there,

                           

                          After some time struggling to make this "Spring + JTA + Drools" integration, I could make it work, but I'm still unsure if it's the right way. As everyone pointed out, the SingleSessionComand#initTransactionManager ignores the case where a org.springframework.transaction.jta.JtaTransactionManager is used. So I had to manually create an Environment like this:

                           

                          Environment environment = EnvironmentFactory.newEnvironment();

                          environment.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);

                          DroolsSpringTransactionManager jtaTransactionManager = new DroolsSpringTransactionManager(ptm);

                          this.environment.set(EnvironmentName.TRANSACTION_MANAGER, jtaTransactionManager);

                          DroolsSpringJpaManager pcm = new DroolsSpringJpaManager(environment);

                          environment.set(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER, pcm);

                           

                          And, after that, I create my ksession (unfortunately, without the <drools:ksession/> shortcut):

                           

                          ksession = JPAKnowledgeService.newStatefulKnowledgeSession(this.kbase, null, environment);

                           

                          Hope this helps.

                          Fábio

                          • 12. Re: Drools, Spring integration and JTA in container
                            Alex Manly Newbie

                            Hi Fabio

                             

                            Thanks for taking the time to respond.

                             

                            Can you please tell me what the object type is for your attribute: "ptm".

                             

                            I assume it is this object type:

                             

                            {code}

                            org.springframework.transaction.jta.JtaTransactionManager

                            {code}

                             

                             

                            Also, I am using Drools version 5.1 and the Class EnvironmentName does not have a static field named:

                             

                            {code}

                            EnvironmentName.PERSISTENCE_CONTEXT_MANAGER

                            {code}

                             

                            What should I use instead of that field?

                             

                            Kind regards

                            Alex

                            • 13. Re: Drools, Spring integration and JTA in container
                              Fabio Wang Newbie

                              Hi,

                               

                              I've just noticed that the code of initTransactionManager you sent was a bit different from the one I was analyzing. I'm using Drools version 5.2.0.M1.

                               

                              In fact, there doesn't seem to be a way to pass a PersistenceContextManager through the environment in version 5.1.x. So I think the easiest way to make it work would be to subclass the SingleSessionCommandService, override the initTransactionManager, where you would lookup the transactionManager in the environment using any key you like), and then manually instantiate a CommandBasedStatefulKnowledgeSession.

                               

                              I just came up with this idea, so I don't know if it works at all.

                               

                              (By the way, ptm is supposed to be the spring PlatformTransactionManager, so yes, it could be a JtaTransactionManager).

                               

                              What a mess, huh?

                              • 14. Re: Drools, Spring integration and JTA in container
                                Alex Manly Newbie

                                Hi,

                                 

                                I have managed to get the spring context to load by overriding the SingleSessionCommandService as you mentioned.  Here is my code:

                                 

                                 

                                {code}

                                   public void initTransactionManager(Environment env) {

                                        Object tm = env.get( EnvironmentName.TRANSACTION_MANAGER );

                                        if ( tm != null && tm.getClass().getName().equals( "org.springframework.transaction.jta.JtaTransactionManager" ) ) {

                                            logger.debug( "Instantiating Spring JtaTransactionManager" );

                                            this.txm = new JtaTransactionManager(((org.springframework.transaction.jta.JtaTransactionManager)tm).getUserTransaction(),

                                                                                  env.get( EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY ),

                                                                                  ((org.springframework.transaction.jta.JtaTransactionManager)tm).getTransactionManager() );

                                            this.jpm = new DefaultJpaManager(this.env);

                                        } else {

                                          // continue as normal

                                        }

                                {code}

                                 

                                 

                                I agree.....very messy.  Thanks for your help.

                                1 2 Previous Next