Skip to content

Commit

Permalink
Merge pull request #16 from vanillabp/bugfix/workflow-module-resource…
Browse files Browse the repository at this point in the history
…s-path

Bugfix/workflow module resources path
  • Loading branch information
stephanpelikan authored Feb 26, 2024
2 parents 0d889f7 + 077d5c2 commit b218633
Show file tree
Hide file tree
Showing 11 changed files with 650 additions and 460 deletions.
66 changes: 47 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ For each use-case to be implemented, the BPMN and the underlying implementation

To encapsulate a workflow module in its runtime environment (e.g. Spring boot container, JEE application container) all necessary configuration and dependencies are bundled as if it were a standalone application. Therefore, each workflow should be an independent module (jar) containing classes and resources (e.g. the BPMN file).

If you run an application consisting of only one workflow module you don't need to define a workflow module explicitly. Instead, the property `spring.application.name` is used as the workflow module id.

### Configuration

In a Spring boot environment one can use [externalized properties](https://www.baeldung.com/spring-yaml) to store configuration details. Typically, a YAML formatted file stored in classpath `config/application.yaml` is used. In a workflow module the same mechanism is used, but the name of the YAML file is customized (e.g. `ride.yaml` for the taxi ride example).
Expand Down Expand Up @@ -106,6 +108,27 @@ public class RideProperties
}
```

### Loading BPM engine resources

Each process engine uses files (BPMN, DMN, etc.) to run workflows. Those files are bundled as part of the workflow module and loaded for each module separately.
Therefore each workflow module has to define a specific directory not clashing with other workflow modules in the classpath:

```yaml
vanillabp:
workflow-modules:
ride:
adapters:
camunda7:
resources-location: classpath*:/ride/camunda7
camunda8:
resources-location: classpath*:/ride/camunda8
```

*Hint:* The BPMN standard is about defining processes but each process engine needs specific attributes to run them.
Therefore, on migrating workflows from one engine to another, the BPMN files have to be copied and changed
according to new engine used. Having this in mind one should also define a resources location specific to the current engine used,
even if there are no plans to migrate to any other engine yet (see sample above).

## Spring boot profiles

Typically, profiles are used to set environment specific properties (e.g. stages):
Expand Down Expand Up @@ -202,33 +225,34 @@ The second scenario is fully supported by VanillaBP. It is a minimally invasive

In periods of no migration there is only one adapter in classpath and therefore no configuration is required. Once you prepare for migration by adding another adapter, some Spring Boot properties have to be set. The settings are validated at startup and violations will be reported and abort launch.

**Setting adapters for a specific workflow:**
**Setting adapters for a specific workflow-module `ride`:**

```yaml
vanillabp:
workflows:
- bpmn-process-id: DemoWorkflow
adapter: camunda8, camunda7
workflow-modules:
ride:
default-adapter: camunda8, camunda7
```

*Hint:* The adapters are used in the order of appearance. Additionally, the first adapter is used to start new workflows.
*Hint:* The adapters are used in the order of their appearance in `default-adapter`. Additionally, the first adapter is used to start new workflows.

**Setting adapters for a specific workflow which is part of a workflow-module:**
**Setting adapters for a specific workflow having BPMN process ID `Ride`:**

```yaml
vanillabp:
workflows:
- bpmn-process-id: DemoWorkflow
workflow-module-id: Demo
adapter: camunda8, camunda7
workflow-modules:
ride:
workflows:
Ride:
default-adapter: camunda8, camunda7
```

**Setting adapters for a all not explicitly specified workflows:**
**Setting adapters for all, not explicitly specified workflows:**

```yaml
vanillabp:
default-adapter: camunda8, camunda7
workflows:
workflow-modules:
...
```

Expand All @@ -239,19 +263,23 @@ Sometimes it is fine to not migrate a workflow (e.g. it will be retired soon). I
```yaml
vanillabp:
default-adapter: camunda8, camunda7
workflows:
- bpmn-process-id: DemoWorkflow
adapter: camunda7
workflow-modules:
ride:
workflows:
Ride:
default-adapter: camunda7
```

Using this technique it is also possible to limit migration to specific workflows only:
Using this technique, it is also possible to limit migration to specific workflows only:

```yaml
vanillabp:
default-adapter: camunda7
workflows:
- bpmn-process-id: DemoWorkflow
adapter: camunda8, camunda7
workflow-modules:
ride:
workflows:
Ride:
default-adapter: camunda8, camunda7
```

## Noteworthy & Contributors
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<artifactId>spring-boot-support</artifactId>
<name>Abstract VanillaBP SPI adapter for Spring Boot</name>
<version>1.0.8-SNAPSHOT</version>
<version>1.1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.vanillabp.springboot.adapter;

import io.vanillabp.spi.process.ProcessService;
import io.vanillabp.springboot.adapter.VanillaBpProperties.WorkflowAndModuleAdapters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.repository.CrudRepository;
Expand All @@ -24,8 +23,8 @@
* is done for each adapter.
* <p>
* @see VanillaBpProperties#getDefaultAdapter()
* @see VanillaBpProperties#getWorkflows()
* @see WorkflowAndModuleAdapters#getAdapter()
* @see VanillaBpProperties.WorkflowModuleAdapterProperties#getDefaultAdapter()
* @see VanillaBpProperties.WorkflowAdapterProperties#getDefaultAdapter()
*/
public class AdapterAwareProcessService<DE> implements ProcessService<DE> {

Expand All @@ -35,6 +34,8 @@ public class AdapterAwareProcessService<DE> implements ProcessService<DE> {

private final Map<String, ProcessServiceImplementation<DE>> processServicesByAdapter;

private final List<String> wiredAdapterIds = new LinkedList<>();

private String workflowModuleId;

private String primaryBpmnProcessId;
Expand Down Expand Up @@ -62,7 +63,7 @@ public AdapterAwareProcessService(
this.workflowAggregateClass = workflowAggregateClass;

processServicesByAdapter.forEach((adapterId, adapter) -> adapter.setParent(this));

}

public CrudRepository<DE, ?> getWorkflowAggregateRepository() {
Expand Down Expand Up @@ -162,6 +163,7 @@ public void wire(
if (this.workflowModuleId == null) {
this.workflowModuleId = workflowModuleId;
}

if (isPrimary) {
this.primaryBpmnProcessId = bpmnProcessId;
if (messageBasedStartEventsMessageNames != null) {
Expand All @@ -171,26 +173,28 @@ public void wire(
this.signalBasedStartEventsSignalNames.addAll(signalBasedStartEventsSignalNames);
}
}

wiredAdapterIds.add(adapterId);
if (wiredAdapterIds.size() == processServicesByAdapter.size()) { // all adapters wired for this service
properties.validatePropertiesFor(
wiredAdapterIds,
workflowModuleId,
bpmnProcessId);
}

this.bpmnProcessIds.add(bpmnProcessId);

}

private List<String> determineAdapterIds() {

return properties
.getWorkflows()
.stream()
.filter(workflow -> workflow.matchesAny(workflowModuleId, bpmnProcessIds))
.findFirst()
.map(WorkflowAndModuleAdapters::getAdapter)
.filter(adapter -> !adapter.isEmpty())
.orElse(properties.getDefaultAdapter());
private List<String> getAdapterIds() {

return properties.getDefaultAdapterFor(workflowModuleId, primaryBpmnProcessId);

}

private String determinePrimaryAdapterId() {
private String getPrimaryAdapterId() {

return determineAdapterIds().get(0);
return getAdapterIds().get(0);

}

Expand All @@ -199,7 +203,7 @@ public DE startWorkflow(
final DE workflowAggregate) throws Exception {

return processServicesByAdapter
.get(determinePrimaryAdapterId())
.get(getPrimaryAdapterId())
.startWorkflow(workflowAggregate);

}
Expand All @@ -212,12 +216,12 @@ public DE correlateMessage(
if (messageBasedStartEventsMessageNames.contains(messageName)) {

return processServicesByAdapter
.get(determinePrimaryAdapterId())
.get(getPrimaryAdapterId())
.correlateMessage(workflowAggregate, messageName);

} else {

return determineAdapterIds()
return getAdapterIds()
.stream()
.map(processServicesByAdapter::get)
.map(adapter -> adapter.correlateMessage(workflowAggregate, messageName))
Expand All @@ -239,12 +243,12 @@ public DE correlateMessage(
if (messageBasedStartEventsMessageNames.contains(messageName)) {

return processServicesByAdapter
.get(determinePrimaryAdapterId())
.get(getPrimaryAdapterId())
.correlateMessage(workflowAggregate, messageName, correlationId);

} else {

return determineAdapterIds()
return getAdapterIds()
.stream()
.map(processServicesByAdapter::get)
.map(adapter -> adapter.correlateMessage(workflowAggregate, messageName, correlationId))
Expand All @@ -263,12 +267,12 @@ public DE correlateMessage(
if (messageBasedStartEventsMessageNames.contains(message.getClass().getSimpleName())) {

return processServicesByAdapter
.get(determinePrimaryAdapterId())
.get(getPrimaryAdapterId())
.correlateMessage(workflowAggregate, message);

} else {

return determineAdapterIds()
return getAdapterIds()
.stream()
.map(processServicesByAdapter::get)
.map(adapter -> adapter.correlateMessage(workflowAggregate, message))
Expand All @@ -288,12 +292,12 @@ public DE correlateMessage(
if (messageBasedStartEventsMessageNames.contains(message.getClass().getSimpleName())) {

return processServicesByAdapter
.get(determinePrimaryAdapterId())
.get(getPrimaryAdapterId())
.correlateMessage(workflowAggregate, message, correlationId);

} else {

return determineAdapterIds()
return getAdapterIds()
.stream()
.map(processServicesByAdapter::get)
.map(adapter -> adapter.correlateMessage(workflowAggregate, message, correlationId))
Expand All @@ -310,7 +314,7 @@ public DE completeUserTask(
final String taskId) {

final var exceptions = new LinkedList<Map.Entry<String, Exception>>();
return determineAdapterIds()
return getAdapterIds()
.stream()
.map(adapterId -> Map.entry(adapterId, processServicesByAdapter.get(adapterId)))
.map(adapter -> {
Expand Down Expand Up @@ -340,7 +344,7 @@ public DE cancelUserTask(
final String bpmnErrorCode) {

final var exceptions = new LinkedList<Map.Entry<String, Exception>>();
return determineAdapterIds()
return getAdapterIds()
.stream()
.map(adapterId -> Map.entry(adapterId, processServicesByAdapter.get(adapterId)))
.map(adapter -> {
Expand Down Expand Up @@ -369,7 +373,7 @@ public DE completeTask(
final String taskId) {

final var exceptions = new LinkedList<Map.Entry<String, Exception>>();
return determineAdapterIds()
return getAdapterIds()
.stream()
.map(adapterId -> Map.entry(adapterId, processServicesByAdapter.get(adapterId)))
.map(adapter -> {
Expand Down Expand Up @@ -399,7 +403,7 @@ public DE cancelTask(
final String bpmnErrorCode) {

final var exceptions = new LinkedList<Map.Entry<String, Exception>>();
return determineAdapterIds()
return getAdapterIds()
.stream()
.map(adapterId -> Map.entry(adapterId, processServicesByAdapter.get(adapterId)))
.map(adapter -> {
Expand Down
Loading

0 comments on commit b218633

Please sign in to comment.