[rules-users] IllegalStateException when disposing of a persisted session

Thomas Grayson tgrayson at bluemetal.com
Wed Jun 12 15:42:12 EDT 2013


We are using Drools persistence with a StatefulKnowledgeSession.  The persistence itself works fine, but I am encountering an IllegalStateException when disposing of the StatefulKnowledgeSession.  This happens with either a brand new session with no facts or one that has had facts added to it.  It also happens with sessions that have been restored from the persistent store.  The code does no explicit transaction management and relies on Drools to do this under the covers.  We are using Drools 5.5.0 Final.  How do I dispose of a session correctly?

The documentation<http://docs.jboss.org/drools/release/5.5.0.Final/drools-expert-docs/html/ch03.html#d0e3961> includes Example 3.66, "Configuring JTA DataSource."  My code does not include code like this anywhere.  Do I need it?  It's not clear from the example where the PoolingDataSource instance would be used or when this code should be called.  If this configuration is required, can it be done via Spring instead of programmatically?

I'll provide some supporting information below.  I've edited these excerpts to redact some private details and eliminate distracting code, but the substance is intact.

Here is the stack trace created by invoking the "dispose" method from a shutdown hook:

java.lang.IllegalStateException: No value for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean at 732e3e73] bound to thread [Thread-3]
       at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:209)
       at org.drools.container.spring.beans.persistence.DroolsSpringJpaManager.dispose(DroolsSpringJpaManager.java:135)
       at org.drools.persistence.SingleSessionCommandService.execute(SingleSessionCommandService.java:345)
       at org.drools.command.impl.CommandBasedStatefulKnowledgeSession.dispose(CommandBasedStatefulKnowledgeSession.java:241)
       at MyClass1.stop
       at MyClass2$1.run
       at java.lang.Thread.run(Unknown Source)

The code uses Drools-Spring to configure the knowledge base and Java code to initialize the knowledge session.  We're using JPA, the Bitronix transaction manager, and the H2 database, basically as described in the documentation<http://docs.jboss.org/drools/release/5.5.0.Final/droolsjbpm-introduction-docs/html/releaseNotes.html#d0e2827>.  Here is the code for creating the session:

        ApplicationContext context = new ClassPathXmlApplicationContext(APPLICATION_CONTEXT_XML);
        KnowledgeStoreService kstore = (KnowledgeStoreService) context.getBean("myAppKnowledgeStore");
        KnowledgeBase kbase = ...; // initialized by Spring configuration
        Environment env = KnowledgeBaseFactory.newEnvironment();
        env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, context.getBean("entityManagerFactory"));
        env.set(EnvironmentName.TRANSACTION_MANAGER, context.getBean("txManager"));
        StatefulKnowledgeSession ksession = kstore.newStatefulKnowledgeSession(kbase, null, env);

Here is the relevant portion of the Spring ApplicationContext.xml file:

       <bean id="dataSourceH2"
              class="org.springframework.jdbc.datasource.DriverManagerDataSource">
              <property name="driverClassName" value="org.h2.Driver" />
              <property name="url" value="jdbc:h2:tcp://localhost/~/myApp" />
              <property name="username" value="sa" />
              <property name="password" value="" />
       </bean>

       <bean id="entityManagerFactory"
              class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
              <property name="dataSource" ref="dataSourceH2" />
              <property name="persistenceUnitName" value="myAppH2" />
       </bean>

       <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
              <property name="entityManagerFactory" ref="entityManagerFactory" />
       </bean>

       <drools:grid-node id="myAppEngineNode" />
       <drools:kstore id="myAppKnowledgeStore" />

       <drools:kbase id="myAppEngineKBase" node="MyAppEngineNode">
              <drools:configuration>
                     <drools:assert-behavior mode="EQUALITY" />
              </drools:configuration>
              <drools:resources>
                     <drools:resource type="DRL" source="classpath:MyAppInternalRules.drl" />
                     <drools:resource type="DTABLE" source="classpath:MyAppRules.xls" >
                           <drools:decisiontable-conf input-type="XLS" worksheet-name="Sheet 1" />
                     </drools:resource>
                     <drools:resource type="DTABLE" source="classpath:MyAppRules.xls" >
                           <drools:decisiontable-conf input-type="XLS" worksheet-name="Sheet 2" />
                     </drools:resource>
              </drools:resources>
       </drools:kbase>

Here is the relevant part of the persistence.xml file:

       <persistence-unit name="myAppH2">
              <provider>org.hibernate.ejb.HibernatePersistence</provider>
              <class>org.drools.persistence.info.SessionInfo</class>
              <properties>
                     <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
                     <property name="hibernate.max_fetch_depth" value="3" />
                     <property name="hibernate.hbm2ddl.auto" value="UPDATE" />
                     <property name="hibernate.show_sql" value="true" />
                     <property name="hibernate.connection.autocommit" value="true" />
                     <property name="hibernate.transaction.manager_lookup_class" value= "org.hibernate.transaction.BTMTransactionManagerLookup"/>
              </properties>
       </persistence-unit>

I have a jndi.properties that's identical to what's in the documentation<http://docs.jboss.org/drools/release/5.5.0.Final/drools-expert-docs/html/ch03.html#d0e3961>.

I noticed in the documentation (Example 3.65, Configuring JPA) that the persistence-unit block is defined a bit differently.  In particular, transaction-type is specified and a jta-data-source are defined, unlike in my file:

       <persistence-unit name="org.drools.persistence.jpa" transaction-type="JTA">
          <provider>org.hibernate.ejb.HibernatePersistence</provider>
          <jta-data-source>jdbc/BitronixJTADataSource</jta-data-source>
          ...
       </persistence-unit>

I tried defining these as shown, but then the code failed on startup when it tried to create a transaction:

org.drools.container.spring.beans.persistence.DroolsSpringTransactionManager: Unable to begin transaction
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
       at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:427)
       at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
       at org.drools.container.spring.beans.persistence.DroolsSpringTransactionManager.begin(DroolsSpringTransactionManager.java:48)
       at org.drools.persistence.SingleSessionCommandService.<init>(SingleSessionCommandService.java:190)
       at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
       at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
       at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
       at java.lang.reflect.Constructor.newInstance(Unknown Source)
       at org.drools.persistence.jpa.KnowledgeStoreServiceImpl.buildCommandService(KnowledgeStoreServiceImpl.java:100)
       at org.drools.persistence.jpa.KnowledgeStoreServiceImpl.loadStatefulKnowledgeSession(KnowledgeStoreServiceImpl.java:83)
       at MyClass1.initializeKnowledgeSession
       at MyClass1.initializeKnowledgeEngine
       at MyClass2.main
Caused by: java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
       at org.hibernate.ejb.AbstractEntityManagerImpl.getTransaction(AbstractEntityManagerImpl.java:996)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
       at java.lang.reflect.Method.invoke(Unknown Source)
       at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
       at com.sun.proxy.$Proxy16.getTransaction(Unknown Source)
       at org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction(DefaultJpaDialect.java:70)
       at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:377)
       ... 12 more
Thanks,
Tom

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20130612/08b9d785/attachment-0001.html 


More information about the rules-users mailing list