feat: add spring boot autoconfiguration and starter modules with JDBC support
This commit is contained in:
Generated
+4
@@ -7,6 +7,10 @@
|
||||
<file url="file://$PROJECT_DIR$/ordo-core/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-example/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-example/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-spring-boot-autoconfigure/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-spring-boot-autoconfigure/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-spring-boot-starter/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-spring-boot-starter/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-storage-jdbc/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ordo-storage-jdbc/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ordo-spring-boot-autoconfigure</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring-boot.version>3.3.5</spring-boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo-storage-jdbc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package com.jetlumen.ordo.spring;
|
||||
|
||||
import com.jetlumen.ordo.api.AssigneeResolver;
|
||||
import com.jetlumen.ordo.api.OrdoEngine;
|
||||
import com.jetlumen.ordo.api.TransactionExecutor;
|
||||
import com.jetlumen.ordo.api.repository.ApprovalTaskRepository;
|
||||
import com.jetlumen.ordo.api.repository.ProcessDefinitionRepository;
|
||||
import com.jetlumen.ordo.api.repository.ProcessInstanceRepository;
|
||||
import com.jetlumen.ordo.core.DefaultOrdoEngine;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcApprovalTaskRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcConnectionProvider;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcProcessDefinitionRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcProcessInstanceRepository;
|
||||
import com.jetlumen.ordo.storage.jdbc.JdbcTransactionExecutor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.time.Clock;
|
||||
|
||||
/**
|
||||
* Autoconfigures a JDBC-backed {@link OrdoEngine} when a {@link DataSource} bean is
|
||||
* present. Any bean already defined by the application (e.g. a custom
|
||||
* {@link AssigneeResolver} or repository implementation) takes precedence over the
|
||||
* defaults created here.
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnProperty(prefix = "ordo", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnClass(DataSource.class)
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
@AutoConfigureAfter({DataSourceAutoConfiguration.class, FlywayAutoConfiguration.class})
|
||||
@EnableConfigurationProperties(OrdoProperties.class)
|
||||
public class OrdoJdbcAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock ordoClock() {
|
||||
return Clock.systemUTC();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AssigneeResolver ordoAssigneeResolver() {
|
||||
return AssigneeResolver.direct();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@DependsOnDatabaseInitialization
|
||||
public JdbcConnectionProvider ordoJdbcConnectionProvider(DataSource dataSource) {
|
||||
return new JdbcConnectionProvider(dataSource);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TransactionExecutor ordoTransactionExecutor(JdbcConnectionProvider connectionProvider) {
|
||||
return new JdbcTransactionExecutor(connectionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ProcessDefinitionRepository ordoProcessDefinitionRepository(JdbcConnectionProvider connectionProvider) {
|
||||
return new JdbcProcessDefinitionRepository(connectionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ProcessInstanceRepository ordoProcessInstanceRepository(JdbcConnectionProvider connectionProvider) {
|
||||
return new JdbcProcessInstanceRepository(connectionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ApprovalTaskRepository ordoApprovalTaskRepository(JdbcConnectionProvider connectionProvider) {
|
||||
return new JdbcApprovalTaskRepository(connectionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OrdoEngine ordoEngine(Clock ordoClock,
|
||||
AssigneeResolver ordoAssigneeResolver,
|
||||
TransactionExecutor ordoTransactionExecutor,
|
||||
ProcessDefinitionRepository ordoProcessDefinitionRepository,
|
||||
ProcessInstanceRepository ordoProcessInstanceRepository,
|
||||
ApprovalTaskRepository ordoApprovalTaskRepository) {
|
||||
return new DefaultOrdoEngine(ordoClock, ordoAssigneeResolver, ordoTransactionExecutor,
|
||||
ordoProcessDefinitionRepository, ordoProcessInstanceRepository, ordoApprovalTaskRepository);
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.jetlumen.ordo.spring;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/** Configuration properties for the Ordo Spring Boot autoconfiguration. */
|
||||
@ConfigurationProperties(prefix = "ordo")
|
||||
public class OrdoProperties {
|
||||
|
||||
/** Whether the Ordo JDBC autoconfiguration should be applied. */
|
||||
private boolean enabled = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
com.jetlumen.ordo.spring.OrdoJdbcAutoConfiguration
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package com.jetlumen.ordo.spring;
|
||||
|
||||
import com.jetlumen.ordo.api.ApprovalStep;
|
||||
import com.jetlumen.ordo.api.ApprovalTask;
|
||||
import com.jetlumen.ordo.api.AssigneeResolver;
|
||||
import com.jetlumen.ordo.api.OrdoEngine;
|
||||
import com.jetlumen.ordo.api.ProcessDefinition;
|
||||
import com.jetlumen.ordo.api.ProcessInstance;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OrdoJdbcAutoConfigurationTest {
|
||||
|
||||
private static final ProcessDefinition LEAVE_REQUEST = new ProcessDefinition("leave-request", "Leave request",
|
||||
List.of(new ApprovalStep("manager", "Manager approval", "maria")));
|
||||
|
||||
private final ApplicationContextRunner withDataSourceRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
DataSourceAutoConfiguration.class, FlywayAutoConfiguration.class, OrdoJdbcAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.datasource.url=jdbc:h2:mem:ordo_" + UUID.randomUUID()
|
||||
+ ";MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1",
|
||||
"spring.datasource.username=sa");
|
||||
|
||||
private final ApplicationContextRunner withoutDataSourceRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(OrdoJdbcAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void assemblesJdbcBackedEngineWhenDataSourceIsPresent() {
|
||||
withDataSourceRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(OrdoEngine.class);
|
||||
OrdoEngine engine = context.getBean(OrdoEngine.class);
|
||||
|
||||
engine.register(LEAVE_REQUEST);
|
||||
ProcessInstance instance = engine.start("leave-request", "alice");
|
||||
List<ApprovalTask> pending = engine.findPendingTasksByAssignee("maria");
|
||||
assertThat(pending).hasSize(1);
|
||||
|
||||
ApprovalTask approved = engine.approve(pending.get(0).id(), "maria", "looks good");
|
||||
assertThat(approved.status().name()).isEqualTo("APPROVED");
|
||||
assertThat(engine.findInstance(instance.id())).isPresent();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void backsOffWhenNoDataSourceBeanIsPresent() {
|
||||
withoutDataSourceRunner.run(context ->
|
||||
assertThat(context).doesNotHaveBean(OrdoEngine.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void backsOffWhenDisabledViaProperty() {
|
||||
withDataSourceRunner.withPropertyValues("ordo.enabled=false")
|
||||
.run(context ->
|
||||
assertThat(context).doesNotHaveBean(OrdoEngine.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void honoursUserDefinedAssigneeResolver() {
|
||||
withDataSourceRunner.withUserConfiguration(CustomAssigneeResolverConfig.class)
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(OrdoEngine.class);
|
||||
assertThat(context.getBean(AssigneeResolver.class)).isNotNull();
|
||||
assertThat(context.getBean(AssigneeResolver.class).resolve(null, null))
|
||||
.isEqualTo("custom-assignee");
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomAssigneeResolverConfig {
|
||||
@Bean
|
||||
AssigneeResolver ordoAssigneeResolver() {
|
||||
return (step, ctx) -> "custom-assignee";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ordo-spring-boot-starter</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring-boot.version>3.3.5</spring-boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo-spring-boot-autoconfigure</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
<!--
|
||||
Flyway 10+ split PostgreSQL support out of flyway-core into this dialect
|
||||
module. It is required for migrations to run against PostgreSQL; H2 support
|
||||
remains bundled in flyway-core so tests need nothing extra.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-database-postgresql</artifactId>
|
||||
</dependency>
|
||||
<!--
|
||||
No JDBC driver is bundled. Add the driver for your target database yourself, e.g.:
|
||||
org.postgresql:postgresql (production)
|
||||
com.h2database:h2 (tests / local dev)
|
||||
-->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user