jbpm4 整合SSH2 兼容 hibernate4

来源:互联网 发布:Mac OS X Capitan 编辑:程序博客网 时间:2024/06/01 10:18
废话不多说,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 替换完就可以了。


写的不好,希望能帮助到你。







4 0
原创粉丝点击