diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/liquibase/LiquibaseEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/liquibase/LiquibaseEndpointTests.java index 800cdb1af9d1..4410b30f27e5 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/liquibase/LiquibaseEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/liquibase/LiquibaseEndpointTests.java @@ -32,8 +32,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; -import org.springframework.boot.jdbc.init.DataSourceInitializationSettings; -import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -148,9 +148,10 @@ DataSource dataSource() { DataSource dataSource = new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseConnection.get(getClass().getClassLoader()).getType()) .setName(UUID.randomUUID().toString()).build(); - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(Arrays.asList("classpath:/db/create-custom-schema.sql")); - ScriptDataSourceInitializer initializer = new ScriptDataSourceInitializer(dataSource, settings); + DataSourceScriptDatabaseInitializer initializer = new DataSourceScriptDatabaseInitializer(dataSource, + settings); initializer.initializeDatabase(); return dataSource; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java index e4609776ca7e..3a5f847b6e2b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java @@ -41,9 +41,9 @@ import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceInitializationMode; import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; -import org.springframework.boot.jdbc.init.DataSourceInitializationSettings; -import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.DependsOn; @@ -56,7 +56,7 @@ /** * Configuration for {@link DataSource} initialization using a - * {@link ScriptDataSourceInitializer} with DDL and DML scripts. + * {@link DataSourceScriptDatabaseInitializer} with DDL and DML scripts. * * @author Andy Wilkinson */ @@ -87,13 +87,13 @@ private static List scriptLocations(List locations, String fallb @org.springframework.context.annotation.Conditional(DifferentCredentialsCondition.class) @org.springframework.context.annotation.Import(DataSourceInitializationDependencyConfigurer.class) @ConditionalOnSingleCandidate(DataSource.class) - @ConditionalOnMissingBean(ScriptDataSourceInitializer.class) + @ConditionalOnMissingBean(DataSourceScriptDatabaseInitializer.class) static class InitializationSpecificCredentialsDataSourceInitializationConfiguration { @Bean - ScriptDataSourceInitializer ddlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, + DataSourceScriptDatabaseInitializer ddlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, DataSourceProperties properties, ResourceLoader resourceLoader) { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(scriptLocations(properties.getSchema(), "schema", properties.getPlatform())); settings.setContinueOnError(properties.isContinueOnError()); settings.setSeparator(properties.getSeparator()); @@ -106,9 +106,9 @@ ScriptDataSourceInitializer ddlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, + DataSourceScriptDatabaseInitializer dmlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, DataSourceProperties properties, ResourceLoader resourceLoader) { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setDataLocations(scriptLocations(properties.getData(), "data", properties.getPlatform())); settings.setContinueOnError(properties.isContinueOnError()); settings.setSeparator(properties.getSeparator()); @@ -144,13 +144,13 @@ static class DataCredentials { @org.springframework.context.annotation.Import(DataSourceInitializationDependencyConfigurer.class) @org.springframework.context.annotation.Conditional(DataSourceInitializationCondition.class) @ConditionalOnSingleCandidate(DataSource.class) - @ConditionalOnMissingBean(ScriptDataSourceInitializer.class) + @ConditionalOnMissingBean(DataSourceScriptDatabaseInitializer.class) static class SharedCredentialsDataSourceInitializationConfiguration { @Bean - ScriptDataSourceInitializer scriptDataSourceInitializer(DataSource dataSource, DataSourceProperties properties, - ResourceLoader resourceLoader) { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DataSourceScriptDatabaseInitializer scriptDataSourceInitializer(DataSource dataSource, + DataSourceProperties properties, ResourceLoader resourceLoader) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(scriptLocations(properties.getSchema(), "schema", properties.getPlatform())); settings.setDataLocations(scriptLocations(properties.getData(), "data", properties.getPlatform())); settings.setContinueOnError(properties.isContinueOnError()); @@ -188,12 +188,12 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeM } - static class InitializationModeDataSourceScriptDatabaseInitializer extends ScriptDataSourceInitializer { + static class InitializationModeDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { private final DataSourceInitializationMode mode; InitializationModeDataSourceScriptDatabaseInitializer(DataSource dataSource, - DataSourceInitializationSettings settings, DataSourceInitializationMode mode) { + DatabaseInitializationSettings settings, DataSourceInitializationMode mode) { super(dataSource, settings); this.mode = mode; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java index 87b864e78151..c723d29c676f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java @@ -29,9 +29,9 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.jdbc.init.DataSourceInitializationSettings; -import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -45,7 +45,7 @@ * @since 2.5.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnMissingBean(ScriptDataSourceInitializer.class) +@ConditionalOnMissingBean(DataSourceScriptDatabaseInitializer.class) @ConditionalOnSingleCandidate(DataSource.class) @ConditionalOnProperty(prefix = "spring.sql.init", name = "enabled", matchIfMissing = true) @AutoConfigureAfter(DataSourceAutoConfiguration.class) @@ -54,15 +54,15 @@ public class SqlInitializationAutoConfiguration { @Bean - ScriptDataSourceInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, + DataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, SqlInitializationProperties initializationProperties) { - DataSourceInitializationSettings settings = createSettings(initializationProperties); - return new ScriptDataSourceInitializer(determineDataSource(dataSource, initializationProperties.getUsername(), - initializationProperties.getPassword()), settings); + DatabaseInitializationSettings settings = createSettings(initializationProperties); + return new DataSourceScriptDatabaseInitializer(determineDataSource(dataSource, + initializationProperties.getUsername(), initializationProperties.getPassword()), settings); } - private static DataSourceInitializationSettings createSettings(SqlInitializationProperties properties) { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + private static DatabaseInitializationSettings createSettings(SqlInitializationProperties properties) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations( scriptLocations(properties.getSchemaLocations(), "schema", properties.getPlatform())); settings.setDataLocations(scriptLocations(properties.getDataLocations(), "data", properties.getPlatform())); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java index 8010165e47e3..7a94d57d2d7d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java @@ -43,7 +43,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; -import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitialization; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; @@ -240,14 +240,15 @@ void whenThereIsAnEmptyUserProvidedDataSource() { void testDataSourceIsInitializedEarly() { this.contextRunner.withUserConfiguration(TestInitializedDataSourceConfiguration.class) .withPropertyValues("spring.datasource.initialization-mode=always").run((context) -> { - assertThat(context).hasSingleBean(ScriptDataSourceInitializer.class); + assertThat(context).hasSingleBean(DataSourceScriptDatabaseInitializer.class); assertThat(context.getBean(TestInitializedDataSourceConfiguration.class).called).isTrue(); }); } @Test void whenNoInitializationRelatedSpringDataSourcePropertiesAreConfiguredThenInitializationBacksOff() { - this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ScriptDataSourceInitializer.class)); + this.contextRunner + .run((context) -> assertThat(context).doesNotHaveBean(DataSourceScriptDatabaseInitializer.class)); } private static Function hideConnectionPools() { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java new file mode 100644 index 000000000000..d453c7a4bee9 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.jdbc.init; + +import java.nio.charset.Charset; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.core.io.Resource; +import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; + +/** + * {@link InitializingBean} that performs {@link DataSource} initialization using schema + * (DDL) and data (DML) scripts. + * + * @author Andy Wilkinson + * @since 2.5.0 + */ +public class DataSourceScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer { + + private final DataSource dataSource; + + /** + * Creates a new {@link DataSourceScriptDatabaseInitializer} that will initialize the + * given {@code DataSource} using the given settings. + * @param dataSource data source to initialize + * @param settings initialization settings + */ + public DataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) { + super(settings); + this.dataSource = dataSource; + } + + /** + * Returns the {@code DataSource} that will be initialized. + * @return the initialization data source + */ + protected final DataSource getDataSource() { + return this.dataSource; + } + + @Override + protected void runScripts(List resources, boolean continueOnError, String separator, Charset encoding) { + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.setContinueOnError(continueOnError); + populator.setSeparator(separator); + if (encoding != null) { + populator.setSqlScriptEncoding(encoding.name()); + } + for (Resource resource : resources) { + populator.addScript(resource); + } + DatabasePopulatorUtils.execute(populator, this.dataSource); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializerDetector.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerDetector.java similarity index 78% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializerDetector.java rename to spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerDetector.java index 254d62b25d7b..1cbcb840a52a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializerDetector.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerDetector.java @@ -23,15 +23,16 @@ import org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector; /** - * A {@link DataSourceInitializerDetector} for {@link ScriptDataSourceInitializer}. + * A {@link DataSourceInitializerDetector} for + * {@link DataSourceScriptDatabaseInitializer}. * * @author Andy Wilkinson */ -class ScriptDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector { +class DataSourceScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector { @Override protected Set> getDataSourceInitializerBeanTypes() { - return Collections.singleton(ScriptDataSourceInitializer.class); + return Collections.singleton(DataSourceScriptDatabaseInitializer.class); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/package-info.java index 4495a2b635ba..156ea334f269 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/package-info.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/package-info.java @@ -15,6 +15,7 @@ */ /** - * Support for initializaton of a JDBC {@code DataSource}. + * Support for initializaton of an SQL database using a JDBC {@link javax.sql.DataSource + * DataSource}. */ package org.springframework.boot.jdbc.init; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializer.java new file mode 100644 index 000000000000..fedfea6eeacb --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializer.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.r2dbc.init; + +import java.nio.charset.Charset; +import java.util.List; + +import io.r2dbc.spi.ConnectionFactory; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.core.io.Resource; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; + +/** + * An {@link InitializingBean} that initializes a database represented by an R2DBC + * {@link ConnectionFactory}. + * + * @author Andy Wilkinson + * @since 2.5.0 + */ +public class R2dbcScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer { + + private final ConnectionFactory connectionFactory; + + /** + * Creates a new {@code R2dbcScriptDatabaseInitializer} that will initialize the + * database recognized by the given {@code connectionFactory} using the given + * {@code settings}. + * @param connectionFactory connectionFactory for the database + * @param settings initialization settings + */ + public R2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory, + DatabaseInitializationSettings settings) { + super(settings); + this.connectionFactory = connectionFactory; + } + + @Override + protected void runScripts(List scripts, boolean continueOnError, String separator, Charset encoding) { + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.setContinueOnError(continueOnError); + populator.setSeparator(separator); + if (encoding != null) { + populator.setSqlScriptEncoding(encoding.name()); + } + for (Resource script : scripts) { + populator.addScript(script); + } + populator.populate(this.connectionFactory).block(); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/init/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/init/package-info.java new file mode 100644 index 000000000000..adb8e093f7fb --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/init/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-2021 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 + * + * https://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. + */ + +/** + * Support for initializaton of an SQL database using an R2DBC + * {@link io.r2dbc.spi.ConnectionFactory ConnectionFactory}. + */ +package org.springframework.boot.r2dbc.init; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializer.java similarity index 75% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializer.java rename to spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializer.java index 105133b4011b..cdb36306881d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.jdbc.init; +package org.springframework.boot.sql.init; import java.io.IOException; import java.nio.charset.Charset; @@ -23,54 +23,38 @@ import java.util.Collections; import java.util.List; -import javax.sql.DataSource; - import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; -import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; -import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.util.CollectionUtils; /** - * {@link InitializingBean} that performs {@link DataSource} initialization using schema - * (DDL) and data (DML) scripts. + * Base class for an {@link InitializingBean} that performs SQL database initialization + * using schema (DDL) and data (DML) scripts. * * @author Andy Wilkinson * @since 2.5.0 */ -public class ScriptDataSourceInitializer implements ResourceLoaderAware, InitializingBean { +public abstract class AbstractScriptDatabaseInitializer implements ResourceLoaderAware, InitializingBean { private static final String OPTIONAL_LOCATION_PREFIX = "optional:"; - private final DataSource dataSource; - - private final DataSourceInitializationSettings settings; + private final DatabaseInitializationSettings settings; private volatile ResourceLoader resourceLoader; /** - * Creates a new {@link ScriptDataSourceInitializer} that will initialize the given - * {@code DataSource} using the given settings. - * @param dataSource data source to initialize + * Creates a new {@link AbstractScriptDatabaseInitializer} that will initialize the + * database using the given settings. * @param settings initialization settings */ - public ScriptDataSourceInitializer(DataSource dataSource, DataSourceInitializationSettings settings) { - this.dataSource = dataSource; + protected AbstractScriptDatabaseInitializer(DatabaseInitializationSettings settings) { this.settings = settings; } - /** - * Returns the {@code DataSource} that will be initialized. - * @return the initialization data source - */ - protected final DataSource getDataSource() { - return this.dataSource; - } - @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; @@ -148,18 +132,8 @@ private void runScripts(List resources) { this.settings.getEncoding()); } - protected void runScripts(List resources, boolean continueOnError, String separator, Charset encoding) { - ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); - populator.setContinueOnError(continueOnError); - populator.setSeparator(separator); - if (encoding != null) { - populator.setSqlScriptEncoding(encoding.name()); - } - for (Resource resource : resources) { - populator.addScript(resource); - } - DatabasePopulatorUtils.execute(populator, this.dataSource); - } + protected abstract void runScripts(List resources, boolean continueOnError, String separator, + Charset encoding); private static class ScriptLocationResolver { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceInitializationSettings.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/DatabaseInitializationSettings.java similarity index 94% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceInitializationSettings.java rename to spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/DatabaseInitializationSettings.java index 64e4df3b7285..62193407c2cb 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceInitializationSettings.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/DatabaseInitializationSettings.java @@ -14,20 +14,18 @@ * limitations under the License. */ -package org.springframework.boot.jdbc.init; +package org.springframework.boot.sql.init; import java.nio.charset.Charset; import java.util.List; -import javax.sql.DataSource; - /** - * Settings for initializing a database using a JDBC {@link DataSource}. + * Settings for initializing an SQL database. * * @author Andy Wilkinson * @since 2.5.0 */ -public class DataSourceInitializationSettings { +public class DatabaseInitializationSettings { private List schemaLocations; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/package-info.java new file mode 100644 index 000000000000..a325f9d1b349 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2021 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 + * + * https://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. + */ + +/** + * Support for initializaton of an SQL database. + */ +package org.springframework.boot.sql.init; diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index d0812eefc938..2c562ded8d43 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -82,7 +82,7 @@ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter # DataSource Initializer Detectors org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector=\ org.springframework.boot.flyway.FlywayDataSourceInitializerDetector,\ -org.springframework.boot.jdbc.init.ScriptDataSourceInitializerDetector,\ +org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializerDetector,\ org.springframework.boot.liquibase.LiquibaseDataSourceInitializerDetector,\ org.springframework.boot.orm.jpa.JpaDataSourceInitializerDetector diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerTests.java new file mode 100644 index 000000000000..708c567565cd --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.jdbc.init; + +import java.util.UUID; + +import com.zaxxer.hikari.HikariDataSource; +import org.junit.jupiter.api.AfterEach; + +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializerTests; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * Tests for {@link DataSourceScriptDatabaseInitializer}. + * + * @author Andy Wilkinson + */ +class DataSourceScriptDatabaseInitializerTests extends AbstractScriptDatabaseInitializerTests { + + private final HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class) + .url("jdbc:h2:mem:" + UUID.randomUUID()).build(); + + @AfterEach + void closeDataSource() { + this.dataSource.close(); + } + + @Override + protected AbstractScriptDatabaseInitializer createInitializer(DatabaseInitializationSettings settings) { + return new DataSourceScriptDatabaseInitializer(this.dataSource, settings); + } + + @Override + protected int numberOfRows(String sql) { + return new JdbcTemplate(this.dataSource).queryForObject(sql, Integer.class); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializerTests.java new file mode 100644 index 000000000000..2bc81ff5b211 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializerTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.r2dbc.init; + +import java.util.UUID; + +import io.r2dbc.spi.ConnectionFactory; + +import org.springframework.boot.r2dbc.ConnectionFactoryBuilder; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializerTests; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.r2dbc.core.DatabaseClient; + +/** + * Tests for {@link R2dbcScriptDatabaseInitializer}. + * + * @author Andy Wilkinson + */ +class R2dbcScriptDatabaseInitializerTests extends AbstractScriptDatabaseInitializerTests { + + private final ConnectionFactory connectionFactory = ConnectionFactoryBuilder + .withUrl("r2dbc:h2:mem:///" + UUID.randomUUID() + "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE") + .build(); + + @Override + protected AbstractScriptDatabaseInitializer createInitializer(DatabaseInitializationSettings settings) { + return new R2dbcScriptDatabaseInitializer(this.connectionFactory, settings); + } + + @Override + protected int numberOfRows(String sql) { + return DatabaseClient.create(this.connectionFactory).sql(sql).map((row, metadata) -> row.get(0)).first() + .map((number) -> ((Number) number).intValue()).block(); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializerTests.java similarity index 59% rename from spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializerTests.java rename to spring-boot-project/spring-boot/src/test/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializerTests.java index f235b85abe06..cb1e87d5dc0a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/ScriptDataSourceInitializerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializerTests.java @@ -14,105 +14,88 @@ * limitations under the License. */ -package org.springframework.boot.jdbc.init; +package org.springframework.boot.sql.init; import java.util.Arrays; -import java.util.UUID; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; /** - * Tests for {@link ScriptDataSourceInitializer}. + * Base class for testing {@link AbstractScriptDatabaseInitializer} implementations. * * @author Andy Wilkinson */ -class ScriptDataSourceInitializerTests { - - private final HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class) - .url("jdbc:h2:mem:" + UUID.randomUUID()).build(); - - @AfterEach - void closeDataSource() { - this.dataSource.close(); - } +public abstract class AbstractScriptDatabaseInitializerTests { @Test void whenDatabaseIsInitializedThenSchemaAndDataScriptsAreApplied() { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(Arrays.asList("schema.sql")); settings.setDataLocations(Arrays.asList("data.sql")); - ScriptDataSourceInitializer initializer = createInitializer(settings); + AbstractScriptDatabaseInitializer initializer = createInitializer(settings); assertThat(initializer.initializeDatabase()).isTrue(); assertThat(numberOfRows("SELECT COUNT(*) FROM EXAMPLE")).isEqualTo(1); } @Test void whenContinueOnErrorIsFalseThenInitializationFailsOnError() { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setDataLocations(Arrays.asList("data.sql")); - ScriptDataSourceInitializer initializer = createInitializer(settings); + AbstractScriptDatabaseInitializer initializer = createInitializer(settings); assertThatExceptionOfType(DataAccessException.class).isThrownBy(() -> initializer.initializeDatabase()); } @Test void whenContinueOnErrorIsTrueThenInitializationDoesNotFailOnError() { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setContinueOnError(true); settings.setDataLocations(Arrays.asList("data.sql")); - ScriptDataSourceInitializer initializer = createInitializer(settings); + AbstractScriptDatabaseInitializer initializer = createInitializer(settings); assertThat(initializer.initializeDatabase()).isTrue(); } @Test void whenNoScriptsExistAtASchemaLocationThenInitializationFails() { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(Arrays.asList("does-not-exist.sql")); - ScriptDataSourceInitializer initializer = createInitializer(settings); + AbstractScriptDatabaseInitializer initializer = createInitializer(settings); assertThatIllegalStateException().isThrownBy(initializer::initializeDatabase) .withMessage("No schema scripts found at location 'does-not-exist.sql'"); } @Test void whenNoScriptsExistAtADataLocationThenInitializationFails() { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setDataLocations(Arrays.asList("does-not-exist.sql")); - ScriptDataSourceInitializer initializer = createInitializer(settings); + AbstractScriptDatabaseInitializer initializer = createInitializer(settings); assertThatIllegalStateException().isThrownBy(initializer::initializeDatabase) .withMessage("No data scripts found at location 'does-not-exist.sql'"); } @Test void whenNoScriptsExistAtAnOptionalSchemaLocationThenInitializationSucceeds() { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(Arrays.asList("optional:does-not-exist.sql")); - ScriptDataSourceInitializer initializer = createInitializer(settings); + AbstractScriptDatabaseInitializer initializer = createInitializer(settings); assertThat(initializer.initializeDatabase()).isFalse(); } @Test void whenNoScriptsExistAtAnOptionalDataLocationThenInitializationSucceeds() { - DataSourceInitializationSettings settings = new DataSourceInitializationSettings(); + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setDataLocations(Arrays.asList("optional:does-not-exist.sql")); - ScriptDataSourceInitializer initializer = createInitializer(settings); + AbstractScriptDatabaseInitializer initializer = createInitializer(settings); assertThat(initializer.initializeDatabase()).isFalse(); } - private ScriptDataSourceInitializer createInitializer(DataSourceInitializationSettings settings) { - return new ScriptDataSourceInitializer(this.dataSource, settings); - } + protected abstract AbstractScriptDatabaseInitializer createInitializer(DatabaseInitializationSettings settings); - private int numberOfRows(String sql) { - return new JdbcTemplate(this.dataSource).queryForObject(sql, Integer.class); - } + protected abstract int numberOfRows(String sql); }