Commit b542aa3d authored by Andy Wilkinson's avatar Andy Wilkinson

Configure Hibernate with a WAS-specific JtaPlatform when running on WAS

At the time of writing WAS only supports JPA 2.0 which means that
Hibernate 4.2 is the latest version that can be used. SpringJtaPlatform
is Hibernate 4.3-specific as JtaPlatform’s package changed between
Hibernate 4.2 and 4.3. This means that SpringJtaPlatform can’t be used
on current versions of WAS. Futhermore, SpringJtaPlatform won’t work on
WAS even if we could use Hibernate 4.3 as WAS doesn’t make its
TransactionManager available to application code (it’s considered too
dangerous for general consumption) and SpringJtaPlatform
requires a TransactionManager.

This commit updates HibernateJpaAutoConfiguration to always treat WAS as
a special case and configure Hibernate with one of its WAS-specific
JtaPlatform implementations. 

Closes gh-2326
parent 2665ef06
...@@ -74,6 +74,14 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { ...@@ -74,6 +74,14 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
"org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform", "org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform",
"org.hibernate.service.jta.platform.internal.NoJtaPlatform" }; "org.hibernate.service.jta.platform.internal.NoJtaPlatform" };
/**
* {@code WebSphereExtendedJtaPlatform} implementations for various Hibernate
* versions.
*/
private static final String WEBSHERE_JTA_PLATFORM_CLASSES[] = {
"org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform",
"org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform", };
@Autowired @Autowired
private JpaProperties properties; private JpaProperties properties;
...@@ -104,25 +112,14 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { ...@@ -104,25 +112,14 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
throws LinkageError { throws LinkageError {
JtaTransactionManager jtaTransactionManager = getJtaTransactionManager(); JtaTransactionManager jtaTransactionManager = getJtaTransactionManager();
if (jtaTransactionManager != null) { if (jtaTransactionManager != null) {
try { if (runningOnWebSphere()) {
vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform( // We can never use SpringJtaPlatform on WebSphere as
jtaTransactionManager)); // WebSphereUowTransactionManger has a null TransactionManager
// which will cause Hibernate to NPE
configureWebSphereTransactionPlatform(vendorProperties);
} }
catch (NoClassDefFoundError ex) { else {
// Can happen if Hibernate 4.2 is used (for example on WAS) configureSpringJtaPlatform(vendorProperties, jtaTransactionManager);
if (isUsingJndi()) {
// Assume that we are not using a stand-alone transaction manager
// and Hibernate will use JNDI
if (logger.isDebugEnabled()) {
logger.debug("Unable to set Hibernate JTA platform : "
+ ex.getMessage());
}
}
else {
throw new IllegalStateException("Unable to set Hibernate JTA "
+ "platform, are you using the correct "
+ "version of hibernate?", ex);
}
} }
} }
else { else {
...@@ -130,6 +127,56 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { ...@@ -130,6 +127,56 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
} }
} }
private boolean runningOnWebSphere() {
return ClassUtils.isPresent(
"com.ibm.websphere.jtaextensions.ExtendedJTATransaction", getClass()
.getClassLoader());
}
private void configureWebSphereTransactionPlatform(
Map<String, Object> vendorProperties) {
vendorProperties.put(JTA_PLATFORM, getWebSphereJtaPlatformManager());
}
private Object getWebSphereJtaPlatformManager() {
return getJtaPlatformManager(WEBSHERE_JTA_PLATFORM_CLASSES);
}
private Object getJtaPlatformManager(String[] candidates) {
for (String candidate : candidates) {
try {
return Class.forName(candidate).newInstance();
}
catch (Exception ex) {
// Continue searching
}
}
throw new IllegalStateException("Could not configure JTA platform");
}
private void configureSpringJtaPlatform(Map<String, Object> vendorProperties,
JtaTransactionManager jtaTransactionManager) {
try {
vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform(
jtaTransactionManager));
}
catch (NoClassDefFoundError ex) {
// Can happen if Hibernate 4.2 is used
if (isUsingJndi()) {
// Assume that Hibernate will use JNDI
if (logger.isDebugEnabled()) {
logger.debug("Unable to set Hibernate JTA platform : "
+ ex.getMessage());
}
}
else {
throw new IllegalStateException("Unable to set Hibernate JTA "
+ "platform, are you using the correct "
+ "version of Hibernate?", ex);
}
}
}
private boolean isUsingJndi() { private boolean isUsingJndi() {
try { try {
return JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable(); return JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable();
...@@ -140,15 +187,7 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { ...@@ -140,15 +187,7 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
} }
private Object getNoJtaPlatformManager() { private Object getNoJtaPlatformManager() {
for (String noJtaPlatformClass : NO_JTA_PLATFORM_CLASSES) { return getJtaPlatformManager(NO_JTA_PLATFORM_CLASSES);
try {
return Class.forName(noJtaPlatformClass).newInstance();
}
catch (Exception ex) {
// Continue searching
}
}
throw new IllegalStateException("Could not configure JTA platform");
} }
@Order(Ordered.HIGHEST_PRECEDENCE + 20) @Order(Ordered.HIGHEST_PRECEDENCE + 20)
......
...@@ -32,11 +32,13 @@ import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; ...@@ -32,11 +32,13 @@ import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration; import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration;
import org.springframework.boot.autoconfigure.jta.JtaProperties; import org.springframework.boot.autoconfigure.jta.JtaProperties;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
...@@ -148,6 +150,17 @@ public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigura ...@@ -148,6 +150,17 @@ public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigura
this.context.refresh(); this.context.refresh();
} }
@Test
public void defaultJtaPlatform() throws Exception {
this.context.register(JtaProperties.class, JtaAutoConfiguration.class);
setupTestConfiguration();
this.context.refresh();
Map<String, Object> jpaPropertyMap = this.context.getBean(
LocalContainerEntityManagerFactoryBean.class).getJpaPropertyMap();
assertThat(jpaPropertyMap.get("hibernate.transaction.jta.platform"),
instanceOf(SpringJtaPlatform.class));
}
@Test @Test
public void testCustomJtaPlatform() throws Exception { public void testCustomJtaPlatform() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment