From b7fe56b2f3e8eab9307dc2b3fd6790c09a70a134 Mon Sep 17 00:00:00 2001 From: Stephan Pelikan Date: Mon, 26 Feb 2024 10:57:06 +0100 Subject: [PATCH] Introducing new structure of Spring Boot properties --- pom.xml | 2 +- spring-boot/README.md | 29 +++++++ spring-boot/pom.xml | 4 +- .../Camunda8AdapterConfiguration.java | 8 +- .../camunda8/Camunda8VanillaBpProperties.java | 87 +++++++++++++++++++ .../deployment/Camunda8DeploymentAdapter.java | 10 ++- .../service/Camunda8ProcessService.java | 11 +-- 7 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8VanillaBpProperties.java diff --git a/pom.xml b/pom.xml index 44f40b2..6c6ee0a 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ camunda8-adapter VanillaBP SPI adapter for Camunda 8.x - 1.2.1-SNAPSHOT + 1.3.0-SNAPSHOT pom diff --git a/spring-boot/README.md b/spring-boot/README.md index aed3657..e668160 100644 --- a/spring-boot/README.md +++ b/spring-boot/README.md @@ -112,6 +112,35 @@ On using receive tasks Camunda 8 requires us to define correlation IDs. If your In case your model has more than one receive task active you have to define unique correlation IDs for each receive task of that message name to enable the BPMS to find the right receive task to correlate to. This might happen for multi-instance receive tasks or receive tasks within a multi-instance embedded sub-process. In that case use the workflow id in combination with the multi-instance element as a correlation id: `=id+"+"+RequestRideOffer` (where "RequestRideOffer" is the name of the multi-instance element). +## Using Camunda multi-tenancy + +Typically, on operating multiple workflow modules, one wants to avoid name clashes in Camunda (e.g. of event names, etc.). +Therefore, each workflow module is deployed to Camunda as a separate tenant using the workflow module's id as the tenant-id. + +This behavior can be adapted. + +**If you wish to define a custom tenant-id instead:** + +```yaml +vanillabp: + workflow-modules: + ride: + adapters: + camunda8: + tenant-id: taxiride +``` + +**If you want to disable multi-tenancy:** + +```yaml +vanillabp: + workflow-modules: + ride: + adapters: + camunda8: + use-tenants: false +``` + ## Transaction behavior Since Camunda 8 is an external system to your services one has to deal with eventual consistency in conjunction with transactions. This adapter uses the recommended pattern to report a task as completed and roll back the local transaction in case of errors. Possible errors are: diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index fe40353..7e1bfbe 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -5,7 +5,7 @@ org.camunda.community.vanillabp camunda8-adapter - 1.2.1-SNAPSHOT + 1.3.0-SNAPSHOT camunda8-spring-boot-adapter @@ -35,7 +35,7 @@ io.vanillabp spring-boot-support - 1.0.8-SNAPSHOT + 1.1.0-SNAPSHOT io.camunda diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java index 2f10d43..ab35c18 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurationPackage; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Scope; @@ -37,6 +38,7 @@ @AutoConfigurationPackage(basePackageClasses = Camunda8AdapterConfiguration.class) @AutoConfigureBefore(CamundaAutoConfiguration.class) +@EnableConfigurationProperties(Camunda8VanillaBpProperties.class) public class Camunda8AdapterConfiguration extends AdapterConfigurationBase> { private static final Logger logger = LoggerFactory.getLogger(Camunda8AdapterConfiguration.class); @@ -64,6 +66,9 @@ public class Camunda8AdapterConfiguration extends AdapterConfigurationBase Camunda8ProcessService newProcessServiceImplementation( final CrudRepository workflowAggregateRepository) { final var result = new Camunda8ProcessService( - applicationName, + camunda8Properties, workflowAggregateRepository, workflowAggregate -> springDataUtil.getId(workflowAggregate), workflowAggregateClass); diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8VanillaBpProperties.java b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8VanillaBpProperties.java new file mode 100644 index 0000000..1df3507 --- /dev/null +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8VanillaBpProperties.java @@ -0,0 +1,87 @@ +package io.vanillabp.camunda8; + +import io.vanillabp.springboot.adapter.VanillaBpProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.util.StringUtils; + +import java.util.Map; + +@ConfigurationProperties(prefix = VanillaBpProperties.PREFIX, ignoreUnknownFields = true) +public class Camunda8VanillaBpProperties { + + private Map workflowModules = Map.of(); + + public Map getWorkflowModules() { + return workflowModules; + } + + public void setWorkflowModules(Map workflowModules) { + + this.workflowModules = workflowModules; + workflowModules.forEach((workflowModuleId, properties) -> { + properties.workflowModuleId = workflowModuleId; + }); + + } + + private static final WorkflowModuleAdapterProperties defaultProperties = new WorkflowModuleAdapterProperties(); + private static final AdapterConfiguration defaultAdapterProperties = new AdapterConfiguration(); + + public String getTenantId( + final String workflowModuleId) { + + final var configuration = workflowModules + .getOrDefault(workflowModuleId, defaultProperties) + .getAdapters() + .getOrDefault(Camunda8AdapterConfiguration.ADAPTER_ID, defaultAdapterProperties); + if (!configuration.isUseTenants()) { + return null; + } + if (StringUtils.hasText(configuration.getTenant())) { + return configuration.getTenant(); + } + return workflowModuleId; + + } + + public static class AdapterConfiguration { + + private boolean useTenants = true; + + private String tenant; + + public boolean isUseTenants() { + return useTenants; + } + + public void setUseTenants(boolean useTenants) { + this.useTenants = useTenants; + } + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; + } + + } + + public static class WorkflowModuleAdapterProperties { + + String workflowModuleId; + + private Map adapters = Map.of(); + + public Map getAdapters() { + return adapters; + } + + public void setAdapters(Map adapters) { + this.adapters = adapters; + } + + } + +} diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java b/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java index 7a26df0..1eeec31 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java @@ -15,6 +15,7 @@ import io.camunda.zeebe.model.bpmn.instance.UserTask; import io.camunda.zeebe.spring.client.event.ZeebeClientCreatedEvent; import io.vanillabp.camunda8.Camunda8AdapterConfiguration; +import io.vanillabp.camunda8.Camunda8VanillaBpProperties; import io.vanillabp.camunda8.service.Camunda8ProcessService; import io.vanillabp.camunda8.utils.HashCodeInputStream; import io.vanillabp.camunda8.wiring.Camunda8TaskWiring; @@ -47,20 +48,21 @@ public class Camunda8DeploymentAdapter extends ModuleAwareBpmnDeployment { private final DeploymentService deploymentService; - private final String applicationName; + private final Camunda8VanillaBpProperties camunda8Properties; private ZeebeClient client; public Camunda8DeploymentAdapter( final String applicationName, final VanillaBpProperties properties, + final Camunda8VanillaBpProperties camunda8Properties, final DeploymentService deploymentService, final Camunda8TaskWiring taskWiring) { - super(properties); + super(properties, applicationName); + this.camunda8Properties = camunda8Properties; this.taskWiring = taskWiring; this.deploymentService = deploymentService; - this.applicationName = applicationName; } @@ -160,7 +162,7 @@ protected void doDeployment( if (hasDeployables[0]) { - final var tenantId = workflowModuleId == null ? applicationName : workflowModuleId; + final var tenantId = camunda8Properties.getTenantId(workflowModuleId); final var deployedResources = deploymentCommand .map(command -> tenantId == null ? command : command.tenantId(tenantId)) .map(command -> command diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java b/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java index 3724119..f058308 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java @@ -2,6 +2,7 @@ import io.camunda.zeebe.client.ZeebeClient; import io.vanillabp.camunda8.Camunda8AdapterConfiguration; +import io.vanillabp.camunda8.Camunda8VanillaBpProperties; import io.vanillabp.springboot.adapter.AdapterAwareProcessService; import io.vanillabp.springboot.adapter.ProcessServiceImplementation; import org.slf4j.Logger; @@ -26,20 +27,20 @@ public class Camunda8ProcessService private final Function getWorkflowAggregateId; - private final String applicationName; + private final Camunda8VanillaBpProperties camunda8Properties; private AdapterAwareProcessService parent; private ZeebeClient client; public Camunda8ProcessService( - final String applicationName, + final Camunda8VanillaBpProperties camunda8Properties, final CrudRepository workflowAggregateRepository, final Function getWorkflowAggregateId, final Class workflowAggregateClass) { super(); - this.applicationName = applicationName; + this.camunda8Properties = camunda8Properties; this.workflowAggregateRepository = workflowAggregateRepository; this.workflowAggregateClass = workflowAggregateClass; this.getWorkflowAggregateId = getWorkflowAggregateId; @@ -104,7 +105,7 @@ public DE startWorkflow( final var attachedAggregate = workflowAggregateRepository .save(workflowAggregate); - final var tenantId = parent.getWorkflowModuleId() == null ? applicationName : parent.getWorkflowModuleId(); + final var tenantId = camunda8Properties.getTenantId(parent.getWorkflowModuleId()); final var command = client .newCreateInstanceCommand() .bpmnProcessId(parent.getPrimaryBpmnProcessId()) @@ -167,7 +168,7 @@ public DE correlateMessage( final var attachedAggregate = workflowAggregateRepository .save(workflowAggregate); - final var tenantId = parent.getWorkflowModuleId() == null ? applicationName : parent.getWorkflowModuleId(); + final var tenantId = camunda8Properties.getTenantId(parent.getWorkflowModuleId()); final var command = client .newPublishMessageCommand() .messageName(messageName)