3 Replies Latest reply on Mar 1, 2006 8:01 AM by greyfairer

    'Invalid transaction state' in HttpSessionListener with dist

      Hi all,

      We are developing a web application that needs to track when a user logs out, or when it's session times out, so we wrote an HttpSessionListener that uses Hibernate to update a login record when the authentication attribute is removed from the HttpSession. This works in a non-clustered environment.

      Then we wanted to make this work in a load-balancing/failover cluster., so we marked the web.xml distributable, and configured the JBoss cluster. The session failover works fine, e.g. when we shut down one cluster, the user's session was still active at the second cluster.

      The HttpSessionListener didn't work anymore with 'distributable', even if there was only one cluster node active: it gets an 'invalid transaction state' when trying to get a JDBC connection from the local firebird DataSource. Stack trace follows below.

      I crossposted this to the firebird people, too (http://groups.yahoo.com/group/Firebird-Java/message/8353). Error 25S01 seems to mean 'invalid transaction state'.

      What does the ClusteredSession expiration have to do with my transactions? The cluster is still up and running, only one user's session is expiring...

      Used versions: JBoss 4.0.3sp1, hibernate 3.0.5, spring 1.2.6, firebirdsql.rar 1.5.5.

      2006-02-22 17:08:50,640 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[www.acme.com].[/server]] standardSession.attributeEvent
      org.springframework.transaction.CannotCreateTransactionException:Could not open Hibernate Session for transaction; nested exception is
      org.hibernate.TransactionException: JDBC begin failed:
      org.hibernate.TransactionException: JDBC begin failed:
       at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:58)
       at org.hibernate.transaction.JDBCTransactionFactory.beginTransaction(JDBCTransactionFactory.java:24)
       at org.hibernate.jdbc.JDBCContext.beginTransaction(JDBCContext.java:271)
       at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1079)
       at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:520)
       at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:282)
       at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:111)
       at com.acme.utils.AbstractHibernateTransactionRunnable.run(AbstractHibernateTransactionRunnable.java:53)
       at com.acme.webctrl.AcegiApplicationListener.timeoutEvent(AcegiApplicationListener.java:44)
       at com.acme.webctrl.J2EEWebAppListener.attributeRemoved(J2EEWebAppListener.java:59)
       at org.jboss.web.tomcat.tc5.session.ClusteredSession.removeAttributeInternal(ClusteredSession.java:558)
       at org.jboss.web.tomcat.tc5.session.ClusteredSession.expire(ClusteredSession.java:418)
       at org.jboss.web.tomcat.tc5.session.ClusteredSession.expire(ClusteredSession.java:345)
       at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:567)
       at org.jboss.web.tomcat.tc5.session.JBossCacheManager.processExpires(JBossCacheManager.java:683)
       at org.jboss.web.tomcat.tc5.session.JBossManager.backgroundProcess(JBossManager.java:662)
       at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1283)
       at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1568)
       at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1577)
       at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1577)
       at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1557)
       at java.lang.Thread.run(Thread.java:595)
      Caused by: org.firebirdsql.jdbc.FBSQLException: Resource Exception. No
      local transaction active: can't commit, error code: 25S01
       at org.firebirdsql.jdbc.AbstractConnection.setAutoCommit(AbstractConnection.java:328)
       at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:53)


        • 1. Re: 'Invalid transaction state' in HttpSessionListener with
          brian.stansberry

          The session expiration process is running inside a JTA transaction (beginning and ending in the org.jboss.web.tomcat.tc5.session.JBossCacheManager.processExpires() method in your stack trace).

          When the call hits your listener the transaction should be STATUS_ACTIVE.

          • 2. Re: 'Invalid transaction state' in HttpSessionListener with

            I was using a spring configured HibernateTransactionManager (using JDBCTransaction) instead of JtaTransactionManager. This worked on everything else.

            <bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
             <property name="jndiName" value="java:/DefaultDS" />
             </bean>
            
             <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
             <property name="dataSource">
             <ref bean="dataSource" />
             </property>
             [...]
             </bean>
             <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
             <property name="sessionFactory"ref="sessionFactory"/>
             </bean>

            I'll try switching to JBoss's UserTransaction
            <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
             <property name="userTransactionName" value="UserTransaction"/>
             </bean>


            • 3. Re: 'Invalid transaction state' in HttpSessionListener with

              It took a little more work than that, the working solution involved the next spring config:

              <bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
               <property name="jndiName" value="java:/DefaultDS" />
              </bean>
              <bean name="jtaTransactionManager" class="org.springframework.jndi.JndiObjectFactoryBean">
               <property name="jndiName" value="$java:/TransactionManager" />
              </bean>
              <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
               <property name="transactionManager" ref="jtaTransactionManager"/>
              </bean>
              
              <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
               <property name="dataSource" ref="dataSource" />
               <property name="jtaTransactionManager" ref="jtaTransactionManager"/>
               [...]
              </bean>
              <bean id="abstractTransactionProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
               <property name="transactionManager" ref="transactionManager"/>
              </bean>
              

              In hibernate.properties I had to add:
              hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory
              hibernate.transaction.manager_lookup_class org.hibernate.transaction.JBossTransactionManagerLookup
              

              I'm a little worried that I had to configure hibernate's transactionManager twice, once in hibernate.properties, and once in the sessionFactory's jtaTransactionManager property, and also for spring's PlatformTransactionManager.

              Anyway, thanks for the hint.
              Greets, Geert.