SSJ整合jBPM4.3
来源:互联网 发布:java8 base64源码 编辑:程序博客网 时间:2024/05/13 08:22
原文地址
There have been a few discussion threads over using jBPM4 with JPA – with or without Spring. And a few “managed to work” kind of hacks came up. For example, prior to version 4.3, there was SpringConfiguration.setSessionFactory() where you inject the SessionFactory object obtained from the JPA entity manager factory. Another solution may be, you can have two sets of configurations – one for your regular business model and another for jBPM4. And you must admit none of these are really clean solutions.
Ideally this should same as working with Hibernate-jBPM4. You create a session factory configuration and pass the jBPM-xxx.hbm.xml files to the session factory. A sample session factory may look like this:
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">...</property>
<property name="hibernate.format_sql">true</property>
.
.
.
<mapping />
<mapping resource="myResource.hbm.xml" />
<mapping resource="jbpm.repository.hbm.xml" />
<mapping resource="jbpm.execution.hbm.xml" />
<mapping resource="jbpm.history.hbm.xml" />
<mapping resource="jbpm.task.hbm.xml" />
<mapping resource="jbpm.identity.hbm.xml" />
</session-factory>
</hibernate-configuration>
Things should be similar with JPA as well:
xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence" version="1.0">
<persistence-unit name="sample">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>jbpm.execution.hbm.xml</mapping-file>
<mapping-file>jbpm.repository.hbm.xml</mapping-file>
<mapping-file>jbpm.task.hbm.xml</mapping-file>
<mapping-file>jbpm.history.hbm.xml</mapping-file>
<class>org.santanu.MyDomainPojo</class>
<class>org.santanu.AnotherMyDomainPojo</class>
<properties>
...
</properties>
</persistence-unit>
</persistence>
- The class I loved the most when it comes to handle db access in jBPM4 isorg.jbpm.pvm.internal.session.DbSession. By default we have an implementation of that interface,org.jbpm.pvm.internal.hibernate.DbSessionImpl. This implementation uses current hibernate session to do all database operations. But we want to use JPA APIs. So we need to have another implementation of DbSession that will use JPA APIs instead of Hibernate classes.
- Once we have the org.jbpm.pvm.internal.session.DbSession implementation we need configure jBPM to use this. So we need to replace <db-session/> with our own tag in jBPM configuration file.
- To support the tag in configuration we need to create binding and descriptor classes.
- We also need to configure entity manager instead of hibernate session. This involves creating the binding and descriptor classes.
- One more configuration is required for creating/accessing entity manager factory. But if the entity manager factory is created by some other component (if framework like Spring is there in our application then by all likelihood entity manager factory wil be created and managed by that) - then we may not need that. So if we assume Spring to be our container then we can give this configuration a skip.
JPA Implementation of DbSession - We can have a DbSession implementation org.jbpm.pvm.internal.jpa.JpaDbSessionImplwhich somewhat followsorg.jbpm.pvm.internal.hibernate.DbSessionImpl and have the same set of methods implemented using Entity manager instead of Hibernate Session.
Binding classes for JpaDbSession - We need a binding and a descriptor for JpaDbSession. This is just a part of our regular exercise to register a new configuration tag. Both the binding and descriptor for this can be fairly simple.
public class JpaDbSessionBinding extends WireDescriptorBinding {public static final String TAG = "jpa-session";public JpaDbSessionBinding() {super(TAG);}public Object parse(Element element, Parse parse, Parser parser) {JpaDbSessionDescriptor descriptor = new JpaDbSessionDescriptor();return descriptor;}}public class JpaDbSessionDescriptor extends AbstractDescriptor {public Object construct(WireContext wireContext) {return new JpaDbSessionImpl();}public void initialize(Object object, WireContext wireContext) {EntityManager entityManager = wireContext.get(EntityManager.class);if (entityManager == null) {throw new WireException("couldn't find entity manager "+ (entityManagerName != null ? "'" + entityManagerName + "'" + "by type ") + "to create db-session");}// inject the session((JpaDbSessionImpl) object).setEntityManager(entityManager);}public Class<?> getType(WireDefinition wireDefinition) {return JpaDbSessionImpl.class;}}
The configuration we achieve here looks like this:
<jpa-session/>
package org.jbpm.pvm.internal.jpa;import javax.persistence.EntityManager;import org.jbpm.api.cmd.Environment;/*** @author Santanu*/public interface EntityManagerAccessor {/*** Implementing class should return the relevant entity manager.* @param environment* @return*/public EntityManager getEntityManager(Environment environment);}
package org.jbpm.pvm.internal.jpa;import java.util.HashMap;import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import org.jbpm.api.cmd.Environment;import org.springframework.orm.jpa.EntityManagerFactoryUtils;/*** @author Santanu*/public class SpringEntityManagerAccessor implements EntityManagerAccessor {@Override@SuppressWarnings("unchecked")public EntityManager getEntityManager(Environment environment) {EntityManagerFactory entityManagerFactory= environment.get(EntityManagerFactory.class);return EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory, new HashMap());}}
Rest of the binding and descriptor code are simple...
package org.jbpm.pvm.internal.wire.binding;import org.jbpm.pvm.internal.wire.descriptor.JpaEntityManagerDescriptor;import org.jbpm.pvm.internal.xml.Parse;import org.jbpm.pvm.internal.xml.Parser;import org.w3c.dom.Element;/*** @author Santanu*/public class JpaEntityManagerBinding extends WireDescriptorBinding {public static final String TAG = "entity-manager";public JpaEntityManagerBinding() {super(TAG);}/* (non-Javadoc)* @see org.jbpm.pvm.internal.xml.Binding* #parse(org.w3c.dom.Element, org.jbpm.pvm.internal.xml.Parse,* org.jbpm.pvm.internal.xml.Parser)*/@Overridepublic Object parse(Element element, Parse parse, Parser parser) {JpaEntityManagerDescriptor descriptor= new JpaEntityManagerDescriptor();......if (element.hasAttribute("accessor-class")) {descriptor.setProviderClassName(element.getAttribute("accessor-class"));}if (element.hasAttribute("create-new")) {descriptor.setCreateNew(Boolean.valueOf(element.getAttribute("create-new")));}...return descriptor;}}
package org.jbpm.pvm.internal.wire.descriptor;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import org.apache.commons.lang.StringUtils;import org.jbpm.pvm.internal.env.EnvironmentImpl;import org.jbpm.pvm.internal.jpa.EntityManagerAccessor;import org.jbpm.pvm.internal.wire.WireContext;import org.jbpm.pvm.internal.wire.WireDefinition;import org.jbpm.pvm.internal.wire.WireException;/*** @author Santanu*/public class JpaEntityManagerDescriptor extends AbstractDescriptor {.../* (non-Javadoc)* @see org.jbpm.pvm.internal.wire.Descriptor* #construct(org.jbpm.pvm.internal.wire.WireContext)*/@SuppressWarnings("unchecked")@Overridepublic Object construct(WireContext wireContext) {EnvironmentImpl environment = EnvironmentImpl.getCurrent();if (environment==null) {throw new WireException("no environment");}EntityManagerFactory entityManagerFactory = null;if (StringUtils.isNotBlank(factoryName)) {entityManagerFactory= (EntityManagerFactory)wireContext.get(factoryName);} else {entityManagerFactory = environment.get(EntityManagerFactory.class);}if (entityManagerFactory == null) {throw new WireException("No entity manager factory found");}EntityManager entityManager = null;// here we fight to get the entity manager// entity manager can be obtained in multiple ways// it can be injected by the container// it can be a "resource local" entity manager, where onus is// on the application to manage entity manager// lets allow the user to plug in some codeto get the EntityManagerif ((entityManager == null) && StringUtils.isNotBlank(providerClassName)) {try {Class providerClass = Class.forName(providerClassName);EntityManagerAccessor entityManagerProvider= (EntityManagerAccessor)providerClass.newInstance();entityManager = entityManagerProvider.getEntityManager(environment);} catch (ClassNotFoundException e) {throw new WireException("Problem loading class " + providerClassName, e);} catch (InstantiationException e) {throw new WireException("Problem while creating object of type "+ providerClassName, e);} catch (IllegalAccessException e) {throw new WireException("Problem while creating object of type "+ providerClassName, e);}// else if we are allowed to create an entity manager and have a factory// somewhere in the wire context then we can easily create oneif ((entityManager == null) && create) {entityManager = entityManagerFactory.createEntityManager();}......returnentityManager;}......public Class<?> getType(WireDefinition wireDefinition) {return EntityManager.class;}}
The last thing that is pending is the patch-up code we need to make the code dependent directly on hibernate session to work. We need to make sure that if the session is looked up we return the delegating session from the entity manager. For this we need a little change in the existing HibernateSessionDescriptor ans HibernateSessionBinding.We introduce a boolean to specify whether this is running in a JPA environment.
public class HibernateSessionBinding extends WireDescriptorBinding {public HibernateSessionBinding() {super("hibernate-session");}public Object parse(Element element, Parse parse, Parser parser) {HibernateSessionDescriptor descriptor = new HibernateSessionDescriptor();if (element.hasAttribute("jpa")) {Boolean isJpa = XmlUtil.attributeBoolean(element, "jpa", false, parse);descriptor.setJpa(isJpa);//if its jpa then we need this muchif (isJpa) {return descriptor;}}......}......}public class HibernateSessionDescriptor extends AbstractDescriptor {......//now we need some more if this class works to satisfy hibernate//session seekers//in a JPA environment - the strategy works only if the JPA//provider is hibernateprotected boolean jpa = false;public Object construct(WireContext wireContext) {...if (jpa) {return getSessionFromEntityManager(environment);}........}private Session getSessionFromEntityManager(EnvironmentImpl environment) {EntityManager entityManager = environment.get(EntityManager.class);Session session = (Session)entityManager.getDelegate();return session;}......}
Putting these all together, the jBPM configuration with these changes look like this (only the modified parts are depicted here):
<transaction-context>...<!--db-session/--><jpa-session/>......<transaction type="spring" /><entity-manager provider-class="org.jbpm.pvm.internal.jpa.SpringEntityManagerProvider"/><hibernate-session jpa="true"/>...</transaction-context>
源代码提供
- SSJ整合jBPM4.3
- jbpm4.3 spring 整合
- jbpm4.3整合spring3.0
- jbpm4.3与ssh框架进行整合
- jbpm4.3整合spring 完整案例
- JBPM4.3整合spring2.5+hibernate3.3.2
- jbpm4整合struts2+spring2.5+hibernate3.3
- jBPM4.3与Spring3.0的整合
- SSH整合JBPM4.3心得与体会
- SSH+JBPM4+Tomcat6整合
- SSH整合JBPM4.4
- SSH整合JBPM4.4
- jbpm4.3+SSH整合开发Step by Step
- jbpm4整合struts2+spring2.5+hibernate3.3入门实例教程
- jbpm4整合struts2+spring2.5+hibernate3.3入门实例教程
- JBPM4.4与SSH2整合
- jbpm4.4整合spring2.5
- JBPM4整合Spring环境搭建
- Breakdown
- fcntl()函数使用说明
- Linux群集LVS简介
- 直接 Run 和 Debug 结果不一样?
- 挑战题目一:尽请指点
- SSJ整合jBPM4.3
- 重做日志组数量问题
- 广播注册和中断(技巧)
- 五大设计图
- Android实现网络多线程断点续传下载
- 效率低下的组织是怎么产生的?
- Win7系统下鼠标滚轮6个玩法
- ecshop源码分析-ecshop二次开发
- 自己整理的五个常用的焦点图