From ba2bac17de41d30215d765c791da1f497f957494 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sat, 2 Oct 2010 06:30:05 +0000 Subject: [PATCH] SPR-7604 - Support multiple embedded databases. Embedded datasources now get their bean ids set as database name to allow multiple databases of the same type in parallel. Refactored tests a little and made BeanDefinitionParser package private to align with the other ones. Adapted changelog accordingly. --- .../resources/changelog.txt | 2 + .../EmbeddedDatabaseBeanDefinitionParser.java | 13 ++++- .../config/JdbcNamespaceIntegrationTest.java | 55 +++++++++++++------ 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/build-spring-framework/resources/changelog.txt b/build-spring-framework/resources/changelog.txt index 9223b07e86b..1886f1785d4 100644 --- a/build-spring-framework/resources/changelog.txt +++ b/build-spring-framework/resources/changelog.txt @@ -18,6 +18,8 @@ Changes in version 3.0.5 (2010-10-13) * AspectJExpressionPointcut uses bean ClassLoader for initializing the AspectJ pointcut parser * JDBC bundle uses local ClassLoader as bean ClassLoader for "sql-error-codes.xml" parsing * EmbeddedDatabaseFactory shuts down database when failing to populate it in "initDatabase()" +* embedded database support now also works with Derby >= 10.6 +* "jdbc:embedded-database" uses id as database name to allow multiple ones in parallel * DefaultLobHandler's "wrapAsLob" mode works with PostgreSQL's "getAsciiStream()" requirement * ResultSetWrappingSqlRowSet (as used by JdbcTemplate's "queryForRowSet") supports column labels now * LocalSessionFactoryBean's "entityCacheStrategies" works with region names on Hibernate 3.6 as well diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/EmbeddedDatabaseBeanDefinitionParser.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/EmbeddedDatabaseBeanDefinitionParser.java index f31131907f6..9e6e9d3f5e8 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/EmbeddedDatabaseBeanDefinitionParser.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/EmbeddedDatabaseBeanDefinitionParser.java @@ -38,16 +38,27 @@ import org.w3c.dom.Element; * @author Oliver Gierke * @since 3.0 */ -public class EmbeddedDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser { +class EmbeddedDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser { + + private static final String NAME_PROPERTY = "databaseName"; @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(EmbeddedDatabaseFactoryBean.class); setDatabaseType(element, builder); setDatabasePopulator(element, context, builder); + useIdAsDatabaseNameIfGiven(element, builder); return getSourcedBeanDefinition(builder, element, context); } + private void useIdAsDatabaseNameIfGiven(Element element, BeanDefinitionBuilder builder) { + + String id = element.getAttribute(ID_ATTRIBUTE); + if (StringUtils.hasText(id)) { + builder.addPropertyValue(NAME_PROPERTY, id); + } + } + private void setDatabaseType(Element element, BeanDefinitionBuilder builder) { String type = element.getAttribute("type"); if (StringUtils.hasText(type)) { diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/JdbcNamespaceIntegrationTest.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/JdbcNamespaceIntegrationTest.java index 22d189a9ad5..7ef895d8f72 100644 --- a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/JdbcNamespaceIntegrationTest.java +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/JdbcNamespaceIntegrationTest.java @@ -1,11 +1,18 @@ package org.springframework.jdbc.config; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import javax.sql.DataSource; import org.junit.Test; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.core.JdbcTemplate; public class JdbcNamespaceIntegrationTest { @@ -14,13 +21,7 @@ public class JdbcNamespaceIntegrationTest { public void testCreateEmbeddedDatabase() throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "org/springframework/jdbc/config/jdbc-config.xml"); - try { - assertCorrectSetup(context.getBean("dataSource", DataSource.class)); - assertCorrectSetup(context.getBean("h2DataSource", DataSource.class)); - assertCorrectSetup(context.getBean("derbyDataSource", DataSource.class)); - } finally { - context.close(); - } + assertCorrectSetup(context, "dataSource", "h2DataSource", "derbyDataSource"); } @Test @@ -28,26 +29,44 @@ public class JdbcNamespaceIntegrationTest { // If Derby isn't cleaned up properly this will fail... ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "org/springframework/jdbc/config/jdbc-config.xml"); - try { - assertCorrectSetup(context.getBean("derbyDataSource", DataSource.class)); - } finally { - context.close(); - } + assertCorrectSetup(context, "derbyDataSource"); } @Test public void testCreateWithResourcePattern() throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "org/springframework/jdbc/config/jdbc-config-pattern.xml"); + assertCorrectSetup(context, "dataSource"); + } + + @Test + public void testMultipleDataSourcesHaveDifferentDatabaseNames() throws Exception { + + DefaultListableBeanFactory factory = new XmlBeanFactory(new ClassPathResource( + "org/springframework/jdbc/config/jdbc-config-multiple-datasources.xml")); + + assertBeanPropertyValueOf("databaseName", "firstDataSource", factory); + assertBeanPropertyValueOf("databaseName", "secondDataSource", factory); + } + + private void assertBeanPropertyValueOf(String propertyName, String expected, DefaultListableBeanFactory factory) { + + BeanDefinition bean = factory.getBeanDefinition(expected); + PropertyValue value = bean.getPropertyValues().getPropertyValue(propertyName); + assertThat(value, is(notNullValue())); + assertThat(value.getValue().toString(), is(expected)); + } + + private void assertCorrectSetup(ConfigurableApplicationContext context, String... dataSources) { + try { - assertCorrectSetup(context.getBean("dataSource", DataSource.class)); + for (String dataSourceName : dataSources) { + DataSource dataSource = context.getBean(dataSourceName, DataSource.class); + JdbcTemplate t = new JdbcTemplate(dataSource); + assertEquals(1, t.queryForInt("select count(*) from T_TEST")); + } } finally { context.close(); } } - - private void assertCorrectSetup(DataSource dataSource) { - JdbcTemplate t = new JdbcTemplate(dataSource); - assertEquals(1, t.queryForInt("select count(*) from T_TEST")); - } }