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-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/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/ordo-example/src/main/resources" 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/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/ordo-storage-jdbc/src/main/resources" 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" />
|
<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>
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
<module>ordo-api</module>
|
<module>ordo-api</module>
|
||||||
<module>ordo-example</module>
|
<module>ordo-example</module>
|
||||||
<module>ordo-storage-jdbc</module>
|
<module>ordo-storage-jdbc</module>
|
||||||
|
<module>ordo-spring-boot-starter</module>
|
||||||
|
<module>ordo-spring-boot-autoconfigure</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
Reference in New Issue
Block a user