9 Replies Latest reply on Jan 10, 2006 11:42 PM by hoogenbj

    Transaction demarcation with EJB/CMT

    heismann

      Hello,

      I've been unable to successfully configure JBPM/Hibernate to rely upon the EJB container for transaction demarcation.

      My Environment:
      JBoss 4.0.2
      Hibernate 3.0.5
      JBPM 3.0.2
      JDK 1.5 on Solaris

      jbpm.properties

      jbpm.log.package.org.jbpm=info
      jbpm.log.package.org.jbpm.persistence.hibernate=info
      
      jbpm.scheduler.service.factory=org.jbpm.scheduler.impl.SchedulerServiceImpl
      jbpm.task.instance.class=org.jbpm.taskmgmt.exe.TaskInstance
      
      # uncomment the next line if JbpmSessionFactory.getInstance()
      # should lookup the singleton instance from JNDI instead of creating
      # a default one.
      #
      jbpm.session.factory.jndi.name=java:/jbpm/JbpmSessionFactory
      
      jbpm.hibernate.cfg.xml=jbpm.hibernate.cfg.xml
      
      #hibernate.show_sql=true
      #hibernate.query.substitutions=true 1, false 0
      
      


      jbpm.hibernate.cfg.xml
      <!DOCTYPE hibernate-configuration PUBLIC
       "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
       "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
      <hibernate-configuration>
       <session-factory>
       <!-- jdbc connection properties -->
       <property name="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</property>
       <property name="hibernate.connection.datasource">java:/JBPMDS</property>
       <property name="hibernate.connection.provider_class">org.hibernate.connection.DatasourceConnectionProvider</property>
       <property name="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</property>
       <property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
       <property name="hibernate.session_factory_name">java:com/env/hibernate/SessionFactory</property>
       <property name="hibernate.transaction.flush_before_completion">true</property>
       <property name="hibernate.transaction.auto_close_session">true</property>
       <!-- c3p0 connection pooling properties -->
       <property name="hibernate.c3p0.min_size">1</property>
       <property name="hibernate.c3p0.max_size">3</property>
       <!-- other hibernate properties -->
       <property name="hibernate.show_sql">true</property>
      .
      .
      .
       </session-factory>
      </hibernate-configuration>
      
      




        • 1. Re: Transaction demarcation with EJB/CMT
          heismann

          Whoops, meant to hit preview, not submit.

          The following code is being run from a CMT SSBean. I see Hibernate running a bunch of select statements before the save method is called. After the save, however, I don't see any insert or update statements. This makes me feel that I've misconfigured something. I can force persistance to occur by telling the Hibernate session to flush itself (jbpmSession.getSession().flush()).

          Can anyone give me advice on what I might have misconfigured?

           public void testHelloWorldProcessDefinition()
           {
           JbpmSession jbpmSession = null;
           InitialContext initialContext = null;
           Connection con = null;
           try
           {
           initialContext = new InitialContext();
           Object jndiObject = initialContext.lookup(JNDINAME);
           JbpmSessionFactory instance = (JbpmSessionFactory)
           PortableRemoteObject.narrow(jndiObject, JbpmSessionFactory.class);
           jbpmSession = instance.openJbpmSession();
          //
          // Tried this too.
          //
          // SessionFactory sessionFactory = instance.getSessionFactory();
          // Session currentSession = sessionFactory.getCurrentSession();
          // jbpmSession = instance.openJbpmSession(currentSession);
          
           ProcessDefinition processDefinition =
           jbpmSession.getGraphSession().
           findLatestProcessDefinition("hello world");
           ProcessInstance processInstance =
           new ProcessInstance(processDefinition);
           Token token = processInstance.getRootToken();
           token.signal();
           jbpmSession.getGraphSession().
           saveProcessInstance(processInstance);
           }
           catch (Exception e)
           {
           e.printStackTrace();
           fail("Failure!:\n" + e.getMessage());
           }
           finally
           {
           jbpmSession.close();
           initialContext.close();
           }
           }
          


          I've included some logging output from jbpm/hibernate when the sessionfactory is being configured below.

          13:57:49,923 INFO [WrapperDataSourceService] Bound connection factory for resource adapter for ConnectionManager 'jboss.jca:service=DataSourceBinding,name=JBPMDS to JNDI name 'java:JBPMDS'
          13:57:49,946 INFO [Configuration] configuring from resource: jbpm.hibernate.cfg.xml
          13:57:49,946 INFO [Configuration] Configuration resource: jbpm.hibernate.cfg.xml
          13:57:51,627 INFO [Configuration] Configured SessionFactory: null
          13:57:51,629 INFO [Configuration] processing extends queue
          .
          [HbmBinder] (removed for brevity)
          .
          13:57:51,657 INFO [Configuration] processing association property references
          13:57:51,657 INFO [Configuration] processing foreign key constraints
          13:57:51,681 INFO [ConnectionProviderFactory] Initializing connection provider: org.hibernate.connection.DatasourceConnectionProvider
          13:57:51,683 INFO [NamingHelper] JNDI InitialContext properties:{}
          13:57:51,689 INFO [DatasourceConnectionProvider] Using datasource: java:/JBPMDS
          13:57:51,781 INFO [SettingsFactory] RDBMS: Oracle, version: Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production With the Partitioning, OLAP and Oracle Data Mining options JServer Release 9.2.0.4.0 - Production
          13:57:51,781 INFO [SettingsFactory] JDBC driver: Oracle JDBC driver, version: 9.2.0.3.0
          13:57:51,783 INFO [Dialect] Using dialect: org.hibernate.dialect.Oracle9Dialect
          13:57:51,785 INFO [TransactionFactoryFactory] Transaction strategy: org.hibernate.transaction.CMTTransactionFactory
          13:57:51,785 INFO [TransactionManagerLookupFactory] instantiating TransactionManagerLookup: org.hibernate.transaction.JBossTransactionManagerLookup
          13:57:51,785 INFO [TransactionManagerLookupFactory] instantiated TransactionManagerLookup
          13:57:51,785 INFO [SettingsFactory] Automatic flush during beforeCompletion(): enabled
          13:57:51,785 INFO [SettingsFactory] Automatic session close at end of transaction: enabled
          13:57:51,785 INFO [SettingsFactory] JDBC batch size: 15
          13:57:51,786 INFO [SettingsFactory] JDBC batch updates for versioned data: disabled
          13:57:51,786 INFO [SettingsFactory] Scrollable result sets: enabled
          13:57:51,786 INFO [SettingsFactory] JDBC3 getGeneratedKeys(): disabled
          13:57:51,786 INFO [SettingsFactory] Connection release mode: auto
          13:57:51,786 INFO [SettingsFactory] Default batch fetch size: 1
          13:57:51,786 INFO [SettingsFactory] Generate SQL with comments: disabled
          13:57:51,786 INFO [SettingsFactory] Order SQL updates by primary key: disabled
          13:57:51,786 INFO [SettingsFactory] Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
          13:57:51,788 INFO [ASTQueryTranslatorFactory] Using ASTQueryTranslatorFactory
          13:57:51,788 INFO [SettingsFactory] Query language substitutions: {}
          13:57:51,788 INFO [SettingsFactory] Second-level cache: enabled
          13:57:51,788 INFO [SettingsFactory] Query cache: disabled
          13:57:51,788 INFO [SettingsFactory] Cache provider: org.hibernate.cache.EhCacheProvider
          13:57:51,789 INFO [SettingsFactory] Optimize cache for minimal puts: disabled
          13:57:51,789 INFO [SettingsFactory] Structured second-level cache entries: disabled 13:57:51,790 INFO [SettingsFactory] Echoing all SQL to stdout 13:57:51,790 INFO [SettingsFactory] Statistics: disabled 13:57:51,790 INFO [SettingsFactory] Deleted entity synthetic identifier rollback: disabled 13:57:51,790 INFO [SettingsFactory] Default entity-mode: pojo
          13:57:51,806 INFO [SessionFactoryImpl] building session factory
          13:57:53,978 INFO [SessionFactoryObjectFactory] Factory name: java:com/env/hibernate/SessionFactory
          13:57:53,979 INFO [NamingHelper] JNDI InitialContext properties:{} 13:57:53,980 INFO [SessionFactoryObjectFactory] Bound factory to JNDI name: java:com/env/hibernate/SessionFactory
          13:57:53,981 WARN [SessionFactoryObjectFactory] InitialContext did not implement EventContext
          13:57:53,981 INFO [NamingHelper] JNDI InitialContext properties:{}
          13:57:53,982 INFO [SessionFactoryImpl] Checking 0 named HQL queries
          13:57:53,982 INFO [SessionFactoryImpl] Checking 0 named SQL queries
          13:57:53,983 INFO [JbpmService] binding JbpmSessionFactory 'java:/jbpm/JbpmSessionFactory' into JNDI...
          


          • 2. Re: Transaction demarcation with EJB/CMT
            ralfoeldi

            Hi heismann,

            did you flush the jbpm-/hibernatsession?

            try an explicity session.flush() or wrap whatever you're doing in jbpm beginTransaction / commitTransaction.

            Greeting

            Rainer

            • 3. Re: Transaction demarcation with EJB/CMT
              heismann

              Rainer,

              I have tried explicitly flushing, this results in the changes to the process instance being persisted. I have not tried adding begin/end transaction as I'm hoping to avoid any explicit transaction demarcation code.

              Based upon http://hibernate.org/42.html#A7 I believe it is possible to configure Hibernate so that the EJB container will handle the transaction demarcation.

              Shouldn't a call to session.beginTransaction() or session.endTransaction() within the scope of a CMT SSB be illegal?

              Zac

              • 4. Re: Transaction demarcation with EJB/CMT
                ralfoeldi

                Hi Zac,

                then I don't understand your problem. If the processInstance is being commited (persisted) that should be what you are expecting or isn't it? If the processInstance is persisted the surrounding cmt commited and everything is fine.

                If you trace the jbpm / hibernate code you will see some magic going on that figures out in what kind of environement everyting is happening. JBPM 'transactions' are not J2EE transactions. If called inside an existing transaction they will only flush the session and leave everything else to the existing transaction. The upside of this is that you can use the same code in various envs without changing anything. So it isn't illegal as it doesn't realy begin or commit a transaction.

                Greetings

                Rainer

                • 5. Re: Transaction demarcation with EJB/CMT
                  heismann

                  Hi Ranier,

                  f the processInstance is being commited (persisted) that should be what you are expecting or isn't it?

                  Yes I expect the processInstance to be committed when flush/commitTransaction is invoked.

                  I don't think I should have to call session.flush() or jbpmSession.commitTransaction() as this Hibernate documentation http://hibernate.org/42.html#A7 states:
                  Hibernate binds the current Session to the current (JTA) system transaction that is controlled by your EJB transaction assembly. When the system transaction commits (the EJB transaction completes), the Session is automatically flushed and closed.

                  Is this wrong?


                  Another question: If I end the jbpmSession.commitTransaction(), then if I call the SSB's sessionContext.setRollbackOnly() method shouldn't any updates/inserts performed by Hibernate be rolled back?

                  Thanks for your time.

                  Zac

                  • 6. Re: Transaction demarcation with EJB/CMT
                    heismann

                    It appears my only mistake was in closing the jbpmSession and not allowing the system to take care of it for me.

                    Calling the SSBs sessionContext.setRollbackOnly() had the expected result of not persisting the processInstance.

                    Does anyone know if not closing the jbpmSession will have any adverse affects?

                    Here's a working copy of my test method:

                     public void testHelloWorldProcessDefinition()
                     {
                     JbpmSession jbpmSession = null;
                     InitialContext initialContext = null;
                     Connection con = null;
                     try
                     {
                     initialContext = new InitialContext();
                     Object jndiObject = initialContext.lookup(JNDINAME);
                     JbpmSessionFactory instance = (JbpmSessionFactory) PortableRemoteObject.narrow(jndiObject, JbpmSessionFactory.class);
                     SessionFactory sessionFactory = instance.getSessionFactory();
                     Session currentSession = sessionFactory.getCurrentSession();
                     jbpmSession = instance.openJbpmSession(currentSession);
                    
                     ProcessDefinition processDefinition = jbpmSession.getGraphSession(). findLatestProcessDefinition("hello world");
                     ProcessInstance processInstance = new ProcessInstance(processDefinition);
                     Token token = processInstance.getRootToken();
                     token.signal();
                     jbpmSession.getGraphSession().saveProcessInstance(processInstance);
                     }
                     catch (Exception e)
                     {
                     e.printStackTrace();
                     fail("Failure!:\n" + e.getMessage());
                     }
                     finally
                     {
                     // Let the system take care of this when the EJB's transaction
                     // ends, then the session will be closed.
                     // jbpmSession.close();
                     //
                     initialContext.close();
                     }
                     }
                    


                    • 7. Re: Transaction demarcation with EJB/CMT
                      aguizar

                      Here is JbpmSession.close() in all its glory:

                      public void close() {
                       try {
                       if ( (session!=null) && (session.isOpen())) {
                       session.close();
                       }
                       } catch (Exception e) {
                       log.error(e);
                       throw new RuntimeException( "couldn't close the hibernate connection", e );
                       } finally {
                       popCurrentSession();
                       session = null;
                       }
                       }

                      The following line in your Hibernate configuration already closes the Hibernate session, so that is out. You won't be able to pop it from the thread-local stack because popCurrentSession() is private. This might leak memory in containers that pool threads.

                      Tom is working on a different approach to hold context objects in the 3.1 branch. It should cover the present situation.

                      • 8. Re: Transaction demarcation with EJB/CMT
                        heismann

                        Alex,

                        Thanks for the reply. I had forgotten about popCurrentSession() being in the close() method.

                        So, for now I will be forced to use:

                        jbpmSession.beginTransaction();
                        jbpmSession.commitTransaction();
                        jbpmSession.close();

                        Zac

                        • 9. Re: Transaction demarcation with EJB/CMT

                          No transaction stuff - leave that to the container.
                          Yes close the jBPMSession and
                          Yes flush the hibernate session.