Browse Source
Moved populator to init package and added namespace features git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@2227 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/head
24 changed files with 512 additions and 47 deletions
@ -0,0 +1,109 @@
@@ -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<Element> scripts = DomUtils.getChildElementsByTagName(element, "script"); |
||||
if (scripts.size() > 0) { |
||||
builder.addPropertyValue("databasePopulator", createDatabasePopulator(element, scripts, context)); |
||||
} |
||||
} |
||||
|
||||
private DatabasePopulator createDatabasePopulator(Element element, List<Element> 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<Resource> resources = new ArrayList<Resource>(Arrays.asList(((ResourcePatternResolver)resourceLoader).getResources(location))); |
||||
Collections.<Resource>sort(resources, new Comparator<Resource>() { |
||||
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; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,76 @@
@@ -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()); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,100 @@
@@ -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<Map<String,Object>> cache; |
||||
|
||||
public void setDataSource(DataSource dataSource) { |
||||
this.jdbcTemplate = new JdbcTemplate(dataSource); |
||||
} |
||||
|
||||
public List<Map<String,Object>> getCachedData() { |
||||
return cache; |
||||
} |
||||
|
||||
public void afterPropertiesSet() throws Exception { |
||||
cache = jdbcTemplate.queryForList("SELECT * FROM T_TEST"); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
drop table T_TEST; |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
update T_TEST set NAME='Dave' where name='Keith'; |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
||||
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> |
||||
|
||||
<jdbc:embedded-database id="dataSource" type="HSQL"/> |
||||
|
||||
<jdbc:initialize-database data-source="dataSource"> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/> |
||||
</jdbc:initialize-database> |
||||
|
||||
<!-- This cache relies on data created in the initialize-database element. It works fine |
||||
if the bean definitions are registered in the right order. (Could possibly be fixed later.) --> |
||||
<bean class="org.springframework.jdbc.config.InitializeDatabaseIntegrationTest$CacheData"> |
||||
<property name="dataSource" ref="dataSource"/> |
||||
</bean> |
||||
|
||||
</beans> |
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
||||
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> |
||||
|
||||
<jdbc:embedded-database id="dataSource" type="HSQL"/> |
||||
|
||||
<jdbc:initialize-database data-source="dataSource" enabled="#{systemProperties['ENABLED']}"> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/> |
||||
</jdbc:initialize-database> |
||||
|
||||
</beans> |
||||
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
||||
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> |
||||
|
||||
<jdbc:embedded-database id="dataSource" type="HSQL"/> |
||||
|
||||
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS"> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-drops.sql"/> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/> |
||||
</jdbc:initialize-database> |
||||
|
||||
</beans> |
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
||||
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> |
||||
|
||||
<jdbc:embedded-database id="dataSource" type="HSQL"/> |
||||
|
||||
<jdbc:initialize-database data-source="dataSource"> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/> |
||||
<jdbc:script location="classpath:org/springframework/jdbc/config/*-data.sql"/> |
||||
</jdbc:initialize-database> |
||||
|
||||
</beans> |
||||
Loading…
Reference in new issue