1 Reply Latest reply on Mar 7, 2008 3:34 PM by christian.bauer

    Seam, Spring and jBPM integration HOWTO

    frankyb

      In this post I will publish the work I did to integrate Seam, Spring and jBPM in order to use the same Hibernate SessionFactory in Spring and jBPM (and of course, Seam).


      Maybe it is not the perfect solution, but it works fine, at least for me.


      At first, make sure you use the latest version 2.1.0 of Seam since you could get trouble with 2.0.1 and SpringTransactions.




      The relevant parts of the configuration are:


      - in your Spring bean config, define your Hibernate sessionFactory as usual and set the following properties in special


      <bean id="hibernateSessionFactory"
                class="...">
      
           <!-- The hibernate properties  -->
           <property name="hibernateProperties">
                <props>
                          
      ...
      
                        <prop key="hibernate.hbm2ddl.auto">update</prop>
                     <!-- set to create-drop to NOT maintain state between two executions of the app -->
                     
      
                     <prop
                               key="hibernate.transaction.flush_before_completion">
                               true
                     </prop>
                     <prop key="hibernate.connection.release_mode">
                               after_transaction
                     </prop>
      
                </props>
           </property>
      
      <!-- this property must be set to false so we can use independent sessions -->
           <property name="useTransactionAwareDataSource">
                <value>false</value>
           </property>
      
      
           <property name="mappingResources">
                <list>
      
                      <!-- here you have to list all the *hbm.xml files for jBPM -->
                      <!-- see the default hibernate.cfg.xml file from jBPM -->
      
      
      ...
      
      </bean>



      - second, for the Seam Spring integration we need two beans



      <bean id="sessionFactory"
                class="org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean">
                <property name="sessionName" value="hibernateSession" />
      </bean>
      
           
      <bean id="localTransactionManager"
                class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                <property name="sessionFactory" ref="hibernateSessionFactory" />
      </bean>



      That's it for Spring configuration.


      Now in components.xml, we need



      <!-- use the power of Spring transactions -->
      <spring:spring-transaction platform-transaction-manager-name="localTransactionManager"/>
             
      <persistence:managed-hibernate-session name="hibernateSession" auto-create="true"
              session-factory="#{hibernateSessionFactory}"/> 
              
         
      <component class="org.jboss.seam.bpm.Jbpm">
              <property name="processDefinitions">processdefinition.jpdl.xml</property>
      </component>




      In order to use the hibernateSession in jBPM, I subclassed the DbPersistenceService from jBPM. You need two classes:




      package your.namespace.jbpm.integration;
      
      
      
      import org.hibernate.Session;
      import org.hibernate.SessionFactory;
      
      import org.jboss.seam.Component;
      import org.jboss.seam.contexts.Contexts;
      
      import org.jbpm.svc.Service;
      
      /**
       * @author Frank Bitzer (FBI)
       *
       */
      
      public class DbPersistenceServiceFactory extends
                org.jbpm.persistence.db.DbPersistenceServiceFactory {
      
           private static final long serialVersionUID = 997L;
      
           
           SessionFactory sessionFactory;
           
           /**
            * {@inheritDoc}
            */
           public Service openService() {
               
                //create instance of own service implementation
               return new your.namespace.jbpm.integration.DbPersistenceService(this);
             }
           
           
           /**
            * Retrieve Hibernate sessionFactory
            */
           @Override
           public synchronized SessionFactory getSessionFactory() {
              
                if (sessionFactory==null) {
                    
                      if(Contexts.isApplicationContextActive()){
                           
                           //access seam component holding session
                           Session session = (Session)
                                 Component.getInstance("hibernateSession");
                          
                           //and extract sessionFactory
                          sessionFactory = session.getSessionFactory();
                          
                      }
                     
               }
               
               return sessionFactory;
           }
           
           /**
            * Set sessionFactory
            */
           @Override
           public void setSessionFactory(SessionFactory sessionFactory) {
               this.sessionFactory = sessionFactory;
             }
           
           
      }





      package your.namespace.jbpm.integration;
      
      import org.hibernate.Session;
      import org.jbpm.JbpmContext;
      import org.jbpm.persistence.db.DbPersistenceServiceFactory;
      import org.jbpm.svc.Services;
      import org.springframework.orm.hibernate3.SessionFactoryUtils;
      
      /**
       * @author Frank Bitzer (FBI)
       * 
       */
      public class DbPersistenceService extends
                org.jbpm.persistence.db.DbPersistenceService {
      
           private static final long serialVersionUID = 996L;
      
           public DbPersistenceService(
                     DbPersistenceServiceFactory persistenceServiceFactory) {
                this(persistenceServiceFactory, getCurrentServices());
           }
      
           static Services getCurrentServices() {
                Services services = null;
                JbpmContext currentJbpmContext = JbpmContext.getCurrentJbpmContext();
                if (currentJbpmContext != null) {
                     services = currentJbpmContext.getServices();
                }
                return services;
           }
      
           DbPersistenceService(DbPersistenceServiceFactory persistenceServiceFactory,
                     Services services) {
      
                super(persistenceServiceFactory);
      
                this.persistenceServiceFactory = persistenceServiceFactory;
                this.isTransactionEnabled = persistenceServiceFactory
                          .isTransactionEnabled();
                this.isCurrentSessionEnabled = persistenceServiceFactory
                          .isCurrentSessionEnabled();
                this.services = services;
      
           }
      
           
           /**
            * Use Hibernate sessionFactory to retrieve a Session instance.
            */
           public Session getSession() {
      
                if ((session == null) && (getSessionFactory() != null)) {
      
                     session = getSessionFactory().openSession();
      
                     mustSessionBeClosed = true;
                     mustSessionBeFlushed = true;
                     mustConnectionBeClosed = false;
      
                     isTransactionEnabled = !SessionFactoryUtils.isSessionTransactional(
                               session, getSessionFactory());
      
                     if (isTransactionEnabled) {
      
                          beginTransaction();
                     }
      
                }
                return session;
           }
      
      }




      To finish work, simply use the brand-new DbPersistenceService in jbpm.cfg.xml like



      ...
      <jbpm-context>
          <service name="persistence">
                <factory>
                     <bean class="your.namespace.jbpm.integration.DbPersistenceServiceFactory">
                          <field name="isTransactionEnabled">
                              <false/>
                          </field>
                     </bean>
                </factory>
           </service>
      
      ...
      </jbpm-context>
      ...




      That's it!



      If you have some improvements, please let me know.


      @Seam people: if you want this article to appear somewhere else than in this forum (e.g. in the Knowledge Base), feel free to adapt it.