Skip to content

Commit aa4b34c

Browse files
committed
GH-507 - Improve database schema initialization for event publications.
We now use ResourceDatabasePopulator to execute the schema files creating the infrastructure for the event publication registry. This makes sure that the statements in those files are executed individually. Related ticket: GH-403.
1 parent 864baac commit aa4b34c

File tree

4 files changed

+68
-60
lines changed

4 files changed

+68
-60
lines changed

spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/DatabaseSchemaInitializer.java

Lines changed: 1 addition & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,7 @@
1515
*/
1616
package org.springframework.modulith.events.jdbc;
1717

18-
import java.io.IOException;
19-
import java.io.UncheckedIOException;
20-
import java.nio.charset.StandardCharsets;
21-
2218
import org.springframework.beans.factory.InitializingBean;
23-
import org.springframework.core.io.Resource;
24-
import org.springframework.core.io.ResourceLoader;
25-
import org.springframework.jdbc.core.JdbcOperations;
26-
import org.springframework.util.StreamUtils;
2719

2820
/**
2921
* Initializes the DB schema used to store events
@@ -32,48 +24,4 @@
3224
* @author Björn Kieling
3325
* @author Oliver Drotbohm
3426
*/
35-
class DatabaseSchemaInitializer implements InitializingBean {
36-
37-
private final JdbcOperations jdbcOperations;
38-
private final ResourceLoader resourceLoader;
39-
private final DatabaseType databaseType;
40-
41-
/**
42-
* Creates a new {@link DatabaseSchemaInitializer} for the given {@link JdbcOperations}, {@link ResourceLoader} and
43-
* {@link DatabaseType}.
44-
*
45-
* @param jdbcOperations must not be {@literal null}.
46-
* @param resourceLoader must not be {@literal null}.
47-
* @param databaseType must not be {@literal null}.
48-
*/
49-
public DatabaseSchemaInitializer(JdbcOperations jdbcOperations, ResourceLoader resourceLoader,
50-
DatabaseType databaseType) {
51-
52-
this.jdbcOperations = jdbcOperations;
53-
this.resourceLoader = resourceLoader;
54-
this.databaseType = databaseType;
55-
}
56-
57-
/*
58-
* (non-Javadoc)
59-
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
60-
*/
61-
@Override
62-
public void afterPropertiesSet() {
63-
64-
var schemaResourceFilename = databaseType.getSchemaResourceFilename();
65-
var schemaDdlResource = resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + schemaResourceFilename);
66-
var schemaDdl = asString(schemaDdlResource);
67-
68-
jdbcOperations.execute(schemaDdl);
69-
}
70-
71-
private static String asString(Resource resource) {
72-
73-
try {
74-
return StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
75-
} catch (IOException e) {
76-
throw new UncheckedIOException(e);
77-
}
78-
}
79-
}
27+
interface DatabaseSchemaInitializer extends InitializingBean {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.modulith.events.jdbc;
17+
18+
import org.springframework.core.io.Resource;
19+
import org.springframework.core.io.ResourceLoader;
20+
import org.springframework.util.Assert;
21+
22+
/**
23+
* Simple wrapper around a {@link ResourceLoader} to load database specific schema files from the classpath.
24+
*
25+
* @author Oliver Drotbohm
26+
*/
27+
public class DatabaseSchemaLocator {
28+
29+
private final ResourceLoader resourceLoader;
30+
31+
/**
32+
* Creates a new {@link DatabaseSchemaLocator} for the given {@link ResourceLoader}.
33+
*
34+
* @param resourceLoader must not be {@literal null}.
35+
*/
36+
DatabaseSchemaLocator(ResourceLoader resourceLoader) {
37+
38+
Assert.notNull(resourceLoader, "ResourceLoader must not be null!");
39+
40+
this.resourceLoader = resourceLoader;
41+
}
42+
43+
/**
44+
* Loads the {@link Resource} copntaining the schema for the given {@link DatabaseType} from the classpath.
45+
*
46+
* @param databaseType must not be {@literal null}.
47+
* @return will never be {@literal null}.
48+
*/
49+
Resource getSchemaResource(DatabaseType databaseType) {
50+
51+
Assert.notNull(databaseType, "DatabaseType must not be null!");
52+
53+
var schemaResourceFilename = databaseType.getSchemaResourceFilename();
54+
return resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + schemaResourceFilename);
55+
}
56+
}

spring-modulith-events/spring-modulith-events-jdbc/src/main/java/org/springframework/modulith/events/jdbc/JdbcEventPublicationAutoConfiguration.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.context.annotation.Configuration;
2626
import org.springframework.core.io.ResourceLoader;
2727
import org.springframework.jdbc.core.JdbcTemplate;
28+
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
2829
import org.springframework.jdbc.support.JdbcUtils;
2930
import org.springframework.modulith.events.config.EventPublicationAutoConfiguration;
3031
import org.springframework.modulith.events.config.EventPublicationConfigurationExtension;
@@ -53,10 +54,15 @@ JdbcEventPublicationRepository jdbcEventPublicationRepository(JdbcTemplate jdbcT
5354

5455
@Bean
5556
@ConditionalOnProperty(name = "spring.modulith.events.jdbc.schema-initialization.enabled", havingValue = "true")
56-
DatabaseSchemaInitializer databaseSchemaInitializer(JdbcTemplate jdbcTemplate, ResourceLoader resourceLoader,
57+
DatabaseSchemaInitializer databaseSchemaInitializer(DataSource dataSource, ResourceLoader resourceLoader,
5758
DatabaseType databaseType) {
5859

59-
return new DatabaseSchemaInitializer(jdbcTemplate, resourceLoader, databaseType);
60+
return () -> {
61+
62+
var locator = new DatabaseSchemaLocator(resourceLoader);
63+
64+
new ResourceDatabasePopulator(locator.getSchemaResource(databaseType)).execute(dataSource);
65+
};
6066
}
6167

6268
private static String fromDataSource(DataSource dataSource) {
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,15 @@
2626
import org.mockito.junit.jupiter.MockitoExtension;
2727
import org.springframework.core.io.ClassPathResource;
2828
import org.springframework.core.io.ResourceLoader;
29-
import org.springframework.jdbc.core.JdbcOperations;
3029

3130
/**
3231
* Unit tests for {@link DatabaseSchemaInitializer}.
3332
*
3433
* @author Oliver Drotbohm
3534
*/
3635
@ExtendWith(MockitoExtension.class)
37-
class DatabaseSchemaInitializerUnitTests {
36+
public class DatabaseSchemaLocatorUnitTests {
3837

39-
@Mock JdbcOperations jdbcOperations;
4038
@Mock ResourceLoader resourceLoader;
4139

4240
@Test // GH-159
@@ -46,10 +44,10 @@ void loadsSchemaFilesFromClasspath() {
4644
return new ClassPathResource(it.<String> getArgument(0).substring(ResourceLoader.CLASSPATH_URL_PREFIX.length()));
4745
});
4846

49-
var initializer = new DatabaseSchemaInitializer(jdbcOperations, resourceLoader, DatabaseType.H2);
47+
var locator = new DatabaseSchemaLocator(resourceLoader);
5048
var captor = ArgumentCaptor.forClass(String.class);
5149

52-
assertThatNoException().isThrownBy(initializer::afterPropertiesSet);
50+
assertThatNoException().isThrownBy(() -> locator.getSchemaResource(DatabaseType.H2));
5351
verify(resourceLoader).getResource(captor.capture());
5452
assertThat(captor.getValue()).startsWith(ResourceLoader.CLASSPATH_URL_PREFIX);
5553
}

0 commit comments

Comments
 (0)