Browse Source

Update DataSource auto-configuration to support XA

Update DataSource and JPA auto-configuration to consider XA datasources.

See gh-947
pull/1323/merge
Phillip Webb 12 years ago
parent
commit
8219f2be4c
  1. 9
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java
  2. 8
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceBuilder.java
  3. 44
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java
  4. 137
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DatabaseDriver.java
  5. 3
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java
  6. 119
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfiguration.java
  7. 26
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/EntityManagerFactoryBuilder.java
  8. 28
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java
  9. 30
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java
  10. 1
      spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
  11. 29
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DatabaseDriverTests.java
  12. 128
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfigurationTests.java

9
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@ -74,7 +75,7 @@ public class DataSourceAutoConfiguration { @@ -74,7 +75,7 @@ public class DataSourceAutoConfiguration {
}
@Conditional(DataSourceAutoConfiguration.EmbeddedDataSourceCondition.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedConfiguration {
@ -92,7 +93,7 @@ public class DataSourceAutoConfiguration { @@ -92,7 +93,7 @@ public class DataSourceAutoConfiguration {
}
@Conditional(DataSourceAutoConfiguration.NonEmbeddedDataSourceCondition.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
protected static class NonEmbeddedConfiguration {
@Autowired
@ -196,7 +197,8 @@ public class DataSourceAutoConfiguration { @@ -196,7 +197,8 @@ public class DataSourceAutoConfiguration {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
if (hasBean(context, DataSource.class)) {
if (hasBean(context, DataSource.class)
|| hasBean(context, XADataSource.class)) {
return ConditionOutcome
.match("existing bean configured database detected");
}
@ -210,6 +212,7 @@ public class DataSourceAutoConfiguration { @@ -210,6 +212,7 @@ public class DataSourceAutoConfiguration {
return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
context.getBeanFactory(), type, true, false).length > 0;
}
}
}

8
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceBuilder.java

@ -49,8 +49,6 @@ public class DataSourceBuilder { @@ -49,8 +49,6 @@ public class DataSourceBuilder {
private ClassLoader classLoader;
private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider();
private Map<String, String> properties = new HashMap<String, String>();
public static DataSourceBuilder create() {
@ -76,9 +74,9 @@ public class DataSourceBuilder { @@ -76,9 +74,9 @@ public class DataSourceBuilder {
private void maybeGetDriverClassName() {
if (!this.properties.containsKey("driverClassName")
&& this.properties.containsKey("url")) {
String cls = this.driverClassNameProvider.getDriverClassName(this.properties
.get("url"));
this.properties.put("driverClassName", cls);
String url = this.properties.get("url");
String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
this.properties.put("driverClassName", driverClass);
}
}

44
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java

@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
package org.springframework.boot.autoconfigure.jdbc;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
@ -64,7 +67,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB @@ -64,7 +67,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
private EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection.NONE;
private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider();
private Xa xa = new Xa();
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
@ -86,7 +89,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB @@ -86,7 +89,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
String driverClassName = null;
if (StringUtils.hasText(this.url)) {
driverClassName = this.driverClassNameProvider.getDriverClassName(this.url);
driverClassName = DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName();
}
if (!StringUtils.hasText(driverClassName)) {
@ -113,7 +116,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB @@ -113,7 +116,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
"Cannot determine embedded database url for database type "
+ this.embeddedDatabaseConnection
+ ". If you want an embedded "
+ "database please put a supported on on the classpath.");
+ "database please put a supported one on the classpath.");
}
return url;
}
@ -228,4 +231,39 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB @@ -228,4 +231,39 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
return this.classLoader;
}
public Xa getXa() {
return this.xa;
}
public void setXa(Xa xa) {
this.xa = xa;
}
/**
* XA Specific datasource settings.
*/
public static class Xa {
private String dataSourceClassName;
private Map<String, String> properties = new LinkedHashMap<String, String>();
public String getDataSourceClassName() {
return this.dataSourceClassName;
}
public void setDataSourceClassName(String dataSourceClassName) {
this.dataSourceClassName = dataSourceClassName;
}
public Map<String, String> getProperties() {
return this.properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
}
}

137
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DatabaseDriver.java

@ -0,0 +1,137 @@ @@ -0,0 +1,137 @@
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Enumeration of common database drivers.
*
* @author Phillip Webb
* @author Maciej Walkowiak
* @since 1.2.0
*/
enum DatabaseDriver {
/**
* Unknown type.
*/
UNKNOWN(null),
/**
* Apache Derby.
*/
DERBY("org.apache.derby.jdbc.EmbeddedDriver"),
/**
* H2.
*/
H2("org.h2.Driver", "org.h2.jdbcx.JdbcDataSource"),
/**
* HyperSQL DataBase.
*/
HSQLDB("org.hsqldb.jdbc.JDBCDriver", "org.hsqldb.jdbc.pool.JDBCXADataSource"),
/**
* SQL Lite.
*/
SQLITE("org.sqlite.JDBC"),
/**
* MySQL.
*/
MYSQL("com.mysql.jdbc.Driver", "org.mysql.jdbc.MySQLDataSource"),
/**
* Maria DB.
*/
MARIADB("org.mariadb.jdbc.Driver", "org.mariadb.jdbc.MySQLDataSource"),
/**
* Google App Engine.
*/
GOOGLE("com.google.appengine.api.rdbms.AppEngineDriver"),
/**
* Oracle
*/
ORACLE("oracle.jdbc.OracleDriver", "oracle.jdbc.xa.OracleXADataSource"),
/**
* Postres
*/
POSTGRESQL("org.postgresql.Driver", "org.postgresql.xa.PGXADataSource"),
/**
* JTDS
*/
JTDS("net.sourceforge.jtds.jdbc.Driver"),
/**
* SQL Server
*/
SQLSERVER("com.microsoft.sqlserver.jdbc.SQLServerDriver");
private final String driverClassName;
private final String xaDataSourceClassName;
private DatabaseDriver(String driverClassName) {
this(driverClassName, null);
}
private DatabaseDriver(String driverClassName, String xaDataSourceClassName) {
this.driverClassName = driverClassName;
this.xaDataSourceClassName = xaDataSourceClassName;
}
/**
* @return the driverClassName or {@code null}
*/
public String getDriverClassName() {
return this.driverClassName;
}
/**
* @return the xaDataSourceClassName or {@code null}
*/
public String getXaDataSourceClassName() {
return this.xaDataSourceClassName;
}
/**
* Find a {@link DatabaseDriver} for the given URL.
* @param url JDBC URL
* @return driver class name or {@link #UNKNOWN} if not found
*/
public static DatabaseDriver fromJdbcUrl(String url) {
if (StringUtils.hasLength(url)) {
Assert.isTrue(url.startsWith("jdbc"), "URL must start with 'jdbc'");
String urlWithoutPrefix = url.substring("jdbc".length()).toLowerCase();
for (DatabaseDriver driver : values()) {
String prefix = ":" + driver.name().toLowerCase() + ":";
if (driver != UNKNOWN && urlWithoutPrefix.startsWith(prefix)) {
return driver;
}
}
}
return UNKNOWN;
}
}

3
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java

@ -36,7 +36,8 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; @@ -36,7 +36,8 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
* @since 1.2.0
*/
@Configuration
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@AutoConfigureBefore({ XADataSourceAutoConfiguration.class,
DataSourceAutoConfiguration.class })
@ConditionalOnClass(DataSource.class)
@ConditionalOnProperty(prefix = DataSourceProperties.PREFIX, name = "jndi-name")
@EnableConfigurationProperties(DataSourceProperties.class)

119
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfiguration.java

@ -0,0 +1,119 @@ @@ -0,0 +1,119 @@
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import javax.transaction.TransactionManager;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jta.XADataSourceWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource} with XA.
*
* @author Phillip Webb
* @author Josh Long
* @since 1.2.0
*/
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@AutoConfigureAfter(JtaAutoConfiguration.class)
@EnableConfigurationProperties(DataSourceProperties.class)
@ConditionalOnClass({ DataSource.class, TransactionManager.class })
@ConditionalOnBean(XADataSourceWrapper.class)
@ConditionalOnMissingBean(DataSource.class)
public class XADataSourceAutoConfiguration implements BeanClassLoaderAware {
@Autowired
private XADataSourceWrapper wrapper;
@Autowired
private DataSourceProperties properties;
@Autowired(required = false)
private XADataSource xaDataSource;
private ClassLoader classLoader;
@Bean
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
public DataSource dataSource() throws Exception {
XADataSource xaDataSource = this.xaDataSource;
if (xaDataSource == null) {
xaDataSource = createXaDataSource();
}
return this.wrapper.wrapDataSource(xaDataSource);
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
private XADataSource createXaDataSource() {
String className = this.properties.getXa().getDataSourceClassName();
if (!StringUtils.hasLength(className)) {
className = DatabaseDriver.fromJdbcUrl(this.properties.getUrl())
.getXaDataSourceClassName();
}
Assert.state(StringUtils.hasLength(className),
"No XA DataSource class name specified");
XADataSource dataSource = createXaDataSourceInstance(className);
bindXaProperties(dataSource, this.properties);
return dataSource;
}
private XADataSource createXaDataSourceInstance(String className) {
try {
Class<?> dataSourceClass = ClassUtils.forName(className, this.classLoader);
Object instance = BeanUtils.instantiate(dataSourceClass);
Assert.isInstanceOf(XADataSource.class, instance);
return (XADataSource) instance;
}
catch (Exception ex) {
throw new IllegalStateException(
"Unable to create XADataSource instance from '" + className + "'");
}
}
private void bindXaProperties(XADataSource target, DataSourceProperties properties) {
MutablePropertyValues values = new MutablePropertyValues();
values.add("user", this.properties.getUsername());
values.add("password", this.properties.getPassword());
values.add("url", this.properties.getUrl());
values.addPropertyValues(properties.getXa().getProperties());
new RelaxedDataBinder(target).withAlias("user", "username").bind(values);
}
}

26
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/EntityManagerFactoryBuilder.java

@ -89,6 +89,8 @@ public class EntityManagerFactoryBuilder { @@ -89,6 +89,8 @@ public class EntityManagerFactoryBuilder {
private Map<String, Object> properties = new HashMap<String, Object>();
private boolean jta;
private Builder(DataSource dataSource) {
this.dataSource = dataSource;
}
@ -142,6 +144,21 @@ public class EntityManagerFactoryBuilder { @@ -142,6 +144,21 @@ public class EntityManagerFactoryBuilder {
return this;
}
/**
* Configure if using a JTA {@link DataSource}, i.e. if
* {@link LocalContainerEntityManagerFactoryBean#setDataSource(DataSource)
* setDataSource} or
* {@link LocalContainerEntityManagerFactoryBean#setJtaDataSource(DataSource)
* setJtaDataSource} should be called on the
* {@link LocalContainerEntityManagerFactoryBean}.
* @param jta if the data source is JTA
* @return the builder for fluent usage
*/
public Builder jta(boolean jta) {
this.jta = jta;
return this;
}
public LocalContainerEntityManagerFactoryBean build() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
if (EntityManagerFactoryBuilder.this.persistenceUnitManager != null) {
@ -153,7 +170,14 @@ public class EntityManagerFactoryBuilder { @@ -153,7 +170,14 @@ public class EntityManagerFactoryBuilder {
}
entityManagerFactoryBean
.setJpaVendorAdapter(EntityManagerFactoryBuilder.this.jpaVendorAdapter);
entityManagerFactoryBean.setDataSource(this.dataSource);
if (this.jta) {
entityManagerFactoryBean.setJtaDataSource(this.dataSource);
}
else {
entityManagerFactoryBean.setDataSource(this.dataSource);
}
entityManagerFactoryBean.setPackagesToScan(this.packagesToScan);
entityManagerFactoryBean.getJpaPropertyMap().putAll(
EntityManagerFactoryBuilder.this.properties.getProperties());

28
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java

@ -22,6 +22,7 @@ import java.util.Map; @@ -22,6 +22,7 @@ import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -29,8 +30,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome; @@ -29,8 +30,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.HibernateEntityManagerCondition;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@ -39,29 +41,30 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -39,29 +41,30 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.ClassUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Hibernate JPA.
*
* @author Phillip Webb
* @author Josh Long
*/
@Configuration
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class,
EnableTransactionManagement.class, EntityManager.class })
@Conditional(HibernateEntityManagerCondition.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JtaAutoConfiguration.class })
public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
private static final String JTA_PLATFORM = "hibernate.transaction.jta.platform";
@Autowired
private JpaProperties properties;
@Autowired
private DataSource dataSource;
@Autowired
private ConfigurableApplicationContext applicationContext;
@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
@ -74,6 +77,21 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { @@ -74,6 +77,21 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
return vendorProperties;
}
@Override
protected void customizeVendorProperties(Map<String, Object> vendorProperties) {
super.customizeVendorProperties(vendorProperties);
if (!vendorProperties.containsKey(JTA_PLATFORM)) {
JtaTransactionManager jtaTransactionManager = getJtaTransactionManager();
if (jtaTransactionManager != null) {
vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform(
jtaTransactionManager));
}
else {
vendorProperties.put(JTA_PLATFORM, NoJtaPlatform.INSTANCE);
}
}
}
static class HibernateEntityManagerCondition extends SpringBootCondition {
private static String[] CLASS_NAMES = {

30
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java

@ -44,6 +44,7 @@ import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; @@ -44,6 +44,7 @@ import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@ -71,6 +72,9 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { @@ -71,6 +72,9 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
@Autowired
private JpaProperties jpaProperties;
@Autowired(required = false)
private JtaTransactionManager jtaTransactionManager;
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public PlatformTransactionManager transactionManager() {
@ -103,14 +107,24 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { @@ -103,14 +107,24 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
@ConditionalOnMissingBean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder factoryBuilder) {
Map<String, Object> vendorProperties = getVendorProperties();
customizeVendorProperties(vendorProperties);
return factoryBuilder.dataSource(this.dataSource).packages(getPackagesToScan())
.properties(getVendorProperties()).build();
.properties(vendorProperties).jta(isJta()).build();
}
protected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();
protected abstract Map<String, Object> getVendorProperties();
/**
* Customize vendor properties before they are used. Allows for post processing (for
* example to configure JTA specific settings).
* @param vendorProperties the vendor properties to customize
*/
protected void customizeVendorProperties(Map<String, Object> vendorProperties) {
}
protected EntityManagerFactoryBuilder.EntityManagerFactoryBeanCallback getVendorCallback() {
return null;
}
@ -127,6 +141,20 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { @@ -127,6 +141,20 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
}
/**
* @return the jtaTransactionManager or {@code null}
*/
protected JtaTransactionManager getJtaTransactionManager() {
return this.jtaTransactionManager;
}
/**
* Returns if a JTA {@link PlatformTransactionManager} is being used.
*/
protected final boolean isJta() {
return (this.jtaTransactionManager != null);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;

1
spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

@ -20,6 +20,7 @@ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\ @@ -20,6 +20,7 @@ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\

29
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProviderTests.java → spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DatabaseDriverTests.java

@ -20,47 +20,46 @@ import org.junit.Rule; @@ -20,47 +20,46 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link DriverClassNameProvider}.
* Tests for {@link DatabaseDriver}.
*
* @author Phillip Webb
* @author Maciej Walkowiak
*/
public class DriverClassNameProviderTests {
private DriverClassNameProvider provider = new DriverClassNameProvider();
public class DatabaseDriverTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void classNameForKnownDatabase() {
String driverClassName = this.provider
.getDriverClassName("jdbc:postgresql://hostname/dbname");
String driverClassName = DatabaseDriver.fromJdbcUrl(
"jdbc:postgresql://hostname/dbname").getDriverClassName();
assertEquals("org.postgresql.Driver", driverClassName);
}
@Test
public void nullForUnknownDatabase() {
String driverClassName = this.provider
.getDriverClassName("jdbc:unknowndb://hostname/dbname");
public void nullClassNameForUnknownDatabase() {
String driverClassName = DatabaseDriver.fromJdbcUrl(
"jdbc:unknowndb://hostname/dbname").getDriverClassName();
assertNull(driverClassName);
}
@Test
public void failureOnNullJdbcUrl() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("JdbcUrl must not be null");
this.provider.getDriverClassName(null);
public void unknownOnNullJdbcUrl() {
assertThat(DatabaseDriver.fromJdbcUrl(null), equalTo(DatabaseDriver.UNKNOWN));
}
@Test
public void failureOnMalformedJdbcUrl() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("JdbcUrl must start with");
this.provider.getDriverClassName("malformed:url");
this.thrown.expectMessage("URL must start with");
DatabaseDriver.fromJdbcUrl("malformed:url");
}
}

128
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/XADataSourceAutoConfigurationTests.java

@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import org.hsqldb.jdbc.pool.JDBCXADataSource;
import org.junit.Test;
import org.springframework.boot.jta.XADataSourceWrapper;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link XADataSourceAutoConfiguration}.
*
* @author Phillip Webb
*/
public class XADataSourceAutoConfigurationTests {
@Test
public void wrapExistingXaDataSource() throws Exception {
ApplicationContext context = createContext(WrapExisting.class);
context.getBean(DataSource.class);
XADataSource source = context.getBean(XADataSource.class);
MockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);
assertThat(wrapper.getXaDataSource(), equalTo(source));
}
@Test
public void createFromUrl() throws Exception {
ApplicationContext context = createContext(FromProperties.class,
"spring.datasource.url:jdbc:hsqldb:mem:test",
"spring.datasource.username:un");
context.getBean(DataSource.class);
MockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);
JDBCXADataSource dataSource = (JDBCXADataSource) wrapper.getXaDataSource();
assertNotNull(dataSource);
assertThat(dataSource.getUrl(), equalTo("jdbc:hsqldb:mem:test"));
assertThat(dataSource.getUser(), equalTo("un"));
}
@Test
public void createFromClass() throws Exception {
ApplicationContext context = createContext(
FromProperties.class,
"spring.datasource.xa.data-source-class:org.hsqldb.jdbc.pool.JDBCXADataSource",
"spring.datasource.xa.properties.database-name:test");
context.getBean(DataSource.class);
MockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);
JDBCXADataSource dataSource = (JDBCXADataSource) wrapper.getXaDataSource();
assertNotNull(dataSource);
assertThat(dataSource.getDatabaseName(), equalTo("test"));
}
private ApplicationContext createContext(Class<?> configuration, String... env) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, env);
context.register(configuration, XADataSourceAutoConfiguration.class);
context.refresh();
return context;
}
@Configuration
static class WrapExisting {
@Bean
public MockXADataSourceWrapper wrapper() {
return new MockXADataSourceWrapper();
}
@Bean
public XADataSource xaDataSource() {
return mock(XADataSource.class);
}
}
@Configuration
static class FromProperties {
@Bean
public MockXADataSourceWrapper wrapper() {
return new MockXADataSourceWrapper();
}
}
private static class MockXADataSourceWrapper implements XADataSourceWrapper {
private XADataSource dataSource;
@Override
public DataSource wrapDataSource(XADataSource dataSource) {
this.dataSource = dataSource;
return mock(DataSource.class);
}
public XADataSource getXaDataSource() {
return this.dataSource;
}
}
}
Loading…
Cancel
Save