您的位置:首页 > 产品设计 > 产品经理

jbpm4 整合SSH2 兼容 hibernate4

2014-10-16 10:40 393 查看
废话不多说,jbpm4默认支持hibernate3.
整合过程如下:
研究过JBPM的人都知道,JBPM在操作流程时,一切都是基于ProcessEngine对象,所以整合的思路很简单,只要我们能让Spring创建出ProcessEngine,整合就算是迈出一大步,我们先在spring配置文件applicationContext-common.xml中添加如下:

<!-- jbpm配置 -->
<!-- 默认配置 这样需要jbpm.cfg.xml在classes目录下-->
<bean id="springHelper" class="org.jbpm.pvm.internal.processengine.SpringHelper" />
<!-- 配置 这样可以自行胚子jbpm.cfg.xml所在位置-->
<!--
<bean id="springHelper" class="org.jbpm.pvm.internal.processengine.SpringHelper">
<property name="jbpmCfg" value="jbpm.cfg.xml" />
</bean>
-->
<bean id="processEngine" factory-bean="springHelper" factory-method="createProcessEngine" />
<!-- 模板配置自己写的,不是必须的 -->
<bean id="jbpmTemplate" class="cn.seven.jbpm.util.JbpmTemplate">
<property name="processEngine" ref="processEngine"></property>
<property name="baseHiber" ref="baseHiber"></property>
</bean>

 
在这里创建processEngine 对象,在这里用到jbpm.cfg.xml
文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<jbpm-configuration>

<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.businesscalendar.cfg.xml" />
<!-- <import resource="jbpm.tx.hibernate.cfg.xml" /> -->
<import resource="jbpm.tx.spring.cfg.xml" />
<import resource="jbpm.jpdl.cfg.xml" />
<import resource="jbpm.bpmn.cfg.xml" />
<import resource="jbpm.identity.cfg.xml" />
<import resource="jbpm.console.cfg.xml" />

<!-- Job executor is excluded for running the example test cases. -->
<!-- To enable timers and messages in production use, this should be included. -->
<!--
<import resource="jbpm.jobexecutor.cfg.xml" />
-->

<!-- <import resource="jbpm.mail.templates.examples.xml" /> -->
<process-engine-context>
<string name="spring.cfg" value="classpath:/config/applicationContext-common.xml" />
</process-engine-context>
</jbpm-configuration>

 
看到这里,或许你又会问:jbpm.cfg.xml里又引用了那么多的文件,这些文件在哪里?这些文件,你不用担心,他们都在jbpm.jar文件里,这不是我们管的事。 
  到这里,算完了吗?还没有!前面说过,JBPM要数据库表的支持才能工作,JBPM又是使用Hibernate操作数据库,就不免要配置Hibernate的表与实体的映射文件,如下:
<property name="mappingLocations">
<list>
<value>classpath:jbpm.execution.hbm.xml</value>
<value>classpath:jbpm.history.hbm.xml</value>
<value>classpath:jbpm.identity.hbm.xml</value>
<value>classpath:jbpm.repository.hbm.xml</value>
<value>classpath:jbpm.task.hbm.xml</value>
</list>
</property>


我本地是这样配置的也可以,我的hibernate配置信息也一并交给spring管理,所以在applicationContext-common.xml文件中
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />

</bean>

 

这个标签内增加如下内容:
<!-- 如果使用配置文件 -->
<property name="mappingResources">
<list>
<value>jbpm.repository.hbm.xml</value>
<value>jbpm.execution.hbm.xml</value>
<value>jbpm.history.hbm.xml</value>
<value>jbpm.task.hbm.xml</value>
<value>jbpm.identity.hbm.xml</value>
</list>
</property>


这里说个题外话:
mappingResources、mappingLocations、mappingDirectoryLocations、mappingJarLocations
他们的区别:
1. mappingResources:指定classpath下具体映射文件名
<property name="mappingResources">
<value>petclinic.hbm.xml </value>
</property>
2. mappingLocations:可以指定任何文件路径,并且可以指定前缀:classpath、file等
<property name="mappingLocations">
<value>/WEB-INF/petclinic.hbm.xml </value>
</property>
<property name="mappingLocations">
<value>classpath:/com/company/domain/petclinic.hbm.xml </value>
</property>
也可以用通配符指定,'*'指定一个文件(路径)名,'**'指定多个文件(路径)名,例如:
<property name="mappingLocations">
<value>classpath:/com/company/domainmaps/*.hbm.xml </value>
</property>
上面的配置是在com/company/domain包下任何maps路径下的hbm.xml文件都被加载为映射文件

3. mappingDirectoryLocations:指定映射的文件路径

<property name="mappingDirectoryLocations">  <list>
<value>WEB-INF/HibernateMappings</value>
</list>
</property>
也可以通过classpath来指出
<property name="mappingDirectoryLocations">
<list>
<value>classpath:/XXX/package/</value>
</list>
</property>


言归正传,
下面一步,就是jar包的添加,如果你已经整合了SSH2,那么你只需要再添加jbpm.jar, juel-api.jar,juel-engine.jar,juel-impl.jar,mail.jar即可。

这里需要注意:
 juel-api.jar,juel-engine.jar,juel-impl.jar

这三个jar有可能会导致jar冲突,我本人的环境tomcat6.0 中存在这个问题,
解决办法:
把这三个jar包直接放到tomcat6.0/lib 下边,程序中就不要添加了,然后删除tomcat 6.0 原来的el-api.jar

如果是hinernate3的话到此就结束了。

问题是hibernate4怎么处理:
经过查资料总结如下经验:
jbpm4.4默认用的是hibernate3,如果要使用hibernate4整合,则要覆写一些类,一共3个,如图:



 
注意,你可以直接在项目中建如上几个包,然后创建这三个类,下面介绍这三个类的内容,你如果想看原内容,自行查询源码,在你下载的jbpm4.4中有,这里就不多说了。

(1)BlobStrategyBlob.java
package org.jbpm.pvm.internal.lob;

import java.sql.SQLException;

import org.hibernate.SessionFactory;
import org.jbpm.api.JbpmException;

import cn.seven.framework.spring.util.SpringContextUtil;

public class BlobStrategyBlob implements BlobStrategy {

public void set(byte[] bytes, Lob lob) {
if (bytes!=null) {
lob.cachedBytes = bytes;
//lob.blob = Hibernate.createBlob(bytes); --源码(hinernate3)--seven
lob.blob = ((SessionFactory)SpringContextUtil.getBean("sessionFactory")).getCurrentSession().getLobHelper().createBlob(bytes);
}
}

public byte[] get(Lob lob) {
if (lob.cachedBytes!=null) {
return lob.cachedBytes;
}

java.sql.Blob sqlBlob = lob.blob;
if (sqlBlob!=null) {
try {
return sqlBlob.getBytes(1, (int) sqlBlob.length());
} catch (SQLException e) {
throw new JbpmException("couldn't extract bytes out of blob", e);
}
}
return null;
}
}


 

从上面可以看出,我就修改了一行,即15行换作16行内容:

SpringContextUtil是我本地的一个工具类,其目的就是根据在spring注册的bean名称获取实例,上面16行代码换成以下四行:
 
ApplicationContext ac =  WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
SessionFactory sessionFactory = (SessionFactory)ac.getBean("sessionFactory");
Session session = sessionFactory.getCurrentSession();
lob.blob = session.getLobHelper().createBlob(bytes);


(2)SpringProcessEngine.java
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. */
package org.jbpm.pvm.internal.processengine;

import org.hibernate.cfg.Configuration;
import org.jbpm.api.ProcessEngine;
import org.jbpm.internal.log.Log;
import org.jbpm.pvm.internal.cfg.ConfigurationImpl;
import org.jbpm.pvm.internal.env.EnvironmentFactory;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.env.PvmEnvironment;
import org.jbpm.pvm.internal.env.SpringContext;
import org.jbpm.pvm.internal.wire.descriptor.ProvidedObjectDescriptor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;

/**
* this environment factory will see only the singleton beans.
*
* The created {@link SpringEnvironment}s will see the prototype beans and it
* will cache them.
*
* @author Andries Inze
*/
public class SpringProcessEngine extends ProcessEngineImpl implements EnvironmentFactory, ProcessEngine {

private static final Log log = Log.getLog(SpringProcessEngine.class.getName());

private static final long serialVersionUID = 1L;

private ApplicationContext applicationContext;

public static ProcessEngine create(ConfigurationImpl configuration) {
SpringProcessEngine springProcessEngine = null;

ApplicationContext applicationContext = null;
if (configuration.isInstantiatedFromSpring()) {
applicationContext = (ApplicationContext) configuration.getApplicationContext();

springProcessEngine = new SpringProcessEngine();
springProcessEngine.applicationContext = applicationContext;
springProcessEngine.initializeProcessEngine(configuration);

LocalSessionFactoryBean localSessionFactoryBean = springProcessEngine.get(LocalSessionFactoryBean.class);
Configuration hibernateConfiguration = localSessionFactoryBean.getConfiguration();
springProcessEngine.processEngineWireContext
.getWireDefinition()
.addDescriptor(new ProvidedObjectDescriptor(hibernateConfiguration, true));

springProcessEngine.checkDb(configuration);

} else {
String springCfg = (String) configuration.getProcessEngineWireContext().get("spring.cfg");
if (springCfg==null) {
springCfg = "applicationContext.xml";
}
applicationContext = new ClassPathXmlApplicationContext(springCfg);
springProcessEngine = (SpringProcessEngine) applicationContext.getBean("processEngine");
}

return springProcessEngine;
}

public EnvironmentImpl openEnvironment() {
PvmEnvironment environment = new PvmEnvironment(this);

if (log.isTraceEnabled())
log.trace("opening jbpm-spring" + environment);

environment.setContext(new SpringContext(applicationContext));

installAuthenticatedUserId(environment);
installProcessEngineContext(environment);
installTransactionContext(environment);

return environment;
}

@SuppressWarnings("unchecked")
@Override
public <T> T get(Class<T> type) {
String[] names = applicationContext.getBeanNamesForType(type);

if (names.length >= 1) {

if (names.length > 1 && log.isWarnEnabled()) {
log.warn("Multiple beans for type " + type + " found. Returning the first result.");
}

return (T) applicationContext.getBean(names[0]);
}

return super.get(type);
}

@Override
public Object get(String key) {
if (applicationContext.containsBean(key)) {
return applicationContext.getBean(key);
}

return super.get(key);
}
}


 

