|
4 | 4 | import io.github.arun0009.idempotent.core.persistence.IdempotentStore; |
5 | 5 | import org.slf4j.Logger; |
6 | 6 | import org.slf4j.LoggerFactory; |
7 | | -import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
| 7 | +import org.springframework.boot.autoconfigure.AutoConfiguration; |
8 | 8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
| 9 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
9 | 10 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
10 | 11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
11 | 12 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
12 | 13 | import org.springframework.context.annotation.Bean; |
13 | | -import org.springframework.context.annotation.Configuration; |
14 | 14 | import org.springframework.jdbc.core.JdbcTemplate; |
15 | 15 | import org.springframework.scheduling.TaskScheduler; |
16 | 16 | import org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler; |
| 17 | +import org.springframework.util.Assert; |
17 | 18 | import tools.jackson.databind.DefaultTyping; |
18 | 19 | import tools.jackson.databind.json.JsonMapper; |
19 | 20 | import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator; |
|
22 | 23 | import javax.sql.DataSource; |
23 | 24 | import java.time.Duration; |
24 | 25 |
|
25 | | -@Configuration |
26 | | -@ConditionalOnBean(DataSource.class) |
27 | | -@EnableConfigurationProperties(RdsIdempotentProperties.class) |
28 | | -@AutoConfigureAfter( |
29 | | - name = { |
| 26 | +@AutoConfiguration( |
| 27 | + afterName = { |
30 | 28 | "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration", |
31 | 29 | "org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration" |
32 | 30 | }) |
33 | | -public class RdsConfig { |
| 31 | +@ConditionalOnClass({DataSource.class, JdbcTemplate.class}) |
| 32 | +@ConditionalOnBean(DataSource.class) |
| 33 | +@EnableConfigurationProperties(RdsIdempotentProperties.class) |
| 34 | +public class RdsAutoConfiguration { |
34 | 35 |
|
35 | | - private static final Logger log = LoggerFactory.getLogger(RdsConfig.class); |
| 36 | + private static final Logger log = LoggerFactory.getLogger(RdsAutoConfiguration.class); |
36 | 37 |
|
37 | 38 | @Bean |
38 | 39 | @ConditionalOnMissingBean |
39 | | - public JsonMapper rdsJsonMapper() { |
40 | | - log.warn("Using an unrestricted polymorphic type validator for RDS idempotent store. " |
41 | | - + "Without restrictions of the PolymorphicTypeValidator, deserialization is " |
42 | | - + "vulnerable to arbitrary code execution when reading from untrusted sources."); |
43 | | - BasicPolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder() |
44 | | - .allowIfBaseType(Object.class) |
45 | | - .allowIfSubType((ctx, clazz) -> true) |
46 | | - .build(); |
47 | | - return JsonMapper.builder() |
48 | | - .polymorphicTypeValidator(ptv) |
49 | | - .setDefaultTyping(new DefaultTypeResolverBuilder( |
50 | | - ptv, DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY, JsonTypeInfo.Id.CLASS, "@class")) |
51 | | - .build(); |
| 40 | + public IdempotentStore idempotentStore( |
| 41 | + JdbcTemplate jdbcTemplate, RdsIdempotentProperties properties, RdsJacksonJsonBuilderCustomizer customizer) { |
| 42 | + Assert.hasText(properties.tableName(), "idempotent.rds.table-name must not be blank"); |
| 43 | + |
| 44 | + var jsonBuilder = JsonMapper.builder(); |
| 45 | + customizer.customize(jsonBuilder); |
| 46 | + |
| 47 | + return new RdsIdempotentStore(jdbcTemplate, properties.tableName(), jsonBuilder.build()); |
52 | 48 | } |
53 | 49 |
|
54 | 50 | @Bean |
55 | 51 | @ConditionalOnMissingBean |
56 | | - public IdempotentStore idempotentStore( |
57 | | - JdbcTemplate jdbcTemplate, RdsIdempotentProperties properties, JsonMapper rdsJsonMapper) { |
58 | | - return new RdsIdempotentStore(jdbcTemplate, properties.getTableName(), rdsJsonMapper); |
| 52 | + public RdsJacksonJsonBuilderCustomizer rdsJacksonJsonBuilderCustomizer() { |
| 53 | + return builder -> { |
| 54 | + log.warn("Using an unrestricted polymorphic type validator for RDS idempotent store. " |
| 55 | + + "Without restrictions of the PolymorphicTypeValidator, deserialization is " |
| 56 | + + "vulnerable to arbitrary code execution when reading from untrusted sources."); |
| 57 | + var ptv = BasicPolymorphicTypeValidator.builder() |
| 58 | + .allowIfBaseType(Object.class) |
| 59 | + .allowIfSubType((ctx, clazz) -> true) |
| 60 | + .build(); |
| 61 | + builder.polymorphicTypeValidator(ptv) |
| 62 | + .setDefaultTyping(new DefaultTypeResolverBuilder( |
| 63 | + ptv, DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY, JsonTypeInfo.Id.CLASS, "@class")); |
| 64 | + }; |
59 | 65 | } |
60 | 66 |
|
61 | 67 | @Bean |
62 | 68 | @ConditionalOnMissingBean |
63 | 69 | @ConditionalOnProperty(prefix = "idempotent.rds.cleanup", name = "enabled", matchIfMissing = true) |
64 | 70 | public RdsCleanupTask rdsCleanupTask( |
65 | 71 | JdbcTemplate jdbcTemplate, RdsIdempotentProperties properties, TaskScheduler rdsCleanupTaskScheduler) { |
| 72 | + Assert.isTrue(properties.cleanup().batchSize() > 0, "idempotent.rds.cleanup.batch-size must be positive"); |
| 73 | + Assert.isTrue(properties.cleanup().fixedDelay() > 0, "idempotent.rds.cleanup.fixed-delay must be positive"); |
| 74 | + |
66 | 75 | RdsDialect dialect = RdsDialect.detect(jdbcTemplate); |
67 | | - RdsCleanupTask cleanupTask = new RdsCleanupTask( |
| 76 | + var cleanupTask = new RdsCleanupTask( |
68 | 77 | jdbcTemplate, |
69 | | - properties.getTableName(), |
| 78 | + properties.tableName(), |
70 | 79 | dialect, |
71 | | - properties.getCleanup().getBatchSize()); |
| 80 | + properties.cleanup().batchSize()); |
72 | 81 | rdsCleanupTaskScheduler.scheduleWithFixedDelay( |
73 | | - cleanupTask::cleanup, Duration.ofMillis(properties.getCleanup().getFixedDelay())); |
| 82 | + cleanupTask::cleanup, Duration.ofMillis(properties.cleanup().fixedDelay())); |
74 | 83 | return cleanupTask; |
75 | 84 | } |
76 | 85 |
|
77 | 86 | @Bean |
78 | 87 | @ConditionalOnMissingBean(name = "rdsCleanupTaskScheduler") |
79 | 88 | @ConditionalOnProperty(prefix = "idempotent.rds.cleanup", name = "enabled", matchIfMissing = true) |
80 | 89 | public TaskScheduler rdsCleanupTaskScheduler() { |
81 | | - SimpleAsyncTaskScheduler scheduler = new SimpleAsyncTaskScheduler(); |
| 90 | + var scheduler = new SimpleAsyncTaskScheduler(); |
82 | 91 | scheduler.setThreadNamePrefix("idempotent-rds-cleanup-"); |
83 | 92 | return scheduler; |
84 | 93 | } |
|
0 commit comments