From 0db68e1b576c78b9c43fb53129c1c5a5db83a3c2 Mon Sep 17 00:00:00 2001 From: David Syer Date: Fri, 30 Oct 2009 10:31:37 +0000 Subject: [PATCH] RESOLVED - issue SPR-5917: DataSourceInitializer and namespace support for creating and populating databases Moved populator to init package and added namespace features --- .../EmbeddedDatabaseBeanDefinitionParser.java | 4 +- ...nitializeDatabaseBeanDefinitionParser.java | 109 ++++++++++++++++ .../jdbc/config/JdbcNamespaceHandler.java | 2 + .../embedded/EmbeddedDatabaseBuilder.java | 1 + .../embedded/EmbeddedDatabaseFactory.java | 1 + .../CannotReadScriptException.java | 2 +- .../init/DataSourceInitializer.java | 76 +++++++++++ .../{embedded => init}/DatabasePopulator.java | 2 +- .../ResourceDatabasePopulator.java | 56 +++++--- .../jdbc/config/spring-jdbc-3.0.xsd | 122 +++++++++++++++--- .../InitializeDatabaseIntegrationTest.java | 100 ++++++++++++++ .../EmbeddedDatabaseBuilderTests.java | 1 + .../EmbeddedDatabaseFactoryBeanTests.java | 1 + .../EmbeddedDatabaseFactoryTests.java | 1 + .../springframework/jdbc/config/db-drops.sql | 1 + .../embedded => config}/db-schema-derby.sql | 0 .../embedded => config}/db-schema.sql | 0 .../embedded => config}/db-test-data.sql | 0 .../jdbc/config/db-update-data.sql | 1 + .../jdbc/config/jdbc-config.xml | 12 +- .../config/jdbc-initialize-cache-config.xml | 21 +++ .../jdbc/config/jdbc-initialize-config.xml | 15 +++ .../config/jdbc-initialize-fail-config.xml | 16 +++ .../config/jdbc-initialize-pattern-config.xml | 15 +++ 24 files changed, 512 insertions(+), 47 deletions(-) create mode 100644 org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java rename org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/{embedded => init}/CannotReadScriptException.java (95%) create mode 100644 org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java rename org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/{embedded => init}/DatabasePopulator.java (95%) rename org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/{embedded => init}/ResourceDatabasePopulator.java (82%) create mode 100644 org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/InitializeDatabaseIntegrationTest.java create mode 100644 org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-drops.sql rename org.springframework.jdbc/src/test/resources/org/springframework/jdbc/{datasource/embedded => config}/db-schema-derby.sql (100%) rename org.springframework.jdbc/src/test/resources/org/springframework/jdbc/{datasource/embedded => config}/db-schema.sql (100%) rename org.springframework.jdbc/src/test/resources/org/springframework/jdbc/{datasource/embedded => config}/db-test-data.sql (100%) create mode 100644 org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-update-data.sql create mode 100644 org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-cache-config.xml create mode 100644 org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-config.xml create mode 100644 org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-fail-config.xml create mode 100644 org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-pattern-config.xml 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 51a0451153f..e18b4adab2b 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 @@ -24,9 +24,9 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.io.Resource; -import org.springframework.jdbc.datasource.embedded.DatabasePopulator; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean; -import org.springframework.jdbc.datasource.embedded.ResourceDatabasePopulator; +import org.springframework.jdbc.datasource.init.DatabasePopulator; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java new file mode 100644 index 00000000000..1e268d3f8e5 --- /dev/null +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java @@ -0,0 +1,109 @@ +/* + * Copyright 2002-2009 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.jdbc.config; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.jdbc.datasource.init.DataSourceInitializer; +import org.springframework.jdbc.datasource.init.DatabasePopulator; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses {@code initialize-database} element and + * creates a {@link BeanDefinition} for {@link DataSourceInitializer}. Picks up nested {@code script} elements and + * configures a {@link ResourceDatabasePopulator} for them. +@author Dave Syer + * + */ +public class InitializeDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser { + + @Override + protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSourceInitializer.class); + builder.addPropertyReference("dataSource", element.getAttribute("data-source")); + builder.addPropertyValue("enabled", element.getAttribute("enabled")); + setDatabasePopulator(element, context, builder); + return getSourcedBeanDefinition(builder, element, context); + } + + @Override + protected boolean shouldGenerateId() { + return true; + } + + private void setDatabasePopulator(Element element, ParserContext context, BeanDefinitionBuilder builder) { + List scripts = DomUtils.getChildElementsByTagName(element, "script"); + if (scripts.size() > 0) { + builder.addPropertyValue("databasePopulator", createDatabasePopulator(element, scripts, context)); + } + } + + private DatabasePopulator createDatabasePopulator(Element element, List scripts, ParserContext context) { + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.setIgnoreFailedDrops(element.getAttribute("ignore-failures").equals("DROPS")); + populator.setContinueOnError(element.getAttribute("ignore-failures").equals("ALL")); + for (Element scriptElement : scripts) { + String location = scriptElement.getAttribute("location"); + ResourceLoader resourceLoader = context.getReaderContext().getResourceLoader(); + if (resourceLoader instanceof ResourcePatternResolver) { + try { + List resources = new ArrayList(Arrays.asList(((ResourcePatternResolver)resourceLoader).getResources(location))); + Collections.sort(resources, new Comparator() { + public int compare(Resource o1, Resource o2) { + try { + return o1.getURL().toString().compareTo(o2.getURL().toString()); + } catch (IOException e) { + return 0; + } + } + }); + for (Resource resource : resources) { + populator.addScript(resource); + } + } catch (IOException e) { + context.getReaderContext().error("Cannot locate resources for script from location="+location, scriptElement); + } + } else { + populator.addScript(resourceLoader.getResource(location)); + } + } + return populator; + } + + private AbstractBeanDefinition getSourcedBeanDefinition(BeanDefinitionBuilder builder, Element source, + ParserContext context) { + AbstractBeanDefinition definition = builder.getBeanDefinition(); + definition.setSource(context.extractSource(source)); + return definition; + } + +} diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/JdbcNamespaceHandler.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/JdbcNamespaceHandler.java index e03b2ceb2e6..3674dfbaa75 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/JdbcNamespaceHandler.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/JdbcNamespaceHandler.java @@ -22,10 +22,12 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * {@link NamespaceHandler} for JDBC configuration namespace. * @author Oliver Gierke + * @author Dave Syer */ public class JdbcNamespaceHandler extends NamespaceHandlerSupport { public void init() { registerBeanDefinitionParser("embedded-database", new EmbeddedDatabaseBeanDefinitionParser()); + registerBeanDefinitionParser("initialize-database", new InitializeDatabaseBeanDefinitionParser()); } } diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilder.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilder.java index 7bd98c04e8b..5870e01d5cd 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilder.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilder.java @@ -19,6 +19,7 @@ package org.springframework.jdbc.datasource.embedded; import org.springframework.core.io.ClassRelativeResourceLoader; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; /** * A builder that provides a fluent API for constructing an embedded database. diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java index 12c78d0d330..1daf03e076e 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java @@ -25,6 +25,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.jdbc.datasource.init.DatabasePopulator; import org.springframework.util.Assert; /** diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/CannotReadScriptException.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/CannotReadScriptException.java similarity index 95% rename from org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/CannotReadScriptException.java rename to org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/CannotReadScriptException.java index dd2ae82ff9f..4f7414cbbd9 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/CannotReadScriptException.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/CannotReadScriptException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.jdbc.datasource.embedded; +package org.springframework.jdbc.datasource.init; import org.springframework.core.io.support.EncodedResource; diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java new file mode 100644 index 00000000000..041b6bb274c --- /dev/null +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2009 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.jdbc.datasource.init; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; + +/** + * Used to populate a database during initialization. + * @author Dave Syer + * @since 3.0 + * @see DatabasePopulator + */ +public class DataSourceInitializer implements InitializingBean { + + private DataSource dataSource; + + private DatabasePopulator databasePopulator; + + private boolean enabled = true; + + /** + * Flag to explicitly enable or disable the database populator. + * + * @param enabled true if the database populator will be called on startup + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * The {@link DatabasePopulator} to use to populate the data source. Mandatory with no default. + * + * @param databasePopulator the database populator to use. + */ + public void setDatabasePopulator(DatabasePopulator databasePopulator) { + this.databasePopulator = databasePopulator; + } + + /** + * The {@link DataSource} to populate when this component is initialized. Mandatory with no default. + * + * @param dataSource the DataSource + */ + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + /** + * Use the populator to set up data in the data source. Both properties are mandatory with no defaults. + * + * @see InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + if (enabled) { + Assert.state(dataSource != null, "DataSource must be provided"); + Assert.state(databasePopulator != null, "DatabasePopulator must be provided"); + databasePopulator.populate(dataSource.getConnection()); + } + } +} \ No newline at end of file diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/DatabasePopulator.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DatabasePopulator.java similarity index 95% rename from org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/DatabasePopulator.java rename to org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DatabasePopulator.java index e5a3bad750d..5f7881ca319 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/DatabasePopulator.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DatabasePopulator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.jdbc.datasource.embedded; +package org.springframework.jdbc.datasource.init; import java.sql.Connection; import java.sql.SQLException; diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/ResourceDatabasePopulator.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java similarity index 82% rename from org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/ResourceDatabasePopulator.java rename to org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java index cfbefb60a33..8813850a64b 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/ResourceDatabasePopulator.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.jdbc.datasource.embedded; +package org.springframework.jdbc.datasource.init; import java.io.IOException; import java.io.LineNumberReader; @@ -28,7 +28,6 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.core.io.Resource; import org.springframework.core.io.support.EncodedResource; import org.springframework.util.StringUtils; @@ -40,6 +39,7 @@ import org.springframework.util.StringUtils; * Call {@link #setSqlScriptEncoding(String)} to set the encoding for all added scripts.
* * @author Keith Donald + * @author Dave Syer * @since 3.0 */ public class ResourceDatabasePopulator implements DatabasePopulator { @@ -50,6 +50,9 @@ public class ResourceDatabasePopulator implements DatabasePopulator { private String sqlScriptEncoding; + private boolean ignoreFailedDrops = false; + + private boolean continueOnError = false; /** * Add a script to execute to populate the database. @@ -66,6 +69,29 @@ public class ResourceDatabasePopulator implements DatabasePopulator { public void setScripts(Resource[] scripts) { this.scripts = Arrays.asList(scripts); } + + /** + * Flag to indicate that all failures in SQL should be logged but not cause a + * failure. Defaults to false. + * + * @param continueOnError the flag value to set + */ + public void setContinueOnError(boolean continueOnError) { + this.continueOnError = continueOnError; + } + + /** + * Flag to indicate that a failed SQL DROP statement can be ignored. + * This is useful for non-embedded databases whose SQL dialect does not support + * an IF EXISTS clause in a DROP. The default is false + * so that if it the populator runs accidentally against an existing database it + * will fail fast when the script starts with a DROP. + * + * @param ignoreFailedDrops the flag value to set + */ + public void setIgnoreFailedDrops(boolean ignoreFailedDrops) { + this.ignoreFailedDrops = ignoreFailedDrops; + } /** * Specify the encoding for SQL scripts, if different from the platform encoding. @@ -77,30 +103,29 @@ public class ResourceDatabasePopulator implements DatabasePopulator { this.sqlScriptEncoding = sqlScriptEncoding; } - public void populate(Connection connection) throws SQLException { for (Resource script : this.scripts) { - executeSqlScript(connection, applyEncodingIfNecessary(script), false); + executeSqlScript(connection, applyEncodingIfNecessary(script), continueOnError, ignoreFailedDrops); } } private EncodedResource applyEncodingIfNecessary(Resource script) { if (script instanceof EncodedResource) { return (EncodedResource) script; - } - else { + } else { return new EncodedResource(script, this.sqlScriptEncoding); } } - + /** * Execute the given SQL script.

The script will normally be loaded by classpath. There should be one statement * per line. Any semicolons will be removed. Do not use this method to execute DDL if you expect rollback. * @param template the SimpleJdbcTemplate with which to perform JDBC operations * @param resource the resource (potentially associated with a specific encoding) to load the SQL script from. * @param continueOnError whether or not to continue without throwing an exception in the event of an error. + * @param ignoreFailedDrops whether of not to continue in thw event of specifically an error on a DROP. */ - private void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError) + private void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError, boolean ignoreFailedDrops) throws SQLException { if (logger.isInfoEnabled()) { @@ -129,24 +154,21 @@ public class ResourceDatabasePopulator implements DatabasePopulator { if (logger.isDebugEnabled()) { logger.debug(rowsAffected + " rows affected by SQL: " + statement); } - } - catch (SQLException ex) { - if (continueOnError) { + } catch (SQLException ex) { + boolean dropStatement = statement.trim().toLowerCase().startsWith("drop"); + if (continueOnError || (dropStatement && ignoreFailedDrops)) { if (logger.isWarnEnabled()) { logger.warn("Line " + lineNumber + " statement failed: " + statement, ex); } - } - else { + } else { throw ex; } } } - } - finally { + } finally { try { stmt.close(); - } - catch (Throwable ex) { + } catch (Throwable ex) { logger.debug("Could not close JDBC Statement", ex); } } diff --git a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd index 2e8056441db..3a5df3cffbb 100644 --- a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd +++ b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd @@ -1,20 +1,21 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" + xmlns:tool="http://www.springframework.org/schema/tool" + targetNamespace="http://www.springframework.org/schema/jdbc" + elementFormDefault="qualified" attributeFormDefault="unqualified"> - - + + - + ]]> @@ -25,33 +26,114 @@ - + - + - + - + + + + elements. + ]]> + + + + + + + + + + + + + + + + + + + + + + Is this bean "enabled", that is, will the + scripts be executed? + Defaults to true, but can be used to switch on + and off the + initialization depending on the enviroment. + + + + + + + Should failed SQL statements be ignored during initialization? + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -62,21 +144,21 @@ - + - + - + diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/InitializeDatabaseIntegrationTest.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/InitializeDatabaseIntegrationTest.java new file mode 100644 index 00000000000..4ed781acc0c --- /dev/null +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/config/InitializeDatabaseIntegrationTest.java @@ -0,0 +1,100 @@ +package org.springframework.jdbc.config; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.core.JdbcTemplate; + +public class InitializeDatabaseIntegrationTest { + + private String enabled; + private ClassPathXmlApplicationContext context; + + @Before + public void init() { + enabled = System.setProperty("ENABLED", "true"); + } + + @After + public void after() { + if (enabled != null) { + System.setProperty("ENABLED", enabled); + } else { + System.clearProperty("ENABLED"); + } + if (context != null) { + context.close(); + } + } + + @Test + public void testCreateEmbeddedDatabase() throws Exception { + context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-config.xml"); + assertCorrectSetup(context.getBean("dataSource", DataSource.class)); + } + + @Test(expected = BadSqlGrammarException.class) + public void testDisableCreateEmbeddedDatabase() throws Exception { + System.setProperty("ENABLED", "false"); + context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-config.xml"); + assertCorrectSetup(context.getBean("dataSource", DataSource.class)); + } + + @Test + public void testIgnoreFailedDrops() throws Exception { + context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-fail-config.xml"); + assertCorrectSetup(context.getBean("dataSource", DataSource.class)); + } + + @Test + public void testScriptNameWithPattern() throws Exception { + context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-pattern-config.xml"); + DataSource dataSource = context.getBean("dataSource", DataSource.class); + assertCorrectSetup(dataSource); + JdbcTemplate t = new JdbcTemplate(dataSource); + assertEquals("Dave", t.queryForObject("select name from T_TEST", String.class)); + } + + @Test + public void testCacheInitialization() throws Exception { + context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-cache-config.xml"); + assertCorrectSetup(context.getBean("dataSource", DataSource.class)); + CacheData cache = context.getBean(CacheData.class); + assertEquals(1, cache.getCachedData().size()); + } + + private void assertCorrectSetup(DataSource dataSource) { + JdbcTemplate t = new JdbcTemplate(dataSource); + assertEquals(1, t.queryForInt("select count(*) from T_TEST")); + } + + public static class CacheData implements InitializingBean { + + private JdbcTemplate jdbcTemplate; + private List> cache; + + public void setDataSource(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + public List> getCachedData() { + return cache; + } + + public void afterPropertiesSet() throws Exception { + cache = jdbcTemplate.queryForList("SELECT * FROM T_TEST"); + } + + } + +} diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilderTests.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilderTests.java index 7b7ca46a188..78043d842ba 100644 --- a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilderTests.java +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseBuilderTests.java @@ -7,6 +7,7 @@ import static org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType. import org.junit.Test; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.init.CannotReadScriptException; public class EmbeddedDatabaseBuilderTests { diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBeanTests.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBeanTests.java index 7ec34cfe594..1ad8cbd86fb 100644 --- a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBeanTests.java +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBeanTests.java @@ -8,6 +8,7 @@ import org.junit.Test; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; public class EmbeddedDatabaseFactoryBeanTests { diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryTests.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryTests.java index 3c0860052b3..f3e85fb790c 100644 --- a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryTests.java +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryTests.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertTrue; import java.sql.Connection; import org.junit.Test; +import org.springframework.jdbc.datasource.init.DatabasePopulator; public class EmbeddedDatabaseFactoryTests { diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-drops.sql b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-drops.sql new file mode 100644 index 00000000000..a19743fc57f --- /dev/null +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-drops.sql @@ -0,0 +1 @@ +drop table T_TEST; diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/datasource/embedded/db-schema-derby.sql b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-schema-derby.sql similarity index 100% rename from org.springframework.jdbc/src/test/resources/org/springframework/jdbc/datasource/embedded/db-schema-derby.sql rename to org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-schema-derby.sql diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/datasource/embedded/db-schema.sql b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-schema.sql similarity index 100% rename from org.springframework.jdbc/src/test/resources/org/springframework/jdbc/datasource/embedded/db-schema.sql rename to org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-schema.sql diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/datasource/embedded/db-test-data.sql b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-test-data.sql similarity index 100% rename from org.springframework.jdbc/src/test/resources/org/springframework/jdbc/datasource/embedded/db-test-data.sql rename to org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-test-data.sql diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-update-data.sql b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-update-data.sql new file mode 100644 index 00000000000..db1bd5ed042 --- /dev/null +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/db-update-data.sql @@ -0,0 +1 @@ +update T_TEST set NAME='Dave' where name='Keith'; \ No newline at end of file diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-config.xml b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-config.xml index 44c66eba6bf..5a89b9183b7 100644 --- a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-config.xml +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-config.xml @@ -6,18 +6,18 @@ http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> - - + + - - + + - - + + diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-cache-config.xml b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-cache-config.xml new file mode 100644 index 00000000000..01897f217b5 --- /dev/null +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-cache-config.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-config.xml b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-config.xml new file mode 100644 index 00000000000..bf31c320cca --- /dev/null +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-fail-config.xml b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-fail-config.xml new file mode 100644 index 00000000000..45ee2a972bd --- /dev/null +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-fail-config.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-pattern-config.xml b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-pattern-config.xml new file mode 100644 index 00000000000..b03490899d6 --- /dev/null +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/config/jdbc-initialize-pattern-config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + +