From ec83f86d9fb14d439b014bfc43a1d4c8f4a0e11f Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Sun, 9 Feb 2014 17:45:04 -0500 Subject: [PATCH] Upgrade to Hibernate 4 This change upgrades Spring Web Flow to Hibernate 4 but remains compatible with Hibernate 3. Issue: SWF-1534 --- build.gradle | 18 +++--- .../HibernateFlowExecutionListener.java | 58 ++++++++++++++++--- .../HibernateFlowExecutionListenerTests.java | 17 +++--- ...lowManagedPersistenceIntegrationTests.java | 4 +- ...atePersistenceContextPropagationTests.java | 6 +- 5 files changed, 72 insertions(+), 31 deletions(-) diff --git a/build.gradle b/build.gradle index 76e90307..343e6db5 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ configure(subprojects.findAll {it.name != "spring-js-resources"}) { subproject - } subproject.ext { - springVersion = "4.0.0.RELEASE" + springVersion = "4.0.1.RELEASE" springSecurityVersion = "3.2.0.RELEASE" slf4jVersion = "1.6.1" log4jVersion = "1.2.15" @@ -132,10 +132,10 @@ project("spring-js") { compile("org.springframework:spring-web:$springVersion") compile("org.springframework:spring-webmvc:$springVersion") provided("javax.servlet:javax.servlet-api:3.0.1") - optional("org.apache.tiles:tiles-api:2.1.2") - optional("org.apache.tiles:tiles-core:2.1.2") - optional("org.apache.tiles:tiles-jsp:2.1.2") - optional("org.apache.tiles:tiles-servlet:2.1.2") + optional("org.apache.tiles:tiles-api:2.2.2") + optional("org.apache.tiles:tiles-core:2.2.2") + optional("org.apache.tiles:tiles-jsp:2.2.2") + optional("org.apache.tiles:tiles-servlet:2.2.2") testCompile("javax.servlet:jstl:1.2") testCompile("log4j:log4j:$log4jVersion") { exclude group: "javax.mail", module: "mail" @@ -143,6 +143,8 @@ project("spring-js") { exclude group: "com.sun.jdmk", module: "jmxtools" exclude group: "com.sun.jmx", module: "jmxri" } + testCompile("org.slf4j:jcl-over-slf4j:$slf4jVersion") + testCompile("org.slf4j:slf4j-api:$slf4jVersion") testCompile("org.springframework:spring-test:$springVersion") } } @@ -166,7 +168,7 @@ project("spring-webflow") { provided("javax.portlet:portlet-api:2.0") provided("junit:junit:3.8.2") provided("org.eclipse.persistence:javax.persistence:2.0.0") - optional("org.hibernate:hibernate-core:3.6.9.Final") { + optional("org.hibernate:hibernate-core:4.2.8.Final") { exclude group: "org.slf4j", module: "slf4j-api" } optional("org.slf4j:slf4j-api:$slf4jVersion") @@ -175,8 +177,8 @@ project("spring-webflow") { optional("org.springframework:spring-tx:$springVersion") optional("org.springframework:spring-webmvc-portlet:$springVersion") testCompile("javax.validation:validation-api:1.0.0.GA") - testCompile("org.hibernate:hibernate-core:3.6.9.Final") - testCompile("org.hibernate:hibernate-entitymanager:3.6.9.Final") + testCompile("org.hibernate:hibernate-core:4.2.8.Final") + testCompile("org.hibernate:hibernate-entitymanager:4.2.8.Final") testCompile("org.hibernate:hibernate-validator:4.3.0.Final") testCompile("org.apache.tomcat:tomcat-jasper-el:7.0.27") testCompile("org.hsqldb:hsqldb:2.2.8") diff --git a/spring-webflow/src/main/java/org/springframework/webflow/persistence/HibernateFlowExecutionListener.java b/spring-webflow/src/main/java/org/springframework/webflow/persistence/HibernateFlowExecutionListener.java index 679646d2..7b4286c7 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/persistence/HibernateFlowExecutionListener.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/persistence/HibernateFlowExecutionListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2012 the original author or authors. + * Copyright 2004-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,16 +15,21 @@ */ package org.springframework.webflow.persistence; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import org.hibernate.FlushMode; import org.hibernate.Interceptor; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.springframework.orm.hibernate3.SessionHolder; +import org.springframework.orm.hibernate4.SessionHolder; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.definition.FlowDefinition; @@ -48,7 +53,7 @@ import org.springframework.webflow.execution.RequestContext; *
  • When an existing flow ends, commit the changes made to the session in a transaction if the ending state is a * commit state. Then, unbind the context and close it. * - * + * * The general data access pattern implemented here is: * - * + * *

    * Note: All data access except for the final commit will, by default, be non-transactional. However, a flow may call * into a transactional service layer to fetch objects during the conversation in the context of a read-only system @@ -68,13 +73,23 @@ import org.springframework.webflow.execution.RequestContext; * want intermediate flushing to happen, as the nature of a flow implies a transient, isolated resource that can be * canceled before it ends. Generally, the only time a read-write transaction should be started is upon successful * completion of the conversation, triggered by reaching a 'commit' end state. - * + * * @author Keith Donald * @author Juergen Hoeller * @author Ben Hale */ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter { + private static final boolean hibernate3Present = ClassUtils.isPresent("org.hibernate.connection.ConnectionProvider", + HibernateFlowExecutionListener.class.getClassLoader()); + + private static final Method openSessionMethod = + ReflectionUtils.findMethod(SessionFactory.class, "openSession"); + + private static final Method openSessionWithInterceptorMethod = + ReflectionUtils.findMethod(SessionFactory.class, "openSession", Interceptor.class); + + /** * The name of the attribute the flow {@link Session persistence context} is indexed under. */ @@ -183,8 +198,33 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter } private Session createSession(RequestContext context) { - Session session = (entityInterceptor != null ? sessionFactory.openSession(entityInterceptor) : sessionFactory - .openSession()); + Session session; + if (entityInterceptor != null) { + if (hibernate3Present) { + try { + session = (Session) openSessionWithInterceptorMethod.invoke(sessionFactory, entityInterceptor); + } catch (IllegalAccessException ex) { + throw new IllegalStateException("Unable to open Hibernate 3 session", ex); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("Unable to open Hibernate 3 session", ex); + } + } else { + session = sessionFactory.withOptions().interceptor(entityInterceptor).openSession(); + } + } else { + if (hibernate3Present) { + try { + session = (Session) openSessionMethod.invoke(sessionFactory); + } catch (IllegalAccessException ex) { + throw new IllegalStateException("Unable to open Hibernate 3 session", ex); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("Unable to open Hibernate 3 session", ex); + } + } + else { + session = sessionFactory.openSession(); + } + } session.setFlushMode(FlushMode.MANUAL); return session; } @@ -198,7 +238,9 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter } private void bind(Session session) { - TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); + Object sessionHolder = (hibernate3Present ? + new org.springframework.orm.hibernate3.SessionHolder(session) : new SessionHolder(session)); + TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder); } private void unbind(Session session) { diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowExecutionListenerTests.java b/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowExecutionListenerTests.java index f0d99c4e..2d51dbdc 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowExecutionListenerTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowExecutionListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2012 the original author or authors. + * Copyright 2004-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,11 @@ */ package org.springframework.webflow.persistence; -import java.sql.SQLException; - import javax.sql.DataSource; import junit.framework.TestCase; import org.hibernate.Hibernate; -import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.core.io.ClassPathResource; @@ -31,10 +28,10 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.jdbc.datasource.init.DataSourceInitializer; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.HibernateTemplate; -import org.springframework.orm.hibernate3.HibernateTransactionManager; -import org.springframework.orm.hibernate3.LocalSessionFactoryBean; +import org.springframework.orm.hibernate4.HibernateCallback; +import org.springframework.orm.hibernate4.HibernateTemplate; +import org.springframework.orm.hibernate4.HibernateTransactionManager; +import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.webflow.engine.EndState; import org.springframework.webflow.execution.FlowExecutionException; @@ -43,7 +40,7 @@ import org.springframework.webflow.test.MockRequestContext; /** * Tests for {@link HibernateFlowExecutionListener} - * + * * @author Ben Hale */ public class HibernateFlowExecutionListenerTests extends TestCase { @@ -86,7 +83,7 @@ public class HibernateFlowExecutionListenerTests extends TestCase { assertSessionBound(); hibernateTemplate.executeWithNativeSession(new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException, SQLException { + public Object doInHibernate(Session session) { assertSame("Should have been original instance", hibSession, session); return null; } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowManagedPersistenceIntegrationTests.java b/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowManagedPersistenceIntegrationTests.java index 75aab0d9..233cb7ea 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowManagedPersistenceIntegrationTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernateFlowManagedPersistenceIntegrationTests.java @@ -6,8 +6,8 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import org.springframework.orm.hibernate3.HibernateTransactionManager; -import org.springframework.orm.hibernate3.LocalSessionFactoryBean; +import org.springframework.orm.hibernate4.HibernateTransactionManager; +import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.webflow.execution.Action; import org.springframework.webflow.execution.Event; diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernatePersistenceContextPropagationTests.java b/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernatePersistenceContextPropagationTests.java index 32b050eb..e7870b08 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernatePersistenceContextPropagationTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/HibernatePersistenceContextPropagationTests.java @@ -5,9 +5,9 @@ import javax.sql.DataSource; import org.hibernate.SessionFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import org.springframework.orm.hibernate3.HibernateTemplate; -import org.springframework.orm.hibernate3.HibernateTransactionManager; -import org.springframework.orm.hibernate3.LocalSessionFactoryBean; +import org.springframework.orm.hibernate4.HibernateTemplate; +import org.springframework.orm.hibernate4.HibernateTransactionManager; +import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.webflow.execution.FlowExecutionListener;