jbpm4 整合SSH2 兼容 hibernate4

本文介绍了如何将jbpm4与SSH2框架整合,并兼容Hibernate4。首先,通过Spring配置创建ProcessEngine,然后配置jbpm.cfg.xml文件。接着,配置Hibernate的映射文件以支持数据库操作。在整合hibernate4时,需要覆盖某些类以解决与hibernate3的不兼容问题。最后,添加必要的jar包,确保jbpm4能够与SSH2和Hibernate4协同工作。
废话不多说,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 替换完就可以了。


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







评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值