Seam, Spring and jBPM integration HOWTO
frankyb Mar 7, 2008 2:41 PMIn 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.