这个文件,其实就是把35行代码:
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;


替换为
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;


(3)HibernateSessionDescriptor.java
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. */
package org.jbpm.pvm.internal.wire.descriptor;

import java.sql.Connection;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.internal.SessionImpl;
import org.jbpm.internal.log.Log;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.tx.HibernateSessionResource;
import org.jbpm.pvm.internal.tx.StandardTransaction;
import org.jbpm.pvm.internal.wire.WireContext;
import org.jbpm.pvm.internal.wire.WireDefinition;
import org.jbpm.pvm.internal.wire.WireException;

/**
* @author Tom Baeyens
*/
public class HibernateSessionDescriptor extends AbstractDescriptor {

private static final long serialVersionUID = 1L;
private static final Log log = Log.getLog(HibernateSessionDescriptor.class.getName());

protected String factoryName;
protected boolean useCurrent = false;
protected boolean tx = true;
protected boolean close = true;
protected String standardTransactionName;
protected String connectionName;

public Object construct(WireContext wireContext) {
EnvironmentImpl environment = EnvironmentImpl.getCurrent();
if (environment==null) {
throw new WireException("no environment");
}

// get the hibernate-session-factory
SessionFactory sessionFactory = null;
if (factoryName!=null) {
sessionFactory = (SessionFactory) wireContext.get(factoryName);
} else {
sessionFactory = environment.get(SessionFactory.class);
}
if (sessionFactory==null) {
throw new WireException("couldn't find hibernate-session-factory "+(factoryName!=null ? "'"+factoryName+"'" : "by type ")+"to open a hibernate-session");
}

// open the hibernate-session
Session session = null;
if (useCurrent) {
if (log.isTraceEnabled()) log.trace("getting current hibernate session");
session = sessionFactory.getCurrentSession();

} else if (connectionName!=null) {
Connection connection = (Connection) wireContext.get(connectionName);
if (log.isTraceEnabled()) log.trace("creating hibernate session with connection "+connection);
//session = sessionFactory.openSession(connection);源码内容-seven-
session = (Session) sessionFactory.openStatelessSession(connection);

} else {
if (log.isTraceEnabled()) log.trace("creating hibernate session");
session = sessionFactory.openSession();
}

StandardTransaction standardTransaction = environment.get(StandardTransaction.class);
if (standardTransaction!=null) {
HibernateSessionResource hibernateSessionResource = new HibernateSessionResource(session);
standardTransaction.enlistResource(hibernateSessionResource);
}

return session;
}

public Class<?> getType(WireDefinition wireDefinition) {
return SessionImpl.class;
}

public void setFactoryName(String factoryName) {
this.factoryName = factoryName;
}
public void setTx(boolean tx) {
this.tx = tx;
}
public void setStandardTransactionName(String standardTransactionName) {
this.standardTransactionName = standardTransactionName;
}
public void setConnectionName(String connectionName) {
this.connectionName = connectionName;
}
public void setUseCurrent(boolean useCurrent) {
this.useCurrent = useCurrent;
}
public void setClose(boolean close) {
this.close = close;
}
}

 

这个文件是把78行换做79行。

到此基本就完成了,大部分 都应该成功了。如果不成功,有可能是连接池使用问题,因为我本人也遇到该问题
我的数据源配置如下:
<!--dbcp 配数据源 -->
<!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@1.168.0.11:1521:orcl" />
<property name="username" value="xxx" />
<property name="password" value="xxx" />
</bean> -->

<!-- 通过jndi的方式来调用datasource,即使不一定是在j2ee环境中也可以正常使用默认情况下,如果没有指定,"java:comp/env/"将放在后面jndi名称前面-->
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/pt</value>
</property>
<!-- 如果你不想使用 'java:comp/env/'前缀的话请设置下面的值为false, 默认值为false -->
<property name="resourceRef">
<value>true</value>
</property>
</bean>


 

因为我用的是tomcat 6.0 所以代码中这两种方式,估计都会有问题。
解决办法:
替换tomcat中的tomcat-dbcp.jar文件。

我用tomcat7.0中的tomcat-dbcp.jar 替换完就可以了。

写的不好,希望能帮助到你。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息