diff --git a/README.adoc b/README.adoc index 4d12a65d..8694d8f6 100644 --- a/README.adoc +++ b/README.adoc @@ -1,4 +1,4 @@ -[cols="a,a,a,a,a,a"] +[cols="a,a,a,a,a,a,a"] |=== | // ci image::https://github.com/holunda-io/camunda-bpm-data/workflows/default/badge.svg[caption="Build Status", link=https://github.com/holunda-io/camunda-bpm-data/actions] @@ -12,22 +12,209 @@ image::https://api.codacy.com/project/badge/Grade/653136bd5cad48c8a9f2621ee304ff image::https://img.shields.io/badge/License-Apache%202.0-blue.svg[caption="License", link="https://www.holunda.io/camunda-bpm-data/license"] | // changelog image::https://img.shields.io/badge/CHANGES----blue.svg[caption="Change log" link="https://www.holunda.io/camunda-bpm-data/changelog"] +| // gitter +image::https://badges.gitter.im/holunda-io/camunda-bpm-data.svg[caption="Gitter", link="https://gitter.im/holunda-io/camunda-bpm-data?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge"] |=== +== Camunda BPM Data -== Quick Start +> Beautiful process data handling for Camunda BPM. -If you just want to start using the library, please consult our link:https://www.holunda.io/camunda-bpm-data/quick-start[Quick Start] -guide. +== Why to use this library in every Camunda project? -== User Guide +If you are a software engineer and run process automation projects in your company or on behalf of the customer +based on Camunda Process Engine, you probably are familiar with process variables. Camunda offers an API to access +them and thereby manipulate the state of the process execution - one of the core features during process automation. -If you have any questions regarding configuration of Camunda BPM Data please -have a look to our primary documentation - the link:https://www.holunda.io/camunda-bpm-data/wiki/user-guide[User Guide]. +Unfortunately, as a user of the Camunda API, you have to exactly know the variable type (so the Java class behind it). +For example, if you store a String in a variable `"orderId"` you must extract it as a String in every piece of code. +Since there is no code connection between the different code parts, but the BPMN process model orchestrates +these snippets to a single process execution, it makes refactoring and testing of process automation projects +error-prone and challenging. + +This library helps you to overcome these difficulties and make access, manipulation and testing process variables really +easy and convenient. We leverage the Camunda API and offer you not only a better API but also some link:https://www.holunda.io/camunda-bpm-data/wiki/user-guide/features[additional features]. + +If you want to read more about data in Camunda processes, have a look on those articles: + +- https://medium.com/holisticon-consultants/data-in-process-part-1-2620bf9abd76[Data in Process (Part 1)] +- https://medium.com/holisticon-consultants/data-in-process-part-2-7c6a109e6ee2[Data in Process (Part 2)] + + +== Quick Introduction + +=== Setup +If you just want to start using the library, put the following dependency into your project `pom.xml`: + +[source,xml] +---- + + io.holunda.data + camunda-bpm-data + 1.0.0 + +---- + +If you are using Gradle Kotlin DSL add to your `build.gradle`: +[source,kotlin] +---- +implementation("io.holunda.data:camunda-bpm-data:1.0.0") +---- + +For Gradle Groovy DSL add to your `build.gradle`: +[source,groovy] +---- +implementation 'io.holunda.data:camunda-bpm-data:1.0.0' +---- + +=== Variable declaration +Now your setup is completed and you can declare your variables like this: + +[source,java] +---- + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import static io.holunda.camunda.bpm.data.CamundaBpmData.*; + +public class OrderApproval { + public static final VariableFactory ORDER_ID = stringVariable("orderId"); + public static final VariableFactory ORDER = customVariable("order", Order.class); + public static final VariableFactory ORDER_APPROVED = booleanVariable("orderApproved"); + public static final VariableFactory ORDER_TOTAL = customVariable("orderTotal", BigDecimal.class); + public static final VariableFactory ORDER_POSITION = customVariable("orderPosition", OrderPosition.class); +} +---- + +=== Variable access from Java Delegate +And finally, you want to access them from your Java delegates, Execution or Task Listeners or simple Java components: + +[source,java] +---- +public class MyDelegate implements JavaDelegate { + @Override + public void execute(DelegateExecution execution) { + VariableReader reader = CamundaBpmData.reader(execution); + OrderPosition orderPosition = reader.get(ORDER_POSITION); + BigDecimal oldTotal = reader.getOptional(ORDER_TOTAL).orElse(BigDecimal.ZERO); + + BigDecimal newTotal = oldTotal.add(calculatePrice(orderPosition)); + ORDER_TOTAL.on(execution).setLocal(newTotal); + } + + private BigDecimal calculatePrice(OrderPosition orderPosition) { + return orderPosition.getNetCost().multiply(BigDecimal.valueOf(orderPosition.getAmount())); + } +} +---- + +=== Variable access from REST Controller + +Now imagine you are implementing a REST controller for a user task form which +loads data from the process application, displays it, captures some input and +sends that back to the process application to complete the user task. By doing so, +you will usually need to access process variables. Here is an example: + +[source, java] +---- +@RestController +@RequestMapping("/task/approve-order") +public class ApproveOrderTaskController { + + private final TaskService taskService; + + public ApproveOrderTaskController(TaskService taskService) { + this.taskService = taskService; + } + + @GetMapping("/{taskId}") + public ResponseEntity loadTask(@PathVariable("taskId") String taskId) { + Order order = ORDER.from(taskService, taskId).get(); + return ResponseEntity.ok(new ApproveTaskDto(order)); + } + + @PostMapping("/{taskId}") + public ResponseEntity completeTask(@PathVariable("taskId") String taskId, @RequestBody ApproveTaskCompleteDto userInput) { + VariableMap vars = builder() + .set(ORDER_APPROVED, userInput.getApproved()) + .build(); + taskService.complete(taskId, vars); + return ResponseEntity.noContent().build(); + } +} + +---- + +=== Testing correct variable access + +If you want to write the test for the REST controller, you will need to stub +the task service and verify that the correct variables has been set. To simplify +these tests, we created an additional library module `camunda-bpm-data-test`. +Please put the following dependency into your `pom.xml`: +[source,xml] +---- + + io.holunda.data + camunda-bpm-data-test + 1.0.0 + test + +---- + +Now you can use `TaskServiceVariableMockBuilder` to stub correct behavior of Camunda Task Service +and `TaskServiceVerifier` to verify the correct access to variables easily. Here is the JUnit +test of the REST controller above, making use of `camunda-bpm-data-test`. + +[source,java] +---- +public class ApproveOrderTaskControllerTest { + + private static Order order = new Order("ORDER-ID-1", new Date(), new ArrayList<>()); + private TaskService taskService = mock(TaskService.class); + private TaskServiceMockVerifier verifier = taskServiceMockVerifier(taskService); + private ApproveOrderTaskController controller = new ApproveOrderTaskController(taskService); + private String taskId; + + @Before + public void prepareTest() { + reset(taskService); + taskId = UUID.randomUUID().toString(); + } + + @Test + public void testLoadTask() { + // given + taskServiceVariableMockBuilder(taskService).initial(ORDER, order).build(); + // when + ResponseEntity responseEntity = controller.loadTask(taskId); + // then + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(responseEntity.getBody()).isEqualTo(new ApproveTaskDto(order)); + verifier.verifyGet(ORDER, taskId); + verifier.verifyNoMoreInteractions(); + } + + @Test + public void testCompleteTask() { + // when + ApproveTaskCompleteDto response = new ApproveTaskCompleteDto(true); + ResponseEntity responseEntity = controller.completeTask(taskId, response); + // then + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + verifier.verifyComplete(builder().set(ORDER_APPROVED, response.getApproved()).build(), taskId); + verifier.verifyNoMoreInteractions(); + } +} +---- + +=== Further documentation + +For further details, please consult our link:https://www.holunda.io/camunda-bpm-data/quick-start[Quick Start] +guide or have a look to our primary documentation - link:https://www.holunda.io/camunda-bpm-data/wiki/user-guide[the User Guide]. == Working Example -See our link:https://www.holunda.io/camunda-bpm-data/wiki/user-guide/examples[Examples] for usage and configuration. +We prepared some typical usage scenarios and implemented two example projects in Java and Kotlin. +See our link:https://www.holunda.io/camunda-bpm-data/wiki/user-guide/examples[Examples] section for usage and configuration. == License diff --git a/docs/pom.xml b/docs/pom.xml index 94b634a0..8111802d 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ io.holunda.data camunda-bpm-data-parent - 0.0.6 + 1.0.0 camunda-bpm-data-docs diff --git a/docs/src/orchid/resources/changelog/1.0/1.0.0.ad b/docs/src/orchid/resources/changelog/1.0/1.0.0.ad new file mode 100644 index 00000000..5b7de7d9 --- /dev/null +++ b/docs/src/orchid/resources/changelog/1.0/1.0.0.ad @@ -0,0 +1,24 @@ +--- +version: 1.0.0 +--- + +== News + +* Run through a internal review in Holisticon BPM expert team + +== Breaking changes + +* The `CamundaBpmData.builder(xxx)` methods and implementing classes where renamed to `XxxWriter` since where didn't follow the Builder pattern. #49 +* The `camunda-bpm-data-kotlin` module is removed and its content is now a part of the `camunda-bpm-data` JAR +* The `camunda-bpm-data-mockito` module is renamed into `camunda-bpm-data-test` and will contain helpers for testing. + +== Features +* Better documentation and catchy README +* Implementation of Anti-Corruption-Layer #47 +* VariableReader convenience methods to access multiple variables have been implemented, see #46 +* Provided type collection detector for SPIN/Jackson (currently as PR for SPIN and example code) + +== Bugfixes + +* Evaluation of complex guards fail if exists condition isn't fulfilled. +* NPE passing null to set, see #46 diff --git a/docs/src/orchid/resources/homepage.md b/docs/src/orchid/resources/homepage.md index 3d595bd3..d86ced7b 100644 --- a/docs/src/orchid/resources/homepage.md +++ b/docs/src/orchid/resources/homepage.md @@ -4,12 +4,23 @@ layout: frontPage ## Why should I use this? -This library provides convenient tooling for access to process variables in Camunda BPM engine. +If you are a software engineer and run process automation projects in your company or on behalf of the customer +based on Camunda Process Engine, you probably are familiar with process variables. Camunda offers an API to access +them and thereby manipulate the state of the process execution - one of the core features during process automation. + +Unfortunately, as a user of the Camunda API, you have to exactly know the variable type (so the Java class behind it). +For example, if you store a String in a variable `"orderId"` you must extract it as a String in every piece of code. +Since there is no code connection between the different code parts, but the BPMN process model orchestrates +these snippets to a single process execution, it makes refactoring and testing of process automation projects +error-prone and challenging. + +This library helps you to overcome these difficulties and make access, manipulation and testing process variables really +easy and convenient. We leverage the Camunda API and offer you not only a better API but also some [additional features](https://www.holunda.io/camunda-bpm-data/wiki/user-guide/features). ## How to start? A good starting point is the [Quick Start](./quick-start). For more detailed documentation, please have a look at -[User Guide](./wiki/user-guide). +[User Guide](./wiki/user-guide). ## Get in touch diff --git a/docs/src/orchid/resources/pages/quick-start.ad b/docs/src/orchid/resources/pages/quick-start.ad index e0765970..329f2650 100644 --- a/docs/src/orchid/resources/pages/quick-start.ad +++ b/docs/src/orchid/resources/pages/quick-start.ad @@ -16,20 +16,20 @@ In Apache Maven add to your `pom.xml`: io.holunda.data camunda-bpm-data - 0.0.5 + 1.0.0 ---- For Gradle Kotlin DSL add to your `build.gradle`: [source,kotlin] ---- -implementation("io.holunda.data:camunda-bpm-data:0.0.5") +implementation("io.holunda.data:camunda-bpm-data:1.0.0") ---- For Gradle Groovy DSL add to your `build.gradle`: [source,groovy] ---- -implementation 'io.holunda.data:camunda-bpm-data:0.0.5' +implementation 'io.holunda.data:camunda-bpm-data:1.0.0' ---- === Declare process variable factories @@ -54,7 +54,7 @@ public class OrderApproval { } ---- -=== Access process variables +=== Access process variables from Java Delegate If you want to access the process variable, call methods on the `ProcessVariableFactory` to configure the usage context, and then invoke the variable access methods. @@ -79,3 +79,102 @@ class JavaDelegates { } } ---- + +=== Variable access from REST Controller + +Now imagine you are implementing a REST controller for a user task form which +loads data from the process application, displays it, captures some input and +sends that back to the process application to complete the user task. By doing so, +you will usually need to access process variables. Here is an example: + +[source, java] +---- +@RestController +@RequestMapping("/task/approve-order") +public class ApproveOrderTaskController { + + private final TaskService taskService; + + public ApproveOrderTaskController(TaskService taskService) { + this.taskService = taskService; + } + + @GetMapping("/{taskId}") + public ResponseEntity loadTask(@PathVariable("taskId") String taskId) { + Order order = ORDER.from(taskService, taskId).get(); + return ResponseEntity.ok(new ApproveTaskDto(order)); + } + + @PostMapping("/{taskId}") + public ResponseEntity completeTask(@PathVariable("taskId") String taskId, @RequestBody ApproveTaskCompleteDto userInput) { + VariableMap vars = builder() + .set(ORDER_APPROVED, userInput.getApproved()) + .build(); + taskService.complete(taskId, vars); + return ResponseEntity.noContent().build(); + } +} + +---- + +=== Testing correct variable access + +If you want to write the test for the REST controller, you will need to stub +the task service and verify that the correct variables has been set. To simplify +these tests, we created an additional library module `camunda-bpm-data-test`. +Please put the following dependency into your `pom.xml`: +[source,xml] +---- + + io.holunda.data + camunda-bpm-data-test + 1.0.0 + test + +---- + +Now you can use `TaskServiceVariableMockBuilder` to stub correct behavior of Camunda Task Service +and `TaskServiceVerifier` to verify the correct access to variables easily. Here is the JUnit +test of the REST controller above, making use of `camunda-bpm-data-test`. + +[source,java] +---- +public class ApproveOrderTaskControllerTest { + + private static Order order = new Order("ORDER-ID-1", new Date(), new ArrayList<>()); + private TaskService taskService = mock(TaskService.class); + private TaskServiceMockVerifier verifier = taskServiceMockVerifier(taskService); + private ApproveOrderTaskController controller = new ApproveOrderTaskController(taskService); + private String taskId; + + @Before + public void prepareTest() { + reset(taskService); + taskId = UUID.randomUUID().toString(); + } + + @Test + public void testLoadTask() { + // given + taskServiceVariableMockBuilder(taskService).initial(ORDER, order).build(); + // when + ResponseEntity responseEntity = controller.loadTask(taskId); + // then + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(responseEntity.getBody()).isEqualTo(new ApproveTaskDto(order)); + verifier.verifyGet(ORDER, taskId); + verifier.verifyNoMoreInteractions(); + } + + @Test + public void testCompleteTask() { + // when + ApproveTaskCompleteDto response = new ApproveTaskCompleteDto(true); + ResponseEntity responseEntity = controller.completeTask(taskId, response); + // then + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + verifier.verifyComplete(builder().set(ORDER_APPROVED, response.getApproved()).build(), taskId); + verifier.verifyNoMoreInteractions(); + } +} +---- diff --git a/docs/src/orchid/resources/wiki/developer-guide/project-setup.ad b/docs/src/orchid/resources/wiki/developer-guide/project-setup.ad index 5a329238..56015e02 100644 --- a/docs/src/orchid/resources/wiki/developer-guide/project-setup.ad +++ b/docs/src/orchid/resources/wiki/developer-guide/project-setup.ad @@ -58,7 +58,7 @@ If you want to skip the build of examples, please specify the `-DskipExamples` s We are using https://github.com/orchidhq/Orchid[JavaEden Orchid] for generation of a static site documentation and rely on AsciiDoc as much as possible. -TIP: If you want to develop your docs in 'live' mode, run `./mvnw -f docs -Pdocs-serve` and access +TIP: If you want to develop your docs in 'live' mode, run `./mvnw -f docs -Pserve-docs` and access the http://localhost:8080/ from your browser. For creation of documentation, please run: @@ -108,7 +108,7 @@ Currently, the following modules are released to OSS Maven Central: * camunda-bpm-data-parent * camunda-bpm-data -* camunda-bpm-data-kotlin +* camunda-bpm-data-test ==== Trigger new release @@ -131,6 +131,25 @@ You can build a release with: This will update the versions in the `pom.xml` s accordingly and push the release tag to the `master` branch and update the `develop` branch for the new development version. + +==== Create feature for development + +You can create a feature branch for development using: + +[source,sh] +---- +./mvnw gitflow:feature-start +---- + +WARNING: This operation requires special permissions. + +After the feature is complete, create a PR. To merge the PR into develop use the command: + +[source,sh] +---- +./mvnw gitflow:feature-finish +---- + ==== Trigger a deploy WARNING: This operation requires special permissions. diff --git a/docs/src/orchid/resources/wiki/user-guide/examples-java.ad b/docs/src/orchid/resources/wiki/user-guide/examples-java.ad index 85074bec..4429d226 100644 --- a/docs/src/orchid/resources/wiki/user-guide/examples-java.ad +++ b/docs/src/orchid/resources/wiki/user-guide/examples-java.ad @@ -103,7 +103,7 @@ class JavaDelegates { public ExecutionListener removeProcessVariables() { return execution -> { - CamundaBpmData.builder(execution) + CamundaBpmData.writer(execution) .remove(ORDER_ID) .remove(ORDER) .remove(ORDER_APPROVED) @@ -127,20 +127,20 @@ class SomeService { private TaskService taskService; public void setNewValuesForExecution(String executionId, String orderId, Boolean orderApproved) { - CamundaBpmData.builder(runtimeService, executionId) + CamundaBpmData.writer(runtimeService, executionId) .set(ORDER_ID, orderId) .set(ORDER_APPROVED, orderApproved) .update(ORDER_TOTAL, amount -> amount.add(10)); } public void setNewValuesForTask(String taskId, String orderId, Boolean orderApproved) { - CamundaBpmData.builder(taskService, taskId) + CamundaBpmData.writer(taskService, taskId) .set(ORDER_ID, orderId) .set(ORDER_APPROVED, orderApproved); } public void start() { - VariableMap variables = CamundaBpmData.builder() + VariableMap variables = CamundaBpmData.writer() .set(ORDER_ID, "4711") .set(ORDER_APPROVED, false) .build(); @@ -149,6 +149,86 @@ class SomeService { } ---- +=== Fluent API to read several variables + +[source,java] +---- +@Component +class SomeService { + + @Autowired + private RuntimeService runtimeService; + @Autowired + private TaskService taskService; + + public String readValuesFromExecution(String executionId) { + VariableReader reader = CamundaBpmData.reader(runtimeService, executionId); + String orderId = reader.get(ORDER_ID); + Boolean orderApproved = reader.get(ORDER_APPROVED); + if (orderApproved) { + // ... + } + return orderId; + } + + public String readValuesFromTask(String taskId) { + VariableReader reader = CamundaBpmData.reader(taskService, taskId); + String orderId = reader.get(ORDER_ID); + Boolean orderApproved = reader.get(ORDER_APPROVED); + if (orderApproved) { + // ... + } + return orderId; + } +} +---- + + +=== Anti-Corruption-Layer: Wrap variables to correlate + +[source,java] +---- +@Component +class SomeService { + + private static final AntiCorruptionLayer MESSAGE_ACL = CamundaBpmDataMapper.identityReplace( + "__transient", + true + ); + + public void correlate() { + VariableMap variables = CamundaBpmData.builder() + .set(ORDER_ID, "4711") + .set(ORDER_APPROVED, false) + .build(); + runtimeService.correlateMessage("message_1", MESSAGE_ACL.wrap(variables)); + } +} +---- + +=== Anti-Corruption-Layer: Check and wrap variables to correlate + +[source,java] +---- +@Component +class SomeService { + + private static AntiCorruptionLayer MY_ACL = CamundaBpmDataACL.guardTransformingReplace( + "__transient", + true, + new VariablesGuard(exists(ORDER_ID)), + IdentityVariableMapTransformer.INSTANCE + ); + + public void correlate() { + VariableMap variables = CamundaBpmData.builder() + .set(ORDER_ID, "4711") + .set(ORDER_APPROVED, false) + .build(); + runtimeService.correlateMessage("message_1", MESSAGE_ACL.checkAndWrap(variables)); + } +} +---- === Example project diff --git a/docs/src/orchid/resources/wiki/user-guide/examples-kotlin.ad b/docs/src/orchid/resources/wiki/user-guide/examples-kotlin.ad index af32e496..38de79c7 100644 --- a/docs/src/orchid/resources/wiki/user-guide/examples-kotlin.ad +++ b/docs/src/orchid/resources/wiki/user-guide/examples-kotlin.ad @@ -122,14 +122,14 @@ class SomeService( ) { fun setNewValuesForExecution(executionId: String, rderId: String, orderApproved: Boolean) { - runtimeService.builder(executionId) + runtimeService.writer(executionId) .set(ORDER_ID, orderId) .set(ORDER_APPROVED, orderApproved) .update(ORDER_TOTAL, { amount -> amount.add(10) }) } fun setNewValuesForTask(taskId: String, orderId: String, orderApproved: Boolean) { - taskService.builder(taskId) + taskService.writer(taskId) .set(ORDER_ID, orderId) .set(ORDER_APPROVED, orderApproved) } @@ -143,6 +143,81 @@ class SomeService( } ---- +=== Fluent API to read several variables + +[source,kotlin] +---- +@Component +class SomeService( + private val runtimeService: RuntimeService, + private val taskService: TaskService +) { + + fun readValuesFromExecution(executionId: String): String { + val reader = CamundaBpmData.reader(runtimeService, executionId) + val orderId = reader.get(ORDER_ID) + val orderApproved = reader.get(ORDER_APPROVED) + if (orderApproved) { + // ... + } + return orderId + } + + fun readValuesFromTask(taskId: String ): String { + val reader = CamundaBpmData.reader(taskService, taskId) + val orderId = reader.get(ORDER_ID) + val orderApproved = reader.get(ORDER_APPROVED) + if (orderApproved) { + // ... + } + return orderId + } +} +---- + +=== Anti-Corruption-Layer: Wrap variables to correlate + +[source,kotlin] +---- +@Component +class SomeService { + + val MESSAGE_ACL = CamundaBpmDataMapper.identityReplace("__transient", true); + + fun correlate() { + val variables = CamundaBpmData.builder() + .set(ORDER_ID, "4711") + .set(ORDER_APPROVED, false) + .build(); + runtimeService.correlateMessage("message_1", MESSAGE_ACL.wrap(variables)); + } +} +---- + +=== Anti-Corruption-Layer: Check and wrap variables to correlate + +[source,kotlin] +---- +@Component +class SomeService { + + val MY_ACL = CamundaBpmDataACL.guardTransformingReplace( + "__transient", + true, + VariablesGuard(exists(ORDER_ID)), + IdentityVariableMapTransformer + ); + + fun correlate() { + val variables = CamundaBpmData.writer() + .set(ORDER_ID, "4711") + .set(ORDER_APPROVED, false) + .build(); + runtimeService.correlateMessage("message_1", MESSAGE_ACL.checkAndWrap(variables)); + } +} +---- + === Example project diff --git a/docs/src/orchid/resources/wiki/user-guide/features.ad b/docs/src/orchid/resources/wiki/user-guide/features.ad index fa4f5210..922a3cbb 100644 --- a/docs/src/orchid/resources/wiki/user-guide/features.ad +++ b/docs/src/orchid/resources/wiki/user-guide/features.ad @@ -5,15 +5,14 @@ title: Features == {{ page.title }} * Process Variables -- The library provides a way to construct generic adapter for every process variable. -- The adapter contains variable name. +- The library provides a way to construct a generic adapter for every process variable. - The adapter contains variable type. - The adapter can be applied in any context (`RuntimeService`, `TaskService`, `DelegateExecution`, `DelegateTask`, `VariableMap`). - The adapter offers methods to read, write, update and remove variable values. - The adapter works for all types supported by Camunda BPM. This includes primitive types, object and container types ( `List`, `Set`, `Map` ). - The adapter supports global / local variables. - The adapter support transient variables. -- Fluent builders are available in order to set, remove or update multiple variables in the same context. +- Fluent API helper are available in order to set, remove or update multiple variables in the same context (`VariableMapBuilder`, `VariableReader` and `VariableWriter`). * Process Variable Guards - Generic support for `VariableGuard` for evaluation of a list of `VariableCondition`s - Condition to check if variable exists. @@ -21,9 +20,17 @@ title: Features - Condition to check if variable has a predefined value. - Condition to check if variable has one of predefined values. - Condition to check if variable matches condition specified by a custom function. -- `AbstractGuardTaskListener` to construct variable conditions guards easily. -- `AbstractGuardExecutionListener` to construct variable conditions guards easily. +- `DefaultGuardTaskListener` to construct variable conditions guards easily. +- `DefaultGuardExecutionListener` to construct variable conditions guards easily. +* Anti-Corruption-Layer +- Generic support for `AntiCorruptionLayer` for protection and influence of variable modification in signalling and message correlation. +- Helper methods for the client to wrap variables in a transient carrier. +- Execution listener to handle `VariableGuard`-based conditions and `VariableMapTransformer`-based modifications. +- Task listener to handle `VariableGuard`-based conditions and `VariableMapTransformer`-based modifications. +- Factory methods to create `AntiCorruptionLayer` with a `VariableGuard` (see `CamundaBpmDataACL`) +- Factory methods to create `AntiCorruptionLayer` without a `VariableGuard` (see `CamundaBpmDataMapper`) * Testing variable access and mocking `RuntimeService` and `TaskService`. - Builder to create Mockito-based behaviour of `RuntimeService` accessing variables. - Builder to create Mockito-based behaviour of `TaskServiceService` accessing variables. - +- Verifier to check correct access to variables in `RuntimeService` +- Verifier to check correct access to variables in `TaskService` diff --git a/docs/src/orchid/resources/wiki/user-guide/further-outlook.ad b/docs/src/orchid/resources/wiki/user-guide/further-outlook.ad index e043ef5b..db2a2006 100644 --- a/docs/src/orchid/resources/wiki/user-guide/further-outlook.ad +++ b/docs/src/orchid/resources/wiki/user-guide/further-outlook.ad @@ -6,9 +6,6 @@ title: Further outlook == {{ page.title }} -* Implement Contracts to be able to check a guards automatically -* Implement an Anti-Corruption-Layer to protect Message correlation and External Task completion from - setting wrong values (unguarded). - +* Implement Contracts to be able to check guards automatically // We implemented all features we could imagine so far, if you are missing something, please // open an issue in https://github.com/holunda-io/camunda-bpm-data/issues[Github]. diff --git a/docs/src/orchid/resources/wiki/user-guide/motivation.ad b/docs/src/orchid/resources/wiki/user-guide/motivation.ad index a2f82ace..8595cfe1 100644 --- a/docs/src/orchid/resources/wiki/user-guide/motivation.ad +++ b/docs/src/orchid/resources/wiki/user-guide/motivation.ad @@ -52,7 +52,7 @@ will throw a `GuardViolationException` if the condition is not met. import static io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.exists; @Component -class MyGuardListener extends AbstractGuardTaskListener { +class MyGuardListener extends DefaultGuardTaskListener { public MyGuardListener() { super(newArrayList(exists(ORDER_APPROVED)), true); @@ -60,3 +60,71 @@ class MyGuardListener extends AbstractGuardTaskListener { } ---- +=== Anti-Corruption-Layer + +If a process is signalled or hit by a correlated message, there is no way to check if the transported variables are set correctly. +In addition, the variables are written directly to the execution of the correlated process instance. In case of a multi-instance +event-base sub-process this will eventually overwrite the values of the main execution. + +To prevent all this, a feature called Anti-Corruption-Layer (ACL) is implemented. An ACL is there to protect the execution +from bad modifications and influence the way, the modification is executed. For the protection, an ACL relies on a Variables Guards, +defining conditions to be satisfied. For the influencing of modification, the `VariableMapTransformer` can be used. + +To use the ACL layer you will need to change the way you correlate messages (or signal the execution). Instead of supplying the variables +directly to the `correlate` method of the `RuntimeService`, the client is wrapping all variables into a map hold by a single transient variable +and correlate this variable with the process (we call this procedure variable wrapping). On the process side, an execution listener placed +on the end of the catch event is responsible to extract the variable map from the transient variable, check it by passing through the `VariablesGuard` +and finally pass over to the `VariableMapTransformer` to map from external to internal representation. + +Here is the code, required on the client side to correlate the message. + +[source,java] +---- +@Component +class SomeService { + + private static AntiCorruptionLayer MY_ACL = CamundaBpmDataACL.guardTransformingReplace( + "__transient", // name of the transient variable for wrapping + true, // if passes the guard, write to local scope + new VariablesGuard(exists(ORDER_ID)), // guard defining condition on ORDER_ID + IdentityVariableMapTransformer.INSTANCE // use 1:1 transformer + // write the variables without modifications + ); + + public void correlate() { + VariableMap variables = CamundaBpmData.builder() + .set(ORDER_ID, "4711") + .set(ORDER_APPROVED, false) + .build(); + runtimeService.correlateMessage("message_1", MESSAGE_ACL.checkAndWrap(variables)); + } +} +---- + +On the process side, the BPMN message catch event should have an `End` listener responsible for unwrapping the values. If the listener is +implemented as a Spring Bean bounded via delegate expression `${messageAclListener}` then the following code is responsible for providing such a listener: + +[source,java] +---- +@Configuration +class SomeConfiguration { + + private static AntiCorruptionLayer MY_ACL = CamundaBpmDataACL.guardTransformingReplace( + "__transient", // name of the transient variable for wrapping + true, // if passes the guard, write to local scope + new VariablesGuard(exists(ORDER_ID)), // guard defining condition on ORDER_ID + IdentityVariableMapTransformer.INSTANCE // use 1:1 transformer + // write the variables without modifications + ); + + @Bean("messageAclListener") + public ExecutionListener messageAclListener() { + return MY_ACL.getExecutionListener(); + } +} +---- + +Such a setup will only allow to correlate messages, if the variables provided include a value for the `ORDER_ID`. It will write all +variables provided (`ORDER_ID` and `ORDER_APPROVED`) into a local scope of the execution. + + diff --git a/example/example-java/pom.xml b/example/example-java/pom.xml index 5168d2cf..39e8a099 100644 --- a/example/example-java/pom.xml +++ b/example/example-java/pom.xml @@ -6,38 +6,98 @@ io.holunda.data.example camunda-bpm-data-example-parent - 0.0.6 + 1.0.0 camunda-bpm-data-example-java ${project.artifactId} - jar - false + true - io.holunda.data camunda-bpm-data + + io.holunda.data.example + camunda-bpm-data-spin-type-detector + ${project.version} + + io.toolisticon.springboot springboot-swagger-starter - 0.0.4 + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.camunda.bpm.springboot + camunda-bpm-spring-boot-starter-rest + + + org.camunda.bpm + camunda-engine-plugin-spin + + + org.camunda.spin + camunda-spin-core + + + org.camunda.spin + camunda-spin-dataformat-json-jackson + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.module + jackson-module-kotlin + + + + org.codehaus.groovy + groovy-all + + + com.h2database + h2 + + + io.holunda.data - camunda-bpm-data-mockito + camunda-bpm-data-test test + + org.camunda.bpm.assert + camunda-bpm-assert + test + + org.camunda.bpm.springboot camunda-bpm-spring-boot-starter-test - ${camunda-spring-boot.version} test @@ -45,6 +105,24 @@ camunda-bpm-mockito test + + org.springframework.boot + spring-boot-starter-test + test + + + io.holunda.testing + camunda-bpm-jgiven + test + + + + + org.springframework.boot + spring-boot-maven-plugin + + + diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/CamundaBpmDataProcessApplication.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/CamundaBpmDataProcessApplication.java index 06e62984..7bec9797 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/CamundaBpmDataProcessApplication.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/CamundaBpmDataProcessApplication.java @@ -17,7 +17,7 @@ public class CamundaBpmDataProcessApplication { @EventListener public void onDeploy(PostDeployEvent event) { - orderApprovalInstanceFactory.start(); + orderApprovalInstanceFactory.start("1"); } public static void main(String[] args) { diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/Order.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/Order.java index f6efb62f..092cdb45 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/Order.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/Order.java @@ -1,43 +1,89 @@ package io.holunda.camunda.bpm.data.example.domain; +import java.util.ArrayList; import java.util.Date; import java.util.List; +/** + * Order business entity. + */ public class Order { + /** + * Id of the order. + */ private String orderId; + /** + * Order create date. + */ private Date created; + /** + * List of order positions. + */ private List positions; + /** + * Constructor. + */ public Order() { - + this.positions = new ArrayList<>(); } + /** + * Constructor to pass all member attributes. + * @param orderId order id + * @param created creation date + * @param positions list of positions. + */ public Order(String orderId, Date created, List positions) { this.orderId = orderId; this.created = created; this.positions = positions; } + /** + * Sets the order id. + * @param orderId order id to set. + */ public void setOrderId(String orderId) { this.orderId = orderId; } + /** + * Sets the created date. + * @param created created date to set. + */ public void setCreated(Date created) { this.created = created; } + /** + * Sets the order positions. + * @param positions list of positions to set. + */ public void setPositions(List positions) { this.positions = positions; } + /** + * Retrieves the order id. + * @return order id. + */ public String getOrderId() { return orderId; } + /** + * Retrieves the created date. + * @return date of create. + */ public Date getCreated() { return created; } + /** + * Retrieves the list of positions. + * @return list of positions. + */ public List getPositions() { return positions; } @@ -69,4 +115,13 @@ public int hashCode() { result = 31 * result + positions.hashCode(); return result; } + + @Override + public String toString() { + return "Order{" + + "orderId='" + orderId + '\'' + + ", created=" + created + + ", positions=" + positions + + '}'; + } } diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/OrderPosition.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/OrderPosition.java index 0000c466..b9e680e8 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/OrderPosition.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/OrderPosition.java @@ -2,41 +2,86 @@ import java.math.BigDecimal; +/** + * Represents order position business entity. + */ public class OrderPosition { + /** + * Position title. + */ private String title; + /** + * Position net cost per unit. + */ private BigDecimal netCost; + /** + * amount of units. + */ private Long amount; + /** + * Empty constructor. + */ public OrderPosition() { } + /** + * Constructor setting fields. + * @param title title of position. + * @param netCost net cost per unit. + * @param amount amount of units. + */ public OrderPosition(String title, BigDecimal netCost, Long amount) { this.title = title; this.netCost = netCost; this.amount = amount; } + /** + * Retrieves title. + * @return position title. + */ public String getTitle() { return title; } + /** + * Retrieves net cost per unit. + * @return net cost per unit. + */ public BigDecimal getNetCost() { return netCost; } + /** + * Retrieves amount of units. + * @return amount of units. + */ public Long getAmount() { return amount; } + /** + * Sets the title. + * @param title title to set. + */ public void setTitle(String title) { this.title = title; } + /** + * Sets net cost per unit. + * @param netCost net cost to set. + */ public void setNetCost(BigDecimal netCost) { this.netCost = netCost; } + /** + * Sets amount of units. + * @param amount amount to set. + */ public void setAmount(Long amount) { this.amount = amount; } @@ -68,4 +113,13 @@ public int hashCode() { result = 31 * result + amount.hashCode(); return result; } + + @Override + public String toString() { + return "OrderPosition{" + + "title='" + title + '\'' + + ", netCost=" + netCost + + ", amount=" + amount + + '}'; + } } diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/OrderRepository.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/OrderRepository.java new file mode 100644 index 00000000..df51c35a --- /dev/null +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/domain/OrderRepository.java @@ -0,0 +1,41 @@ +package io.holunda.camunda.bpm.data.example.domain; + +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.sql.Date; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Repository to load orders. + */ +@Component +public class OrderRepository { + + /** + * Internal representation for storage. + */ + private final Map orders = new HashMap<>(); + + public OrderRepository() { + final List positions = new ArrayList<>(); + positions.add(new OrderPosition("Pencil", BigDecimal.valueOf(1.50), 2L)); + positions.add(new OrderPosition("Pen", BigDecimal.valueOf(2.10), 2L)); + orders.put("1", new Order("1", Date.from(Instant.now()), positions)); + } + + + /** + * Loads order by id. + * @param orderId order id to load the order for. + * @return order or null. + */ + public Order loadOrder(String orderId) { + return orders.get(orderId); + } + +} diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApproval.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApproval.java index 54840933..76d2ab77 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApproval.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApproval.java @@ -2,10 +2,10 @@ import io.holunda.camunda.bpm.data.example.domain.Order; import io.holunda.camunda.bpm.data.example.domain.OrderPosition; -import io.holunda.camunda.bpm.data.example.service.OrderRepository; +import io.holunda.camunda.bpm.data.example.domain.OrderRepository; import io.holunda.camunda.bpm.data.factory.VariableFactory; -import io.holunda.camunda.bpm.data.guard.integration.AbstractGuardExecutionListener; -import io.holunda.camunda.bpm.data.guard.integration.AbstractGuardTaskListener; +import io.holunda.camunda.bpm.data.guard.integration.DefaultGuardExecutionListener; +import io.holunda.camunda.bpm.data.guard.integration.DefaultGuardTaskListener; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.DelegateTask; import org.camunda.bpm.engine.delegate.ExecutionListener; @@ -21,94 +21,138 @@ import java.math.BigDecimal; import static com.google.common.collect.Lists.newArrayList; -import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; -import static io.holunda.camunda.bpm.data.CamundaBpmData.customVariable; -import static io.holunda.camunda.bpm.data.CamundaBpmData.booleanVariable; +import static io.holunda.camunda.bpm.data.CamundaBpmData.*; import static io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.exists; +/** + * Process backing bean. + */ @Configuration public class OrderApproval { - public static final String KEY = "order-approval"; - - public static final VariableFactory ORDER_ID = stringVariable("orderId"); - public static final VariableFactory ORDER = customVariable("order", Order.class); - public static final VariableFactory ORDER_APPROVED = booleanVariable("orderApproved"); - public static final VariableFactory ORDER_POSITION = customVariable("orderPosition", OrderPosition.class); - public static final VariableFactory ORDER_TOTAL = customVariable("orderTotal", BigDecimal.class); - - private static final Logger logger = LoggerFactory.getLogger(OrderApproval.class); - - @Autowired - private OrderRepository orderRepository; - - /** - * Load a primitive variable by id (string) and store a complex variable (order). - */ - @Bean - public JavaDelegate loadOrder() { - return execution -> { - String orderId = ORDER_ID.from(execution).get(); - Order order = orderRepository.loadOrder(orderId); - ORDER.on(execution).set(order); - }; - } - - @Bean - public ExecutionListener guardExecutionListener() { - return new AbstractGuardExecutionListener(newArrayList(exists(ORDER_ID)), true) {}; - } - - @Bean - public TaskListener guardTaskListener() { - return new AbstractGuardTaskListener(newArrayList(exists(ORDER_APPROVED)), true) {}; - } - - /** - * Load a local order position, write a local variable. - */ - @Bean - public JavaDelegate calculateOrderPositions() { - return execution -> { - OrderPosition orderPosition = ORDER_POSITION.from(execution).get(); - BigDecimal oldTotal = ORDER_TOTAL.from(execution).getOptional().orElse(BigDecimal.ZERO); - BigDecimal newTotal = oldTotal.add(orderPosition.getNetCost().multiply(BigDecimal.valueOf(orderPosition.getAmount()))); - ORDER_TOTAL.on(execution).setLocal(newTotal); - - // alternative - // ORDER_TOTAL.on(execution).updateLocal(amount -> amount.add(orderPosition.getNetCost().multiply(BigDecimal.valueOf(orderPosition.getAmount())))); - }; - } - - - /** - * Read a local variable and store it in global variable. - */ - @Bean - public ExecutionListener writeOrderTotal() { - return execution -> - { - BigDecimal total = ORDER_TOTAL.from(execution).get(); - ORDER_TOTAL.on(execution).set(total); - }; - } - - /** - * Log the task id. - */ - @EventListener(condition = "#task != null && #task.eventName == 'create'") - public void taskLogger(DelegateTask task) { - logger.info("TASK LOGGER: Created user task {}", task.getId()); - } - - @EventListener(condition = "#execution != null && #execution.eventName == 'start' && #execution.currentActivityId == 'start_order_created'") - public void processStartLogger(DelegateExecution execution) { - logger.info("INSTANCE LOGGER: Started process instance {}", execution.getProcessInstanceId()); - } - - @EventListener(condition = "#execution != null && #execution.eventName == 'end' && #execution.currentActivityId == 'end_order_approved'") - public void processEndLogger(DelegateExecution execution) { - logger.info("INSTANCE LOGGER: Finished process instance {}", execution.getProcessInstanceId()); - } + public static final String KEY = "order-approval"; + + enum Elements { + start_order_created, + user_approve_order, + end_order_approved, + end_order_rejected; + + static String element(Elements element) { + return element.name(); + } + } + + public static final VariableFactory ORDER_ID = stringVariable("orderId"); + public static final VariableFactory ORDER = customVariable("order", Order.class); + public static final VariableFactory ORDER_APPROVED = booleanVariable("orderApproved"); + public static final VariableFactory ORDER_POSITION = customVariable("orderPosition", OrderPosition.class); + public static final VariableFactory ORDER_TOTAL = customVariable("orderTotal", BigDecimal.class); + + private static final Logger logger = LoggerFactory.getLogger(OrderApproval.class); + + @Autowired + private OrderRepository orderRepository; + + /** + * Loads a primitive variable by id (string) and store a complex variable (order). + * Used in "Load Order" service task in BPMN ${loadOrder} + * + * @return Java delegate + */ + @Bean + public JavaDelegate loadOrder() { + return execution -> { + String orderId = ORDER_ID.from(execution).get(); + Order order = orderRepository.loadOrder(orderId); + ORDER.on(execution).set(order); + }; + } + + /** + * Load a local order position, write a local variable. + */ + @Bean + public JavaDelegate calculateOrderPositions() { + return execution -> { + OrderPosition orderPosition = ORDER_POSITION.from(execution).get(); + BigDecimal oldTotal = ORDER_TOTAL.from(execution).getOptional().orElse(BigDecimal.ZERO); + BigDecimal newTotal = oldTotal.add(orderPosition.getNetCost().multiply(BigDecimal.valueOf(orderPosition.getAmount()))); + ORDER_TOTAL.on(execution).setLocal(newTotal); + + // alternative + // ORDER_TOTAL.on(execution).updateLocal(amount -> amount.add(orderPosition.getNetCost().multiply(BigDecimal.valueOf(orderPosition.getAmount())))); + }; + } + + + /** + * Read a local variable and store it in global variable. + */ + @Bean + public ExecutionListener writeOrderTotal() { + return execution -> + { + BigDecimal total = ORDER_TOTAL.from(execution).get(); + ORDER_TOTAL.on(execution).set(total); + }; + } + + /** + * Checks that the variable "orderId" exists. + * Used as execution listener on start event in BPMN ${guardExecutionListener} + * + * @return execution listener. + */ + @Bean + public ExecutionListener guardExecutionListener() { + return new DefaultGuardExecutionListener(newArrayList(exists(ORDER_ID)), true); + } + + /** + * Checks that the variable "orderApproved" exists. + * Used as task listener on complete of user task in BPMN ${taskExecutionListener} + * + * @return task listener. + */ + @Bean + public TaskListener guardTaskListener() { + return new DefaultGuardTaskListener( + newArrayList( + exists(ORDER_APPROVED) + ), true + ); + } + + + /** + * Logs the task creation. + * + * @param task task passed by the engine. + */ + @EventListener(condition = "#task != null && #task.eventName == 'create'") + public void taskLogger(DelegateTask task) { + logger.info("TASK LOGGER: Created user task {}", task.getId()); + } + + /** + * Logs process start. + * + * @param execution execution passed by the engine. + */ + @EventListener(condition = "#execution != null && #execution.eventName == 'start' && #execution.currentActivityId == 'start_order_created'") + public void processStartLogger(DelegateExecution execution) { + logger.info("INSTANCE LOGGER: Started process instance {}", execution.getProcessInstanceId()); + } + + /** + * Logs process end. + * + * @param execution execution passed by the engine. + */ + @EventListener(condition = "#execution != null && #execution.eventName == 'end' && #execution.currentActivityId == 'end_order_approved'") + public void processEndLogger(DelegateExecution execution) { + logger.info("INSTANCE LOGGER: Finished process instance {}", execution.getProcessInstanceId()); + } } diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstance.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstance.java index c72cf7a0..6ff1aa6f 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstance.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstance.java @@ -2,15 +2,31 @@ import org.camunda.bpm.engine.runtime.ProcessInstance; -public class OrderApprovalInstance { +import java.util.function.Supplier; +/** + * Order Approval process instance supplier. + */ +public class OrderApprovalInstance implements Supplier { + + /** + * Underlying instance. + */ private final ProcessInstance instance; + /** + * Creates the supplier. + * @param instance instance. + */ public OrderApprovalInstance(ProcessInstance instance) { this.instance = instance; } - public ProcessInstance getInstance() { + /** + * Retrieval of the instance. + * @return instance. + */ + public ProcessInstance get() { return instance; } } diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstanceFactory.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstanceFactory.java index 66a84f97..90b5b95d 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstanceFactory.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalInstanceFactory.java @@ -10,18 +10,33 @@ import static io.holunda.camunda.bpm.data.example.process.OrderApproval.ORDER_ID; import static org.camunda.bpm.engine.variable.Variables.createVariables; +/** + * Factory to create instance factory. + */ @Component public class OrderApprovalInstanceFactory { + /** + * Runtime service to access Camunda API. + */ private final RuntimeService runtimeService; + /** + * Constructs the factory. + * @param runtimeService runtime service to use. + */ public OrderApprovalInstanceFactory(RuntimeService runtimeService) { this.runtimeService = runtimeService; } - public OrderApprovalInstance start() { + /** + * Start new approval process. + * @param orderId id of an order. + * @return instance supplier. + */ + public OrderApprovalInstance start(String orderId) { VariableMap vars = createVariables(); - ORDER_ID.on(vars).set("1"); + ORDER_ID.on(vars).set(orderId); ProcessInstance instance = runtimeService.startProcessInstanceByKey(OrderApproval.KEY, "order-" + UUID.randomUUID().toString(), vars); return new OrderApprovalInstance(instance); } diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskController.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskController.java index d8046f5d..e02ce445 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskController.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskController.java @@ -1,6 +1,5 @@ package io.holunda.camunda.bpm.data.example.rest; - import io.holunda.camunda.bpm.data.example.domain.Order; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.variable.VariableMap; @@ -12,31 +11,34 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import static io.holunda.camunda.bpm.data.example.process.OrderApproval.ORDER; -import static io.holunda.camunda.bpm.data.example.process.OrderApproval.ORDER_APPROVED; -import static org.camunda.bpm.engine.variable.Variables.createVariables; +import java.math.BigDecimal; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.builder; +import static io.holunda.camunda.bpm.data.example.process.OrderApproval.*; @RestController @RequestMapping("/task/approve-order") public class ApproveOrderTaskController { - private final TaskService taskService; - public ApproveOrderTaskController(TaskService taskService) { - this.taskService = taskService; - } - - @GetMapping("/{taskId}") - public ResponseEntity loadTask(@PathVariable("taskId") String taskId) { - Order order = ORDER.from(taskService, taskId).get(); - return ResponseEntity.ok(new ApproveTaskDto(order)); - } - - @PostMapping("/{taskId}") - public ResponseEntity completeTask(@PathVariable("taskId") String taskId, @RequestBody ApproveTaskCompleteDto approveTaskComplete) { - VariableMap vars = createVariables(); - ORDER_APPROVED.on(vars).set(approveTaskComplete.getApproved()); - taskService.complete(taskId, vars); - return ResponseEntity.noContent().build(); - } - + private final TaskService taskService; + + public ApproveOrderTaskController(TaskService taskService) { + this.taskService = taskService; + } + + @GetMapping("/{taskId}") + public ResponseEntity loadTask(@PathVariable("taskId") String taskId) { + final Order order = ORDER.from(taskService, taskId).get(); + final BigDecimal orderTotal = ORDER_TOTAL.from(taskService, taskId).get(); + return ResponseEntity.ok(new ApproveTaskDto(order, orderTotal)); + } + + @PostMapping("/{taskId}") + public ResponseEntity completeTask(@PathVariable("taskId") String taskId, @RequestBody ApproveTaskCompleteDto userInput) { + VariableMap vars = builder() + .set(ORDER_APPROVED, userInput.getApproved()) + .build(); + taskService.complete(taskId, vars); + return ResponseEntity.noContent().build(); + } } diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskCompleteDto.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskCompleteDto.java index 4890f946..25df939a 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskCompleteDto.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskCompleteDto.java @@ -1,18 +1,37 @@ package io.holunda.camunda.bpm.data.example.rest; +/** + * DTO to carry the approve task response. + */ public class ApproveTaskCompleteDto { + /** + * Response value. + */ private Boolean approved; - public ApproveTaskCompleteDto() { - - } + /** + * Empty constructor. + */ + public ApproveTaskCompleteDto() { } + /** + * Constructs DTO with response. + * @param approved response value. + */ public ApproveTaskCompleteDto(Boolean approved) {this.approved = approved;} + /** + * Retrieves response value. + * @return response value. + */ public Boolean getApproved() { return approved; } + /** + * Sets response value. + * @param approved response value to set. + */ public void setApproved(Boolean approved) { this.approved = approved; } diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskDto.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskDto.java index 07a21fe0..0034742b 100644 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskDto.java +++ b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/rest/ApproveTaskDto.java @@ -2,31 +2,70 @@ import io.holunda.camunda.bpm.data.example.domain.Order; -import java.util.Objects; +import java.math.BigDecimal; +/** + * Simple DTO carrying the order and the total. + */ public class ApproveTaskDto { + /** + * Order to carry. + */ private Order order; - public ApproveTaskDto() { + /** + * Order total. + */ + private BigDecimal orderTotal; - } + /** + * Empty constructor. + */ + public ApproveTaskDto() { } - public ApproveTaskDto(Order order) {this.order = order;} + /** + * Constructs the DTO with order. + * + * @param order order to store. + */ + public ApproveTaskDto(Order order, BigDecimal orderTotal) { + this.order = order; + this.orderTotal = orderTotal; + } + /** + * Sets order. + * + * @param order order to set. + */ public void setOrder(Order order) { this.order = order; } + /** + * Sets order total. + * @param orderTotal order total. + */ + public void setOrderTotal(BigDecimal orderTotal) { + this.orderTotal = orderTotal; + } + + /** + * Get order. + * + * @return order to get. + */ public Order getOrder() { return order; } - @Override - public String toString() { - return "ApproveTaskDto{" + - "order=" + order + - '}'; + /** + * Retrieves the total. + * @return order total. + */ + public BigDecimal getOrderTotal() { + return orderTotal; } @Override @@ -39,11 +78,26 @@ public boolean equals(Object o) { } ApproveTaskDto that = (ApproveTaskDto) o; - return Objects.equals(order, that.order); + + if (order != null ? !order.equals(that.order) : that.order != null) { + return false; + } + return orderTotal != null ? orderTotal.equals(that.orderTotal) : that.orderTotal == null; } @Override public int hashCode() { - return order != null ? order.hashCode() : 0; + int result = order != null ? order.hashCode() : 0; + result = 31 * result + (orderTotal != null ? orderTotal.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ApproveTaskDto{" + + "order=" + order + + ", orderTotal=" + orderTotal + + '}'; } } + diff --git a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/service/OrderRepository.java b/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/service/OrderRepository.java deleted file mode 100644 index 649a0182..00000000 --- a/example/example-java/src/main/java/io/holunda/camunda/bpm/data/example/service/OrderRepository.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.holunda.camunda.bpm.data.example.service; - -import io.holunda.camunda.bpm.data.example.domain.Order; -import io.holunda.camunda.bpm.data.example.domain.OrderPosition; -import org.springframework.stereotype.Component; - -import java.math.BigDecimal; -import java.sql.Date; -import java.time.Instant; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Component -public class OrderRepository { - - private final Map orders = new HashMap<>(); - - public OrderRepository() { - List positions = new ArrayList<>(); - positions.add(new OrderPosition("Pencil", BigDecimal.valueOf(1.50), 2L)); - positions.add(new OrderPosition("Pen", BigDecimal.valueOf(2.10), 2L)); - orders.put("1", new Order("1", Date.from(Instant.now()), positions)); - } - - - public Order loadOrder(String orderId) { - return orders.get(orderId); - } - -} diff --git a/example/example-java/src/main/resources/application.yaml b/example/example-java/src/main/resources/application.yaml index cdf71e8f..0f952828 100644 --- a/example/example-java/src/main/resources/application.yaml +++ b/example/example-java/src/main/resources/application.yaml @@ -7,6 +7,7 @@ spring: open-in-view: true camunda: bpm: + default-serialization-format: application/json admin-user: id: admin email: admin@localhost diff --git a/example/example-java/src/main/resources/order_approval.bpmn b/example/example-java/src/main/resources/order_approval.bpmn index 6b308cd0..69521f1c 100644 --- a/example/example-java/src/main/resources/order_approval.bpmn +++ b/example/example-java/src/main/resources/order_approval.bpmn @@ -13,20 +13,20 @@ SequenceFlow_0yomyfk SequenceFlow_1bg5dcq + + + DataObjectReference_0tq2vmr + Property_1fo4y4m + + + DataObjectReference_0843zr5 + - - - - ${!orderApproved} - - + SequenceFlow_0bu7jj9 xor_approved_yes xor_approved_no - - - Please approve order ${order.orderId}. @@ -37,6 +37,14 @@ SequenceFlow_19r0xpo SequenceFlow_0bu7jj9 + + + DataObjectReference_0o9907t + Property_0a3extx + + + DataObjectReference_10cvpxg + @@ -44,6 +52,21 @@ SequenceFlow_1bg5dcq SequenceFlow_19r0xpo + + + DataObjectReference_0843zr5 + Property_1wyqibd + + + DataObjectReference_08nw8lv + Property_1wyqibd + + + DataObjectReference_08nw8lv + + + DataObjectReference_0o9907t + @@ -52,75 +75,160 @@ xor_approved_no + + + + + + + + + + + + + + + ${!orderApproved} + + + - + - + - + - - + + - + - + - + - + - - + + - + - + - + - + - + - - - + + + - + - + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/process/GuardProcessTest.java b/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/process/GuardProcessTest.java index 27f376e2..95eb964e 100644 --- a/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/process/GuardProcessTest.java +++ b/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/process/GuardProcessTest.java @@ -2,6 +2,8 @@ import com.google.common.collect.Lists; import io.holunda.camunda.bpm.data.example.domain.Order; +import io.holunda.camunda.bpm.data.guard.integration.GuardViolationException; +import org.camunda.bpm.engine.ProcessEngineException; import org.camunda.bpm.engine.delegate.JavaDelegate; import org.camunda.bpm.engine.runtime.Job; import org.camunda.bpm.engine.task.Task; @@ -13,13 +15,12 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import java.sql.Date; import java.time.Instant; import java.util.ArrayList; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; @Deployment(resources = "order_approval.bpmn") @@ -28,8 +29,6 @@ public class GuardProcessTest { public final ProcessEngineRule rule = new StandaloneInMemoryTestConfiguration( Lists.newArrayList(new SpinProcessEnginePlugin()) ).rule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); @Before public void register() { @@ -54,33 +53,30 @@ public JavaDelegate calculateOrderPositions() { @Test public void shouldFireExceptionIfOrderIdIsMissing() { - thrown.expectMessage("Guard violated by execution '6' in activity 'Order created'"); + assertThrows( + GuardViolationException.class, + // manual start by-passing the factory + () -> rule.getRuntimeService().startProcessInstanceByKey(OrderApproval.KEY), + "Guard violated by execution '6' in activity 'Order created'\nExpecting variable 'orderId' to be set, but it was not found.\n"); - // manual start by-passing the factory - rule.getRuntimeService().startProcessInstanceByKey(OrderApproval.KEY); - fail("Should not get here"); } @Test public void shouldFireExceptionApproveDecisionIsMissing() { - thrown.expectMessage("Guard violated in task 'Approve order' (taskId: '21')"); - OrderApprovalInstanceFactory factory = new OrderApprovalInstanceFactory(rule.getRuntimeService()); - factory.start(); + factory.start("1"); // async after start Job asyncStart = rule.getManagementService().createJobQuery().singleResult(); rule.getManagementService().executeJob(asyncStart.getId()); - Task task = rule.getTaskService().createTaskQuery().singleResult(); - rule.getTaskService().complete(task.getId()); - - // async after user task - Job job = rule.getManagementService().createJobQuery().singleResult(); - rule.getManagementService().executeJob(job.getId()); - fail("Should not get here"); + assertThrows( + ProcessEngineException.class, + () -> rule.getTaskService().complete(task.getId()), + "Guard violated in task 'Approve order' (taskId: '21')\nExpecting variable 'orderApproved' to be set, but it was not found.\n" + ); } } diff --git a/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalProcessTest.java b/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalProcessTest.java new file mode 100644 index 00000000..a4d70126 --- /dev/null +++ b/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/process/OrderApprovalProcessTest.java @@ -0,0 +1,132 @@ +package io.holunda.camunda.bpm.data.example.process; + + +import com.google.common.collect.Lists; +import io.holunda.camunda.bpm.data.builder.VariableMapBuilder; +import io.holunda.camunda.bpm.data.example.domain.Order; +import io.holunda.camunda.bpm.data.example.domain.OrderPosition; +import org.camunda.bpm.engine.delegate.JavaDelegate; +import org.camunda.bpm.engine.test.Deployment; +import org.camunda.bpm.engine.test.ProcessEngineRule; +import org.camunda.bpm.engine.test.mock.Mocks; +import org.camunda.bpm.spring.boot.starter.test.helper.StandaloneInMemoryTestConfiguration; +import org.camunda.spin.plugin.impl.SpinProcessEnginePlugin; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.math.BigDecimal; +import java.sql.Date; +import java.time.Instant; + +import static io.holunda.camunda.bpm.data.example.process.OrderApproval.*; +import static io.holunda.camunda.bpm.data.example.process.OrderApproval.Elements.*; +import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.*; +import static org.junit.Assert.assertTrue; + +@Deployment(resources = "order_approval.bpmn") +public class OrderApprovalProcessTest { + + @Rule + public final ProcessEngineRule rule = new StandaloneInMemoryTestConfiguration( + Lists.newArrayList(new SpinProcessEnginePlugin()) + ).rule(); + + private OrderApprovalInstanceFactory factory; + + + @Before + public void register() { + factory = new OrderApprovalInstanceFactory(rule.getRuntimeService()); + OrderApproval config = new OrderApproval(); + Mocks.register("guardExecutionListener", config.guardExecutionListener()); + Mocks.register("guardTaskListener", config.guardTaskListener()); + Mocks.register("orderApproval", new MockOrderApproval()); + } + + @Test + public void shouldDeploy() { + // empty method body checks deployment + assertTrue(true); + } + + @Test + public void shouldStartAsync() { + OrderApprovalInstance instance = factory.start("1"); + + assertThat(instance.get()).isStarted(); + assertThat(instance.get()).isWaitingAt(element(start_order_created)); + } + + @Test + public void shouldStartAndWaitInUserTask() { + OrderApprovalInstance instance = factory.start("1"); + + assertThat(instance.get()).isStarted(); + + // pass async on start + execute(job()); + + assertThat(instance.get()).isWaitingAt(element(user_approve_order)); + } + + @Test + public void shouldStartAndWaitInUserTaskAndApprove() { + OrderApprovalInstance instance = factory.start("1"); + + assertThat(instance.get()).isStarted(); + + // pass async on start + execute(job()); + + // complete user task + complete(task(), new VariableMapBuilder().set(ORDER_APPROVED, true).build()); + // pass async oafter user task + execute(job()); + + assertThat(instance.get()).isEnded(); + assertThat(instance.get()).hasPassed(element(end_order_approved)); + } + + @Test + public void shouldStartAndWaitInUserTaskAndReject() { + OrderApprovalInstance instance = factory.start("1"); + + assertThat(instance.get()).isStarted(); + + // pass async on start + execute(job()); + + // complete user task + complete(task(), new VariableMapBuilder().set(ORDER_APPROVED, false).build()); + // pass async oafter user task + execute(job()); + + assertThat(instance.get()).isEnded(); + assertThat(instance.get()).hasPassed(element(end_order_rejected)); + } + + + /** + * Stub for the test. + */ + static class MockOrderApproval { + public JavaDelegate loadOrder() { + return execution -> { + ORDER.on(execution).set(new Order("1", Date.from(Instant.now()), Lists.newArrayList( + new OrderPosition("Pencil", BigDecimal.valueOf(1.99), 3L), + new OrderPosition("Sheet", BigDecimal.valueOf(0.17), 3L) + ))); + }; + } + + public JavaDelegate calculateOrderPositions() { + return execution -> { + ORDER_TOTAL.on(execution).set(BigDecimal.valueOf(6.48)); + }; + } + + public JavaDelegate writeOrderTotal() { return execution -> {}; } + } + +} diff --git a/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskControllerTest.java b/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskControllerTest.java index a903bd6b..a3eac7c9 100644 --- a/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskControllerTest.java +++ b/example/example-java/src/test/java/io/holunda/camunda/bpm/data/example/rest/ApproveOrderTaskControllerTest.java @@ -3,60 +3,67 @@ import io.holunda.camunda.bpm.data.example.domain.Order; import io.holunda.camunda.bpm.data.mockito.TaskServiceMockVerifier; import org.camunda.bpm.engine.TaskService; -import org.camunda.bpm.engine.variable.VariableMap; +import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.UUID; import static io.holunda.camunda.bpm.data.CamundaBpmData.builder; -import static io.holunda.camunda.bpm.data.example.process.OrderApproval.ORDER; -import static io.holunda.camunda.bpm.data.example.process.OrderApproval.ORDER_APPROVED; +import static io.holunda.camunda.bpm.data.example.process.OrderApproval.*; import static io.holunda.camunda.bpm.data.mockito.CamundaBpmDataMockito.taskServiceMockVerifier; import static io.holunda.camunda.bpm.data.mockito.CamundaBpmDataMockito.taskServiceVariableMockBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; /** * Demonstrates the usage of Task Service Variable Mock Builder and Task Service Verifier. */ public class ApproveOrderTaskControllerTest { - private static Order order = new Order("ORDER-ID-1", new Date(), new ArrayList<>()); - private TaskService taskService = mock(TaskService.class); - private TaskServiceMockVerifier verifier = taskServiceMockVerifier(taskService); - private ApproveOrderTaskController controller = new ApproveOrderTaskController(taskService); + private final static Order order = new Order("ORDER-ID-1", new Date(), new ArrayList<>()); + private final TaskService taskService = mock(TaskService.class); + private final TaskServiceMockVerifier verifier = taskServiceMockVerifier(taskService); + private final ApproveOrderTaskController controller = new ApproveOrderTaskController(taskService); + private String taskId; + + @Before + public void prepareTest() { + reset(taskService); + taskId = UUID.randomUUID().toString(); + } @Test public void testLoadTask() { - // given - String taskId = UUID.randomUUID().toString(); - taskServiceVariableMockBuilder(taskService).initial(ORDER, order).build(); + taskServiceVariableMockBuilder(taskService) + .initial(ORDER, order) + .initial(ORDER_TOTAL, BigDecimal.ZERO) + .build(); // when ResponseEntity responseEntity = controller.loadTask(taskId); // then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(responseEntity.getBody()).isEqualTo(new ApproveTaskDto(order)); + assertThat(responseEntity.getBody()).isEqualTo(new ApproveTaskDto(order, BigDecimal.ZERO)); verifier.verifyGet(ORDER, taskId); + verifier.verifyGet(ORDER_TOTAL, taskId); verifier.verifyNoMoreInteractions(); } @Test public void testCompleteTask() { - - // given - String taskId = UUID.randomUUID().toString(); // when ApproveTaskCompleteDto response = new ApproveTaskCompleteDto(true); ResponseEntity responseEntity = controller.completeTask(taskId, response); // then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - VariableMap variables = builder().set(ORDER_APPROVED, response.getApproved()).build(); - verifier.verifyComplete(variables, taskId); + verifier.verifyComplete(builder().set(ORDER_APPROVED, response.getApproved()).build(), taskId); verifier.verifyNoMoreInteractions(); } + } diff --git a/example/example-kotlin/pom.xml b/example/example-kotlin/pom.xml index abaa5bed..57b91c13 100644 --- a/example/example-kotlin/pom.xml +++ b/example/example-kotlin/pom.xml @@ -6,12 +6,11 @@ io.holunda.data.example camunda-bpm-data-example-parent - 0.0.6 + 1.0.0 camunda-bpm-data-example-kotlin ${project.artifactId} - jar false @@ -23,8 +22,56 @@ camunda-bpm-data - io.holunda.data - camunda-bpm-data-kotlin + io.holunda.data.example + camunda-bpm-data-spin-type-detector + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.camunda.bpm.springboot + camunda-bpm-spring-boot-starter-rest + + + org.camunda.bpm + camunda-engine-plugin-spin + + + org.camunda.spin + camunda-spin-core + + + org.camunda.spin + camunda-spin-dataformat-json-jackson + + + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.module + jackson-module-kotlin + + + + org.codehaus.groovy + groovy-all + + + com.h2database + h2 @@ -63,15 +110,49 @@ io.toolisticon.springboot springboot-swagger-starter - 0.0.4 + + + + io.holunda.data + camunda-bpm-data-test + test + + + + io.holunda.testing + camunda-bpm-jgiven + + + com.tngtech.jgiven + jgiven-junit + + + org.springframework.boot + spring-boot-starter-test + test + + + org.jetbrains.kotlin kotlin-maven-plugin + + org.springframework.boot + spring-boot-maven-plugin + + + com.tngtech.jgiven + jgiven-maven-plugin + + + org.jacoco + jacoco-maven-plugin + diff --git a/example/example-kotlin/src/main/kotlin/CamundaBpmDataKotlinExample.kt b/example/example-kotlin/src/main/kotlin/CamundaBpmDataKotlinExample.kt index bc6977ff..e8a4b708 100644 --- a/example/example-kotlin/src/main/kotlin/CamundaBpmDataKotlinExample.kt +++ b/example/example-kotlin/src/main/kotlin/CamundaBpmDataKotlinExample.kt @@ -23,6 +23,6 @@ class CamundaBpmDataKotlinExampleApplication { @EventListener fun onDeploy(event: PostDeployEvent) { - orderApprovalInstanceFactory.start() + orderApprovalInstanceFactory.start("1") } } diff --git a/example/example-kotlin/src/main/kotlin/domain/Order.kt b/example/example-kotlin/src/main/kotlin/domain/Order.kt index 1fd8e5e0..68e6740d 100644 --- a/example/example-kotlin/src/main/kotlin/domain/Order.kt +++ b/example/example-kotlin/src/main/kotlin/domain/Order.kt @@ -2,8 +2,20 @@ package io.holunda.camunda.bpm.data.example.kotlin.domain import java.util.* +/** + * Order business entity. + */ data class Order( - val orderId: String, - val created: Date, - val positions: List = listOf() + /** + * Order id. + */ + val orderId: String, + /** + * Order create date. + */ + val created: Date, + /** + * List of order positions. + */ + val positions: List = listOf() ) diff --git a/example/example-kotlin/src/main/kotlin/domain/OrderPosition.kt b/example/example-kotlin/src/main/kotlin/domain/OrderPosition.kt index d2161532..d4e8d74d 100644 --- a/example/example-kotlin/src/main/kotlin/domain/OrderPosition.kt +++ b/example/example-kotlin/src/main/kotlin/domain/OrderPosition.kt @@ -2,8 +2,20 @@ package io.holunda.camunda.bpm.data.example.kotlin.domain import java.math.BigDecimal +/** + * Order position business entity. + */ data class OrderPosition( - val title: String, - val netCost: BigDecimal, - val amount: Long + /** + * Title. + */ + val title: String, + /** + * Net cost per unit. + */ + val netCost: BigDecimal, + /** + * Amount (number of units). + */ + val amount: Long ) diff --git a/example/example-kotlin/src/main/kotlin/domain/OrderRepository.kt b/example/example-kotlin/src/main/kotlin/domain/OrderRepository.kt new file mode 100644 index 00000000..5bd92d5a --- /dev/null +++ b/example/example-kotlin/src/main/kotlin/domain/OrderRepository.kt @@ -0,0 +1,27 @@ +package io.holunda.camunda.bpm.data.example.kotlin.domain + +import org.springframework.stereotype.Component +import java.math.BigDecimal +import java.sql.Date +import java.time.Instant + +/** + * Repository. + */ +@Component +class OrderRepository { + + val orders = mapOf("1" to Order( + orderId = "1", + created = Date.from(Instant.now()), + positions = listOf( + OrderPosition(title = "Pencil", netCost = BigDecimal.valueOf(1.50), amount = 2), + OrderPosition(title = "Pen", netCost = BigDecimal.valueOf(2.10), amount = 2) + ) + )) + + + fun loadOrder(orderId: String): Order { + return orders.getValue(orderId) + } +} diff --git a/example/example-kotlin/src/main/kotlin/process/OrderApproval.kt b/example/example-kotlin/src/main/kotlin/process/OrderApproval.kt index 5875ae2d..00fbf173 100644 --- a/example/example-kotlin/src/main/kotlin/process/OrderApproval.kt +++ b/example/example-kotlin/src/main/kotlin/process/OrderApproval.kt @@ -9,10 +9,8 @@ import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variable import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variables.ORDER_ID import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variables.ORDER_POSITION import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variables.ORDER_TOTAL -import io.holunda.camunda.bpm.data.example.kotlin.service.OrderRepository +import io.holunda.camunda.bpm.data.example.kotlin.domain.OrderRepository import io.holunda.camunda.bpm.data.factory.VariableFactory -import io.holunda.camunda.bpm.data.remove -import io.holunda.camunda.bpm.data.set import mu.KLogging import org.camunda.bpm.engine.delegate.DelegateExecution import org.camunda.bpm.engine.delegate.DelegateTask @@ -24,70 +22,73 @@ import org.springframework.context.annotation.Configuration import org.springframework.context.event.EventListener import java.math.BigDecimal +/** + * Backing bean. + */ @Configuration class OrderApproval { - @Autowired - lateinit var orderRepository: OrderRepository + @Autowired + lateinit var orderRepository: OrderRepository - companion object : KLogging() { - const val KEY = "order-approval" - } + companion object : KLogging() { + const val KEY = "order-approval" + } - object Variables { - val ORDER_ID = stringVariable("orderId") - val ORDER: VariableFactory = customVariable("order") - val ORDER_APPROVED = booleanVariable("orderApproved") - val ORDER_POSITION: VariableFactory = customVariable("orderPosition") - val ORDER_TOTAL: VariableFactory = customVariable("orderTotal") - } + object Variables { + val ORDER_ID = stringVariable("orderId") + val ORDER: VariableFactory = customVariable("order") + val ORDER_APPROVED = booleanVariable("orderApproved") + val ORDER_POSITION: VariableFactory = customVariable("orderPosition") + val ORDER_TOTAL: VariableFactory = customVariable("orderTotal") + } - /** - * Load a primitive variable by id (string) and store a complex variable (order). - */ - @Bean - fun loadOrder() = JavaDelegate { execution -> - val orderId = ORDER_ID.from(execution).get() - val order = orderRepository.loadOrder(orderId) - ORDER.on(execution).set(order) - ORDER_TOTAL.on(execution).set(BigDecimal.ZERO) - } + /** + * Load a primitive variable by id (string) and store a complex variable (order). + */ + @Bean + fun loadOrder() = JavaDelegate { execution -> + val orderId = ORDER_ID.from(execution).get() + val order = orderRepository.loadOrder(orderId) + ORDER.on(execution).set(order) + ORDER_TOTAL.on(execution).set(BigDecimal.ZERO) + } - /** - * Load a local order position, write a local variable. - */ - @Bean - fun calculateOrderPositions() = JavaDelegate { execution -> - val orderPosition = ORDER_POSITION.from(execution).get() + /** + * Load a local order position, write a local variable. + */ + @Bean + fun calculateOrderPositions() = JavaDelegate { execution -> + val orderPosition = ORDER_POSITION.from(execution).get() - ORDER_TOTAL.on(execution).update { it.plus(orderPosition.netCost.times(BigDecimal.valueOf(orderPosition.amount))) } - } + ORDER_TOTAL.on(execution).update { it.plus(orderPosition.netCost.times(BigDecimal.valueOf(orderPosition.amount))) } + } - /** - * Read a local variable and store it in global variable. - */ - @Bean - fun writeOrderTotal() = ExecutionListener { execution -> - val total = ORDER_TOTAL.from(execution).get() - ORDER_TOTAL.on(execution).set(total) - } + /** + * Read a local variable and store it in global variable. + */ + @Bean + fun writeOrderTotal() = ExecutionListener { execution -> + val total = ORDER_TOTAL.from(execution).get() + ORDER_TOTAL.on(execution).set(total) + } - /** - * Log the task id. - */ - @EventListener(condition = "#task != null && #task.eventName == 'create'") - fun taskLogger(task: DelegateTask) { - logger.info("TASK LOGGER: Created user task ${task.id}") - } + /** + * Log the task id. + */ + @EventListener(condition = "#task != null && #task.eventName == 'create'") + fun taskLogger(task: DelegateTask) { + logger.info("TASK LOGGER: Created user task ${task.id}") + } - @EventListener(condition = "#execution != null && #execution.eventName == 'start' && #execution.currentActivityId == 'start_order_created'") - fun processStartLogger(execution: DelegateExecution) { - logger.info { "INSTANCE LOGGER: Started process instance ${execution.processInstanceId}" } - } + @EventListener(condition = "#execution != null && #execution.eventName == 'start' && #execution.currentActivityId == 'start_order_created'") + fun processStartLogger(execution: DelegateExecution) { + logger.info { "INSTANCE LOGGER: Started process instance ${execution.processInstanceId}" } + } - @EventListener(condition = "#execution != null && #execution.eventName == 'end' && #execution.currentActivityId == 'end_order_approved'") - fun processEndLogger(execution: DelegateExecution) { - logger.info { "INSTANCE LOGGER: Finished process instance ${execution.processInstanceId}" } - } + @EventListener(condition = "#execution != null && #execution.eventName == 'end' && #execution.currentActivityId == 'end_order_approved'") + fun processEndLogger(execution: DelegateExecution) { + logger.info { "INSTANCE LOGGER: Finished process instance ${execution.processInstanceId}" } + } } diff --git a/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstance.kt b/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstance.kt index cc270e86..83f78049 100644 --- a/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstance.kt +++ b/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstance.kt @@ -1,12 +1,10 @@ package io.holunda.camunda.bpm.data.example.kotlin.process -import org.camunda.bpm.engine.RuntimeService -import org.camunda.bpm.engine.TaskService import org.camunda.bpm.engine.runtime.ProcessInstance /** * Represents order delivery process instance. */ class OrderApprovalInstance( - private val delegate: ProcessInstance) : ProcessInstance by delegate { + private val delegate: ProcessInstance) : ProcessInstance by delegate { } diff --git a/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstanceFactory.kt b/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstanceFactory.kt index bf09592c..49a90a7a 100644 --- a/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstanceFactory.kt +++ b/example/example-kotlin/src/main/kotlin/process/OrderApprovalInstanceFactory.kt @@ -1,24 +1,27 @@ package io.holunda.camunda.bpm.data.example.kotlin.process -import io.holunda.camunda.bpm.data.builder +import io.holunda.camunda.bpm.data.builder.VariableMapBuilder import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variables.ORDER_ID import org.camunda.bpm.engine.RuntimeService import org.camunda.bpm.engine.variable.Variables.createVariables import org.springframework.stereotype.Component import java.util.* +/** + * Instance factory. + */ @Component class OrderApprovalInstanceFactory( - private val runtimeService: RuntimeService + private val runtimeService: RuntimeService ) { - fun start(): OrderApprovalInstance { - val vars = createVariables() - ORDER_ID.on(vars).set("1") - val instance = runtimeService.startProcessInstanceByKey(OrderApproval.KEY, "order-${UUID.randomUUID()}", vars) - return OrderApprovalInstance(instance) - } + /** + * Starts the approval process. + */ + fun start(id: String): OrderApprovalInstance { + val vars = VariableMapBuilder().set(ORDER_ID, id).build() + val instance = runtimeService.startProcessInstanceByKey(OrderApproval.KEY, "order-${UUID.randomUUID()}", vars) + return OrderApprovalInstance(instance) + } - fun setVariables(executionId: String) { - } } diff --git a/example/example-kotlin/src/main/kotlin/rest/ApproveOrderTaskController.kt b/example/example-kotlin/src/main/kotlin/rest/ApproveOrderTaskController.kt index 2106b6de..981f32ea 100644 --- a/example/example-kotlin/src/main/kotlin/rest/ApproveOrderTaskController.kt +++ b/example/example-kotlin/src/main/kotlin/rest/ApproveOrderTaskController.kt @@ -3,10 +3,12 @@ package io.holunda.camunda.bpm.data.example.kotlin.rest import io.holunda.camunda.bpm.data.example.kotlin.domain.Order import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variables.ORDER import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variables.ORDER_APPROVED +import io.holunda.camunda.bpm.data.example.kotlin.process.OrderApproval.Variables.ORDER_TOTAL import org.camunda.bpm.engine.TaskService import org.camunda.bpm.engine.variable.Variables.createVariables import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* +import java.math.BigDecimal @RestController @RequestMapping("/task/approve-order") @@ -17,7 +19,8 @@ class ApproveOrderTaskController( @GetMapping("/{taskId}") fun loadTask(@PathVariable("taskId") taskId: String): ResponseEntity { val order = ORDER.from(taskService, taskId).get() - return ResponseEntity.ok(ApproveTaskDto(order)) + val orderTotal = ORDER_TOTAL.from(taskService, taskId).get() + return ResponseEntity.ok(ApproveTaskDto(order, orderTotal)) } @PostMapping("/{taskId}") @@ -29,6 +32,6 @@ class ApproveOrderTaskController( } } -data class ApproveTaskDto(val order: Order) +data class ApproveTaskDto(val order: Order, val orderTotal: BigDecimal) data class ApproveTaskCompleteDto(val approved: Boolean) diff --git a/example/example-kotlin/src/main/kotlin/service/OrderRepository.kt b/example/example-kotlin/src/main/kotlin/service/OrderRepository.kt deleted file mode 100644 index fc45d7ca..00000000 --- a/example/example-kotlin/src/main/kotlin/service/OrderRepository.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.holunda.camunda.bpm.data.example.kotlin.service - -import io.holunda.camunda.bpm.data.example.kotlin.domain.Order -import io.holunda.camunda.bpm.data.example.kotlin.domain.OrderPosition -import org.springframework.stereotype.Component -import java.math.BigDecimal -import java.sql.Date -import java.time.Instant - -@Component -class OrderRepository { - - val orders = mapOf("1" to Order( - orderId = "1", - created = Date.from(Instant.now()), - positions = listOf( - OrderPosition(title = "Pencil", netCost = BigDecimal.valueOf(1.50), amount = 2), - OrderPosition(title = "Pen", netCost = BigDecimal.valueOf(2.10), amount = 2) - ) - )) - - - fun loadOrder(orderId: String): Order { - return orders.getValue(orderId) - } -} diff --git a/example/example-kotlin/src/main/kotlin/spin/JacksonDataFormatConfigurator.kt b/example/example-kotlin/src/main/kotlin/spin/JacksonDataFormatConfigurator.kt deleted file mode 100644 index 025ca64a..00000000 --- a/example/example-kotlin/src/main/kotlin/spin/JacksonDataFormatConfigurator.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.holunda.camunda.bpm.data.example.kotlin.spin - -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule -import com.fasterxml.jackson.module.kotlin.KotlinModule -import org.camunda.spin.impl.json.jackson.format.JacksonJsonDataFormat -import org.camunda.spin.spi.DataFormatConfigurator - -class JacksonDataFormatConfigurator : DataFormatConfigurator { - - override fun configure(dataFormat: JacksonJsonDataFormat) { - val objectMapper = dataFormat.objectMapper - objectMapper.registerModule(KotlinModule()) - objectMapper.registerModule(JavaTimeModule()) - } - - override fun getDataFormatClass(): Class = JacksonJsonDataFormat::class.java - -} diff --git a/example/example-kotlin/src/main/kotlin/spin/KotlinJacksonDataFormatConfigurator.kt b/example/example-kotlin/src/main/kotlin/spin/KotlinJacksonDataFormatConfigurator.kt new file mode 100644 index 00000000..84821e8c --- /dev/null +++ b/example/example-kotlin/src/main/kotlin/spin/KotlinJacksonDataFormatConfigurator.kt @@ -0,0 +1,17 @@ +package io.holunda.camunda.bpm.data.example.kotlin.spin + +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.module.kotlin.KotlinModule +import org.camunda.spin.impl.json.jackson.format.JacksonJsonDataFormat +import org.camunda.spin.spi.DataFormatConfigurator + +class KotlinJacksonDataFormatConfigurator : DataFormatConfigurator { + + override fun configure(dataFormat: JacksonJsonDataFormat) { + val objectMapper = dataFormat.objectMapper + objectMapper.registerModule(KotlinModule()) + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + } + + override fun getDataFormatClass(): Class = JacksonJsonDataFormat::class.java +} \ No newline at end of file diff --git a/example/example-kotlin/src/main/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator b/example/example-kotlin/src/main/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator index 0869c041..f2b7e915 100644 --- a/example/example-kotlin/src/main/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator +++ b/example/example-kotlin/src/main/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator @@ -1 +1 @@ -io.holunda.camunda.bpm.data.example.kotlin.spin.JacksonDataFormatConfigurator +io.holunda.camunda.bpm.data.example.kotlin.spin.KotlinJacksonDataFormatConfigurator diff --git a/example/example-kotlin/src/main/resources/application.yml b/example/example-kotlin/src/main/resources/application.yml index 90ad96ad..eb81d18a 100644 --- a/example/example-kotlin/src/main/resources/application.yml +++ b/example/example-kotlin/src/main/resources/application.yml @@ -7,6 +7,7 @@ spring: open-in-view: true camunda: bpm: + default-serialization-format: application/json filter: create: All Tasks admin-user: diff --git a/example/example-kotlin/src/test/kotlin/itest/CamundaBpmDataITestBase.kt b/example/example-kotlin/src/test/kotlin/itest/CamundaBpmDataITestBase.kt index c7ef35e2..d6ad5b42 100644 --- a/example/example-kotlin/src/test/kotlin/itest/CamundaBpmDataITestBase.kt +++ b/example/example-kotlin/src/test/kotlin/itest/CamundaBpmDataITestBase.kt @@ -9,11 +9,23 @@ import com.tngtech.jgiven.integration.spring.EnableJGiven import com.tngtech.jgiven.integration.spring.JGivenStage import com.tngtech.jgiven.integration.spring.SpringScenarioTest import io.holunda.camunda.bpm.data.CamundaBpmData.* +import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.customVariable +import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.dateVariable +import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.listVariable +import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.mapVariable +import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.setVariable +import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.stringVariable import io.holunda.camunda.bpm.data.factory.VariableFactory import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.BOOLEAN import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.BOOLEAN_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_LIST +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_LIST_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_LOCAL +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_MAP +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_MAP_LOCAL +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_SET +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_SET_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.DATE import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.DATE_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.DOUBLE @@ -24,8 +36,8 @@ import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Value import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_STRING_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LONG import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LONG_LOCAL -import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_DATE import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_DATE_LOCAL +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_LONG import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SET_STRING import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SET_STRING_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SHORT @@ -63,7 +75,7 @@ import java.util.* /** * Alias for the when */ -fun ScenarioTestBase.whenever() = `when`() +fun ScenarioTestBase.whenever(): W = `when`() /** * Base for ITests. @@ -73,459 +85,523 @@ fun ScenarioTestBase.whenever() = `when`() @ActiveProfiles("itest") abstract class CamundaBpmDataITestBase : SpringScenarioTest() { - companion object { - - val STRING_VAR: VariableFactory = stringVariable("String Variable") - val DATE_VAR: VariableFactory = dateVariable("Date Variable") - val SHORT_VAR: VariableFactory = shortVariable("Short Variable") - val INT_VAR: VariableFactory = intVariable("Int Variable") - val LONG_VAR: VariableFactory = longVariable("Long Variable") - val DOUBLE_VAR: VariableFactory = doubleVariable("Double Variable") - val BOOLEAN_VAR: VariableFactory = booleanVariable("Boolean Variable") - val COMPLEX_VAR: VariableFactory = customVariable("Complex Variable", ComplexDataStructure::class.java) - val LIST_STRING_VAR: VariableFactory> = listVariable("List Of String Variable", String::class.java) - val SET_STRING_VAR: VariableFactory> = setVariable("Set Of String Variable", String::class.java) - val MAP_STRING_DATE_VAR: VariableFactory> = mapVariable("Map Of String to Date Variable", String::class.java, Date::class.java) - - object Values { - private val now = Date.from(Instant.now()) - private val yesterday = Date.from(Instant.now().minus(1, ChronoUnit.DAYS)) - - val STRING = VariableValue(STRING_VAR, "value") - val DATE = VariableValue(DATE_VAR, now) - val SHORT = VariableValue(SHORT_VAR, 11.toShort()) - val INT = VariableValue(INT_VAR, 123) - val LONG = VariableValue(LONG_VAR, 812L) - val DOUBLE = VariableValue(DOUBLE_VAR, 12.0) - val BOOLEAN = VariableValue(BOOLEAN_VAR, true) - val COMPLEX = VariableValue(COMPLEX_VAR, ComplexDataStructure("string", 17, now)) - val LIST_STRING = VariableValue(LIST_STRING_VAR, listOf("Hello", "World")) - val SET_STRING = VariableValue(SET_STRING_VAR, setOf("Kermit", "Piggy")) - val MAP_STRING_DATE = VariableValue(MAP_STRING_DATE_VAR, mapOf("Twelve" to now, "Eleven" to now)) - - val STRING_LOCAL = VariableValue(STRING_VAR, "localValue") - val DATE_LOCAL = VariableValue(DATE_VAR, yesterday) - val SHORT_LOCAL = VariableValue(SHORT_VAR, 12.toShort()) - val INT_LOCAL = VariableValue(INT_VAR, 124) - val LONG_LOCAL = VariableValue(LONG_VAR, 815L) - val DOUBLE_LOCAL = VariableValue(DOUBLE_VAR, 14.0) - val BOOLEAN_LOCAL = VariableValue(BOOLEAN_VAR, false) - val COMPLEX_LOCAL = VariableValue(COMPLEX_VAR, ComplexDataStructure("foobar", 12, yesterday)) - val LIST_STRING_LOCAL = VariableValue(LIST_STRING_VAR, listOf("Foo", "Bar")) - val SET_STRING_LOCAL = VariableValue(SET_STRING_VAR, setOf("Homer", "Marge")) - val MAP_STRING_DATE_LOCAL = VariableValue(MAP_STRING_DATE_VAR, mapOf("Ten" to yesterday, "Nine" to yesterday)) + companion object { + + val STRING_VAR: VariableFactory = stringVariable("String Variable") + val DATE_VAR: VariableFactory = dateVariable("Date Variable") + val SHORT_VAR: VariableFactory = shortVariable("Short Variable") + val INT_VAR: VariableFactory = intVariable("Int Variable") + val LONG_VAR: VariableFactory = longVariable("Long Variable") + val DOUBLE_VAR: VariableFactory = doubleVariable("Double Variable") + val BOOLEAN_VAR: VariableFactory = booleanVariable("Boolean Variable") + val COMPLEX_VAR: VariableFactory = customVariable("Complex Variable") + val LIST_STRING_VAR: VariableFactory> = listVariable("List Of String Variable") + val SET_STRING_VAR: VariableFactory> = setVariable("Set Of String Variable") + val MAP_STRING_LONG_VAR: VariableFactory> = mapVariable("Map Of String to String Variable") + val COMPLEX_SET_VAR: VariableFactory> = setVariable("Complex Set") + val COMPLEX_LIST_VAR: VariableFactory> = listVariable("Complex List") + val COMPLEX_MAP_VAR: VariableFactory> = mapVariable("Complex Map") + + object Values { + val now = Date.from(Instant.now()) + val yesterday = Date.from(Instant.now().minus(1, ChronoUnit.DAYS)) + + val STRING = VariableValue(STRING_VAR, "value") + val DATE = VariableValue(DATE_VAR, now) + val SHORT = VariableValue(SHORT_VAR, 11.toShort()) + val INT = VariableValue(INT_VAR, 123) + val LONG = VariableValue(LONG_VAR, 812L) + val DOUBLE = VariableValue(DOUBLE_VAR, 12.0) + val BOOLEAN = VariableValue(BOOLEAN_VAR, true) + val COMPLEX = VariableValue(COMPLEX_VAR, ComplexDataStructure("string", 17, now)) + val LIST_STRING = VariableValue(LIST_STRING_VAR, listOf("Hello", "World")) + val SET_STRING = VariableValue(SET_STRING_VAR, setOf("Kermit", "Piggy")) + val MAP_STRING_LONG = VariableValue(MAP_STRING_LONG_VAR, mapOf("Twelve" to now.toString(), "Eleven" to now.toString())) + val COMPLEX_SET = VariableValue(COMPLEX_SET_VAR, setOf( + ComplexDataStructure("one", 1, now), + ComplexDataStructure("two", 2, yesterday) + )) + val COMPLEX_LIST = VariableValue(COMPLEX_LIST_VAR, listOf( + ComplexDataStructure("one", 1, now), + ComplexDataStructure("two", 2, yesterday) + )) + val COMPLEX_MAP = VariableValue(COMPLEX_MAP_VAR, mapOf( + "1" to ComplexDataStructure("one", 1, now), + "2" to ComplexDataStructure("two", 2, yesterday) + )) + + val STRING_LOCAL = VariableValue(STRING_VAR, "localValue") + val DATE_LOCAL = VariableValue(DATE_VAR, yesterday) + val SHORT_LOCAL = VariableValue(SHORT_VAR, 12.toShort()) + val INT_LOCAL = VariableValue(INT_VAR, 124) + val LONG_LOCAL = VariableValue(LONG_VAR, 815L) + val DOUBLE_LOCAL = VariableValue(DOUBLE_VAR, 14.0) + val BOOLEAN_LOCAL = VariableValue(BOOLEAN_VAR, false) + val COMPLEX_LOCAL = VariableValue(COMPLEX_VAR, ComplexDataStructure("foobar", 12, yesterday)) + val LIST_STRING_LOCAL = VariableValue(LIST_STRING_VAR, listOf("Foo", "Bar")) + val SET_STRING_LOCAL = VariableValue(SET_STRING_VAR, setOf("Homer", "Marge")) + val MAP_STRING_DATE_LOCAL = VariableValue(MAP_STRING_LONG_VAR, mapOf("Ten" to yesterday.toString(), "Nine" to yesterday.toString())) + val COMPLEX_SET_LOCAL = VariableValue(COMPLEX_SET_VAR, setOf( + ComplexDataStructure("one local", 1, now), + ComplexDataStructure("two local", 2, yesterday) + )) + val COMPLEX_LIST_LOCAL = VariableValue(COMPLEX_LIST_VAR, listOf( + ComplexDataStructure("one local", 1, now), + ComplexDataStructure("two local", 2, yesterday) + )) + val COMPLEX_MAP_LOCAL = VariableValue(COMPLEX_MAP_VAR, mapOf( + "1" to ComplexDataStructure("one local", 1, now), + "2" to ComplexDataStructure("two local", 2, yesterday) + )) + } + + private val allValues = mapOf( + COMPLEX_SET_VAR to COMPLEX_SET, + COMPLEX_LIST_VAR to COMPLEX_LIST, + COMPLEX_MAP_VAR to COMPLEX_MAP, + STRING_VAR to STRING, + DATE_VAR to DATE, + SHORT_VAR to SHORT, + INT_VAR to INT, + LONG_VAR to LONG, + DOUBLE_VAR to DOUBLE, + BOOLEAN_VAR to BOOLEAN, + COMPLEX_VAR to COMPLEX, + LIST_STRING_VAR to LIST_STRING, + SET_STRING_VAR to SET_STRING, + MAP_STRING_LONG_VAR to MAP_STRING_LONG + ) + + private val allLocalValues = mapOf( + COMPLEX_SET_VAR to COMPLEX_SET_LOCAL, + COMPLEX_LIST_VAR to COMPLEX_LIST_LOCAL, + COMPLEX_MAP_VAR to COMPLEX_MAP_LOCAL, + STRING_VAR to STRING_LOCAL, + DATE_VAR to DATE_LOCAL, + SHORT_VAR to SHORT_LOCAL, + INT_VAR to INT_LOCAL, + LONG_VAR to LONG_LOCAL, + DOUBLE_VAR to DOUBLE_LOCAL, + BOOLEAN_VAR to BOOLEAN_LOCAL, + COMPLEX_VAR to COMPLEX_LOCAL, + LIST_STRING_VAR to LIST_STRING_LOCAL, + SET_STRING_VAR to SET_STRING_LOCAL, + MAP_STRING_LONG_VAR to MAP_STRING_DATE_LOCAL + ) + + fun createVariableMapUntyped(): VariableMap { + val variables = createVariables() + allValues.values.forEach { + variables.putValue(it.variable.name, it.value) + } + return variables + } + + fun createKeyValuePairs(): Set, Any>> { + return allValues.entries.map { Pair(it.key, it.value.value) }.toSet() + } + + fun createKeyLocalValuePairs(): Set, Any>> { + return allLocalValues.entries.map { Pair(it.key, it.value.value) }.toSet() + } } - private val allValues = mapOf( - STRING_VAR to STRING, - DATE_VAR to DATE, - SHORT_VAR to SHORT, - INT_VAR to INT, - LONG_VAR to LONG, - DOUBLE_VAR to DOUBLE, - BOOLEAN_VAR to BOOLEAN, - COMPLEX_VAR to COMPLEX, - LIST_STRING_VAR to LIST_STRING, - SET_STRING_VAR to SET_STRING, - MAP_STRING_DATE_VAR to MAP_STRING_DATE - ) + @Configuration + class DelegateConfiguration { + + val vars = HashMap() + val optionalVars = HashMap>() + var variableMap: VariableMap = createVariables() + + @Bean + fun serviceWriteAdapter() = JavaDelegate { delegateExecution -> + variableMap = delegateExecution.variablesTyped + } + + @Bean + fun readOptionalFromVariableScope() = JavaDelegate { delegateExecution -> + optionalVars[STRING_VAR.name] = STRING_VAR.from(delegateExecution).optional + optionalVars[DATE_VAR.name] = DATE_VAR.from(delegateExecution).optional + optionalVars[SHORT_VAR.name] = SHORT_VAR.from(delegateExecution).optional + optionalVars[INT_VAR.name] = INT_VAR.from(delegateExecution).optional + optionalVars[LONG_VAR.name] = LONG_VAR.from(delegateExecution).optional + optionalVars[DOUBLE_VAR.name] = DOUBLE_VAR.from(delegateExecution).optional + optionalVars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(delegateExecution).optional + optionalVars[COMPLEX_VAR.name] = COMPLEX_VAR.from(delegateExecution).optional + optionalVars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(delegateExecution).optional + optionalVars[SET_STRING_VAR.name] = SET_STRING_VAR.from(delegateExecution).optional + optionalVars[MAP_STRING_LONG_VAR.name] = MAP_STRING_LONG_VAR.from(delegateExecution).optional + optionalVars[COMPLEX_SET_VAR.name] = COMPLEX_SET_VAR.from(delegateExecution).optional + optionalVars[COMPLEX_LIST_VAR.name] = COMPLEX_LIST_VAR.from(delegateExecution).optional + optionalVars[COMPLEX_MAP_VAR.name] = COMPLEX_MAP_VAR.from(delegateExecution).optional + } + + @Bean + fun readFromVariableScope() = JavaDelegate { delegateExecution -> + vars[STRING_VAR.name] = STRING_VAR.from(delegateExecution).get() + vars[DATE_VAR.name] = DATE_VAR.from(delegateExecution).get() + vars[SHORT_VAR.name] = SHORT_VAR.from(delegateExecution).get() + vars[INT_VAR.name] = INT_VAR.from(delegateExecution).get() + vars[LONG_VAR.name] = LONG_VAR.from(delegateExecution).get() + vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(delegateExecution).get() + vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(delegateExecution).get() + vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(delegateExecution).get() + vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(delegateExecution).get() + vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(delegateExecution).get() + vars[MAP_STRING_LONG_VAR.name] = MAP_STRING_LONG_VAR.from(delegateExecution).get() + vars[COMPLEX_SET_VAR.name] = COMPLEX_SET_VAR.from(delegateExecution).get() + vars[COMPLEX_LIST_VAR.name] = COMPLEX_LIST_VAR.from(delegateExecution).get() + vars[COMPLEX_MAP_VAR.name] = COMPLEX_MAP_VAR.from(delegateExecution).get() + } + + @Bean + fun readLocalFromVariableScope() = JavaDelegate { delegateExecution -> + readLocalVarsFromVariableScope(variableScope = delegateExecution) + } + + @Bean + fun readLocalFromDelegateTask() = TaskListener { delegateTask -> + readLocalVarsFromVariableScope(variableScope = delegateTask) + } + + /** + * Writes local properties from variable scope. + */ + private fun readLocalVarsFromVariableScope(variableScope: VariableScope) { + vars[STRING_VAR.name] = STRING_VAR.from(variableScope).local + vars[DATE_VAR.name] = DATE_VAR.from(variableScope).local + vars[SHORT_VAR.name] = SHORT_VAR.from(variableScope).local + vars[INT_VAR.name] = INT_VAR.from(variableScope).local + vars[LONG_VAR.name] = LONG_VAR.from(variableScope).local + vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(variableScope).local + vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(variableScope).local + vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(variableScope).local + vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(variableScope).local + vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(variableScope).local + vars[MAP_STRING_LONG_VAR.name] = MAP_STRING_LONG_VAR.from(variableScope).local + vars[COMPLEX_SET_VAR.name] = COMPLEX_SET_VAR.from(variableScope).local + vars[COMPLEX_LIST_VAR.name] = COMPLEX_LIST_VAR.from(variableScope).local + vars[COMPLEX_MAP_VAR.name] = COMPLEX_MAP_VAR.from(variableScope).local + + } + + @Bean + fun readNonExisting() = JavaDelegate { delegateExecution -> + val nonExisting = stringVariable("non-existing") + nonExisting.from(delegateExecution).get() + } + + + @Bean + fun readFromVariableMap() = JavaDelegate { delegateExecution -> + val variableMap = delegateExecution.variablesTyped + + vars[STRING_VAR.name] = STRING_VAR.from(variableMap).get() + vars[DATE_VAR.name] = DATE_VAR.from(variableMap).get() + vars[SHORT_VAR.name] = SHORT_VAR.from(variableMap).get() + vars[INT_VAR.name] = INT_VAR.from(variableMap).get() + vars[LONG_VAR.name] = LONG_VAR.from(variableMap).get() + vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(variableMap).get() + vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(variableMap).get() + vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(variableMap).get() + vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(variableMap).get() + vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(variableMap).get() + vars[MAP_STRING_LONG_VAR.name] = MAP_STRING_LONG_VAR.from(variableMap).get() + vars[COMPLEX_SET_VAR.name] = COMPLEX_SET_VAR.from(variableMap).get() + vars[COMPLEX_LIST_VAR.name] = COMPLEX_LIST_VAR.from(variableMap).get() + vars[COMPLEX_MAP_VAR.name] = COMPLEX_MAP_VAR.from(variableMap).get() + } + + @Bean + fun writeVariablesToScope() = JavaDelegate { delegateExecution -> + STRING_VAR.on(delegateExecution).set(STRING.value) + DATE_VAR.on(delegateExecution).set(DATE.value) + SHORT_VAR.on(delegateExecution).set(SHORT.value) + INT_VAR.on(delegateExecution).set(INT.value) + LONG_VAR.on(delegateExecution).set(LONG.value) + DOUBLE_VAR.on(delegateExecution).set(DOUBLE.value) + BOOLEAN_VAR.on(delegateExecution).set(BOOLEAN.value) + COMPLEX_VAR.on(delegateExecution).set(COMPLEX.value) + LIST_STRING_VAR.on(delegateExecution).set(LIST_STRING.value) + SET_STRING_VAR.on(delegateExecution).set(SET_STRING.value) + MAP_STRING_LONG_VAR.on(delegateExecution).set(MAP_STRING_LONG.value) + COMPLEX_SET_VAR.on(delegateExecution).set(COMPLEX_SET.value) + COMPLEX_LIST_VAR.on(delegateExecution).set(COMPLEX_LIST.value) + COMPLEX_MAP_VAR.on(delegateExecution).set(COMPLEX_MAP.value) + + } + + @Bean + fun writeVariablesToScopeAndLocal() = JavaDelegate { delegateExecution -> + STRING_VAR.on(delegateExecution).set(STRING.value) + DATE_VAR.on(delegateExecution).set(DATE.value) + SHORT_VAR.on(delegateExecution).set(SHORT.value) + INT_VAR.on(delegateExecution).set(INT.value) + LONG_VAR.on(delegateExecution).set(LONG.value) + DOUBLE_VAR.on(delegateExecution).set(DOUBLE.value) + BOOLEAN_VAR.on(delegateExecution).set(BOOLEAN.value) + COMPLEX_VAR.on(delegateExecution).set(COMPLEX.value) + LIST_STRING_VAR.on(delegateExecution).set(LIST_STRING.value) + SET_STRING_VAR.on(delegateExecution).set(SET_STRING.value) + MAP_STRING_LONG_VAR.on(delegateExecution).set(MAP_STRING_LONG.value) + COMPLEX_SET_VAR.on(delegateExecution).set(COMPLEX_SET.value) + COMPLEX_LIST_VAR.on(delegateExecution).set(COMPLEX_LIST.value) + COMPLEX_MAP_VAR.on(delegateExecution).set(COMPLEX_MAP.value) + + STRING_VAR.on(delegateExecution).setLocal(STRING_LOCAL.value) + DATE_VAR.on(delegateExecution).setLocal(DATE_LOCAL.value) + SHORT_VAR.on(delegateExecution).setLocal(SHORT_LOCAL.value) + INT_VAR.on(delegateExecution).setLocal(INT_LOCAL.value) + LONG_VAR.on(delegateExecution).setLocal(LONG_LOCAL.value) + DOUBLE_VAR.on(delegateExecution).setLocal(DOUBLE_LOCAL.value) + BOOLEAN_VAR.on(delegateExecution).setLocal(BOOLEAN_LOCAL.value) + COMPLEX_VAR.on(delegateExecution).setLocal(COMPLEX_LOCAL.value) + LIST_STRING_VAR.on(delegateExecution).setLocal(LIST_STRING_LOCAL.value) + SET_STRING_VAR.on(delegateExecution).setLocal(SET_STRING_LOCAL.value) + MAP_STRING_LONG_VAR.on(delegateExecution).setLocal(MAP_STRING_DATE_LOCAL.value) + COMPLEX_SET_VAR.on(delegateExecution).setLocal(COMPLEX_SET_LOCAL.value) + COMPLEX_LIST_VAR.on(delegateExecution).setLocal(COMPLEX_LIST_LOCAL.value) + COMPLEX_MAP_VAR.on(delegateExecution).setLocal(COMPLEX_MAP_LOCAL.value) + } + + @Bean + fun deleteVariablesFromScope() = JavaDelegate { delegateExecution -> + STRING_VAR.on(delegateExecution).remove() + LIST_STRING_VAR.on(delegateExecution).remove() + SET_STRING_VAR.on(delegateExecution).remove() + MAP_STRING_LONG_VAR.on(delegateExecution).remove() + } + } - private val allLocalValues = mapOf( - STRING_VAR to STRING_LOCAL, - DATE_VAR to DATE_LOCAL, - SHORT_VAR to SHORT_LOCAL, - INT_VAR to INT_LOCAL, - LONG_VAR to LONG_LOCAL, - DOUBLE_VAR to DOUBLE_LOCAL, - BOOLEAN_VAR to BOOLEAN_LOCAL, - COMPLEX_VAR to COMPLEX_LOCAL, - LIST_STRING_VAR to LIST_STRING_LOCAL, - SET_STRING_VAR to SET_STRING_LOCAL, - MAP_STRING_DATE_VAR to MAP_STRING_DATE_LOCAL - ) - fun createVariableMapUntyped(): VariableMap { - val variables = createVariables(); - allValues.values.forEach { - variables.putValue(it.variable.name, it.value) - } - return variables - } + /** + * Value holder. + */ + data class VariableValue(val variable: VariableFactory, val value: T) - fun createKeyValuePairs(): Set, Any>> { - return allValues.entries.map { Pair(it.key, it.value.value) }.toSet() + /** + * Complex data structure. + */ + data class ComplexDataStructure( + val someStringValue: String, + val someIntValue: Int, + val someDateValue: Date + ) { + @JsonIgnore + val valueToIgnore: String = "some hidden value" } - fun createKeyLocalValuePairs(): Set, Any>> { - return allLocalValues.entries.map { Pair(it.key, it.value.value) }.toSet() + /** + * Complex key. + */ + data class ComplexKey( + val someStringValue: String, + val index: Int + ) + + /** + * Application to start + */ + @EnableJGiven + @ComponentScan + @SpringBootConfiguration + @EnableAutoConfiguration + class TestApplication +} + + +/** + * Base action stage. + */ +@JGivenStage +class ActionStage : Stage() { + + @Autowired + @ProvidedScenarioState + lateinit var repositoryService: RepositoryService + + @Autowired + @ProvidedScenarioState + lateinit var runtimeService: RuntimeService + + @Autowired + @ProvidedScenarioState + lateinit var taskService: TaskService + + @ProvidedScenarioState + lateinit var processDefinition: ProcessDefinition + + @ProvidedScenarioState + lateinit var processInstance: ProcessInstance + + @ProvidedScenarioState + lateinit var task: Task + + @Autowired + lateinit var delegateConfiguration: CamundaBpmDataITestBase.DelegateConfiguration + + @BeforeScenario + fun cleanUp() { + delegateConfiguration.vars.clear() + delegateConfiguration.optionalVars.clear() + delegateConfiguration.variableMap = createVariables() } - } - @Configuration - class DelegateConfiguration { + fun process_with_delegate_is_deployed( + processDefinitionKey: String = "process_with_delegate", + delegateExpression: String = "\${serviceTaskDelegate}" + ): ActionStage { - val vars = HashMap() - val optionalVars = HashMap>() - var variableMap: VariableMap = createVariables() + val instance = Bpmn + .createExecutableProcess(processDefinitionKey) + .startEvent("start") + .serviceTask("service_task") + .camundaDelegateExpression(delegateExpression) + .endEvent("end") + .done() - @Bean - fun serviceWriteAdapter() = JavaDelegate { delegateExecution -> - variableMap = delegateExecution.variablesTyped + deploy(processDefinitionKey, instance) + + return self() } - @Bean - fun readOptionalFromVariableScope() = JavaDelegate { delegateExecution -> - optionalVars[STRING_VAR.name] = STRING_VAR.from(delegateExecution).optional - optionalVars[DATE_VAR.name] = DATE_VAR.from(delegateExecution).optional - optionalVars[SHORT_VAR.name] = SHORT_VAR.from(delegateExecution).optional - optionalVars[INT_VAR.name] = INT_VAR.from(delegateExecution).optional - optionalVars[LONG_VAR.name] = LONG_VAR.from(delegateExecution).optional - optionalVars[DOUBLE_VAR.name] = DOUBLE_VAR.from(delegateExecution).optional - optionalVars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(delegateExecution).optional - optionalVars[COMPLEX_VAR.name] = COMPLEX_VAR.from(delegateExecution).optional - optionalVars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(delegateExecution).optional - optionalVars[SET_STRING_VAR.name] = SET_STRING_VAR.from(delegateExecution).optional - optionalVars[MAP_STRING_DATE_VAR.name] = MAP_STRING_DATE_VAR.from(delegateExecution).optional + fun process_with_user_task_is_deployed( + processDefinitionKey: String = "process_with_user_task", + taskDefinitionKey: String = "user_task" + ): ActionStage { + + val instance = Bpmn + .createExecutableProcess(processDefinitionKey) + .startEvent("start") + .userTask(taskDefinitionKey) + .endEvent("end") + .done() + + deploy(processDefinitionKey, instance) + + return self() } - @Bean - fun readFromVariableScope() = JavaDelegate { delegateExecution -> - vars[STRING_VAR.name] = STRING_VAR.from(delegateExecution).get() - vars[DATE_VAR.name] = DATE_VAR.from(delegateExecution).get() - vars[SHORT_VAR.name] = SHORT_VAR.from(delegateExecution).get() - vars[INT_VAR.name] = INT_VAR.from(delegateExecution).get() - vars[LONG_VAR.name] = LONG_VAR.from(delegateExecution).get() - vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(delegateExecution).get() - vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(delegateExecution).get() - vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(delegateExecution).get() - vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(delegateExecution).get() - vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(delegateExecution).get() - vars[MAP_STRING_DATE_VAR.name] = MAP_STRING_DATE_VAR.from(delegateExecution).get() + fun process_with_user_task_and_delegate_is_deployed( + processDefinitionKey: String = "process_with_user_task", + taskDefinitionKey: String = "user_task", + delegateExpression: String = "\${serviceTaskDelegate}" + ): ActionStage { + + val instance = Bpmn + .createExecutableProcess(processDefinitionKey) + .startEvent("start") + .userTask(taskDefinitionKey) + .serviceTask("service_task") + .camundaDelegateExpression(delegateExpression) + .endEvent("end") + .done() + deploy(processDefinitionKey, instance) + + return self() } - @Bean - fun readLocalFromVariableScope() = JavaDelegate { delegateExecution -> - readLocalVarsFromVariableScope(variableScope = delegateExecution) + fun process_with_user_task_and_listener_is_deployed( + processDefinitionKey: String = "process_with_user_task_and_listener", + taskDefinitionKey: String = "user_task", + delegateExpression: String = "\${listenerDelegate}" + ): ActionStage { + + val instance = Bpmn + .createExecutableProcess(processDefinitionKey) + .startEvent("start") + .userTask(taskDefinitionKey) + .camundaTaskListenerDelegateExpression("complete", delegateExpression) + .endEvent("end") + .done() + deploy(processDefinitionKey, instance) + + return self() } - @Bean - fun readLocalFromDelegateTask() = TaskListener { delegateTask -> - readLocalVarsFromVariableScope(variableScope = delegateTask) + fun process_with_modifying_delegate_is_deployed( + processDefinitionKey: String = "process_with_delegate", + modifyingDelegateExpression: String = "\${modifyingServiceTaskDelegate}", + delegateExpression: String = "\${serviceTaskDelegate}" + ): ActionStage { + + val instance = Bpmn + .createExecutableProcess(processDefinitionKey) + .startEvent("start") + .serviceTask("modifying_service_task") + .camundaDelegateExpression(modifyingDelegateExpression) + .serviceTask("service_task") + .camundaDelegateExpression(delegateExpression) + .endEvent("end") + .done() + + deploy(processDefinitionKey, instance) + return self() } /** - * Writes local properties from variable scope. + * Starts process with variables. */ - private fun readLocalVarsFromVariableScope(variableScope: VariableScope) { - vars[STRING_VAR.name] = STRING_VAR.from(variableScope).local - vars[DATE_VAR.name] = DATE_VAR.from(variableScope).local - vars[SHORT_VAR.name] = SHORT_VAR.from(variableScope).local - vars[INT_VAR.name] = INT_VAR.from(variableScope).local - vars[LONG_VAR.name] = LONG_VAR.from(variableScope).local - vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(variableScope).local - vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(variableScope).local - vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(variableScope).local - vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(variableScope).local - vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(variableScope).local - vars[MAP_STRING_DATE_VAR.name] = MAP_STRING_DATE_VAR.from(variableScope).local - } - - @Bean - fun readNonExisting() = JavaDelegate { delegateExecution -> - val nonExisting = stringVariable("non-existing") - nonExisting.from(delegateExecution).get() - } + fun process_is_started_with_variables( + processDefinitionKey: String = this.processDefinition.key, + variables: VariableMap + ): ActionStage { + processInstance = runtimeService + .startProcessInstanceByKey(processDefinitionKey, variables) - @Bean - fun readFromVariableMap() = JavaDelegate { delegateExecution -> - val variableMap = delegateExecution.variablesTyped - - vars[STRING_VAR.name] = STRING_VAR.from(variableMap).get() - vars[DATE_VAR.name] = DATE_VAR.from(variableMap).get() - vars[SHORT_VAR.name] = SHORT_VAR.from(variableMap).get() - vars[INT_VAR.name] = INT_VAR.from(variableMap).get() - vars[LONG_VAR.name] = LONG_VAR.from(variableMap).get() - vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(variableMap).get() - vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(variableMap).get() - vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(variableMap).get() - vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(variableMap).get() - vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(variableMap).get() - vars[MAP_STRING_DATE_VAR.name] = MAP_STRING_DATE_VAR.from(variableMap).get() + return self() } - @Bean - fun writeVariablesToScope() = JavaDelegate { delegateExecution -> - STRING_VAR.on(delegateExecution).set(STRING.value) - DATE_VAR.on(delegateExecution).set(DATE.value) - SHORT_VAR.on(delegateExecution).set(SHORT.value) - INT_VAR.on(delegateExecution).set(INT.value) - LONG_VAR.on(delegateExecution).set(LONG.value) - DOUBLE_VAR.on(delegateExecution).set(DOUBLE.value) - BOOLEAN_VAR.on(delegateExecution).set(BOOLEAN.value) - COMPLEX_VAR.on(delegateExecution).set(COMPLEX.value) - LIST_STRING_VAR.on(delegateExecution).set(LIST_STRING.value) - SET_STRING_VAR.on(delegateExecution).set(SET_STRING.value) - MAP_STRING_DATE_VAR.on(delegateExecution).set(MAP_STRING_DATE.value) + /** + * Reads task. + */ + fun process_waits_in_task(taskDefinitionKey: String = "user_task"): ActionStage { + val query = taskService.createTaskQuery().processInstanceId(processInstance.id).taskDefinitionKey(taskDefinitionKey) + assertThat(query.count()).isEqualTo(1L) + task = query.singleResult() + return self() } - @Bean - fun writeVariablesToScopeAndLocal() = JavaDelegate { delegateExecution -> - STRING_VAR.on(delegateExecution).set(STRING.value) - DATE_VAR.on(delegateExecution).set(DATE.value) - SHORT_VAR.on(delegateExecution).set(SHORT.value) - INT_VAR.on(delegateExecution).set(INT.value) - LONG_VAR.on(delegateExecution).set(LONG.value) - DOUBLE_VAR.on(delegateExecution).set(DOUBLE.value) - BOOLEAN_VAR.on(delegateExecution).set(BOOLEAN.value) - COMPLEX_VAR.on(delegateExecution).set(COMPLEX.value) - LIST_STRING_VAR.on(delegateExecution).set(LIST_STRING.value) - SET_STRING_VAR.on(delegateExecution).set(SET_STRING.value) - MAP_STRING_DATE_VAR.on(delegateExecution).set(MAP_STRING_DATE.value) - - STRING_VAR.on(delegateExecution).setLocal(STRING_LOCAL.value) - DATE_VAR.on(delegateExecution).setLocal(DATE_LOCAL.value) - SHORT_VAR.on(delegateExecution).setLocal(SHORT_LOCAL.value) - INT_VAR.on(delegateExecution).setLocal(INT_LOCAL.value) - LONG_VAR.on(delegateExecution).setLocal(LONG_LOCAL.value) - DOUBLE_VAR.on(delegateExecution).setLocal(DOUBLE_LOCAL.value) - BOOLEAN_VAR.on(delegateExecution).setLocal(BOOLEAN_LOCAL.value) - COMPLEX_VAR.on(delegateExecution).setLocal(COMPLEX_LOCAL.value) - LIST_STRING_VAR.on(delegateExecution).setLocal(LIST_STRING_LOCAL.value) - SET_STRING_VAR.on(delegateExecution).setLocal(SET_STRING_LOCAL.value) - MAP_STRING_DATE_VAR.on(delegateExecution).setLocal(MAP_STRING_DATE_LOCAL.value) + /** + * Completes the task. + */ + fun task_is_completed(): ActionStage { + taskService.complete(task.id) + return self() } - @Bean - fun deleteVariablesFromScope() = JavaDelegate { delegateExecution -> - STRING_VAR.on(delegateExecution).remove() - LIST_STRING_VAR.on(delegateExecution).remove() - SET_STRING_VAR.on(delegateExecution).remove() - MAP_STRING_DATE_VAR.on(delegateExecution).remove() + /** + * Calls task callback with task service and task. + */ + fun task_is_accessed_in_user_task(taskServiceTaskCallback: (taskService: TaskService, taskId: String) -> Unit): ActionStage { + taskServiceTaskCallback.invoke(this.taskService, this.task.id) + return self() } - } - - - /** - * Value holder. - */ - data class VariableValue(val variable: VariableFactory, val value: T) - - /** - * Complex data structure. - */ - data class ComplexDataStructure( - val stringValue: String, - val intValue: Int, - val dateValue: Date - ) { - @JsonIgnore - val valueToIgnore: String = "some hidden value" - } - - /** - * Application to start - */ - @EnableJGiven - @ComponentScan - @SpringBootConfiguration - @EnableAutoConfiguration - class TestApplication -} + /** + * Calls execution callback with runtime service and execution. + */ + fun execution_is_accessed_in_wait_state(runtimeServiceExecutionCallback: (runtimeService: RuntimeService, executionId: String) -> Unit): ActionStage { + runtimeServiceExecutionCallback.invoke(this.runtimeService, this.processInstance.id) + return self() + } -/** - * Base action stage. - */ -@JGivenStage -class ActionStage : Stage() { - - @Autowired - @ProvidedScenarioState - lateinit var repositoryService: RepositoryService - - @Autowired - @ProvidedScenarioState - lateinit var runtimeService: RuntimeService - - @Autowired - @ProvidedScenarioState - lateinit var taskService: TaskService - - @ProvidedScenarioState - lateinit var processDefinition: ProcessDefinition - - @ProvidedScenarioState - lateinit var processInstance: ProcessInstance - - @ProvidedScenarioState - lateinit var task: Task - - @Autowired - lateinit var delegateConfiguration: CamundaBpmDataITestBase.DelegateConfiguration - - @BeforeScenario - fun cleanUp() { - delegateConfiguration.vars.clear() - delegateConfiguration.optionalVars.clear() - delegateConfiguration.variableMap = createVariables() - } - - fun process_with_delegate_is_deployed( - processDefinitionKey: String = "process_with_delegate", - delegateExpression: String = "\${serviceTaskDelegate}" - ): ActionStage { - - val instance = Bpmn - .createExecutableProcess(processDefinitionKey) - .startEvent("start") - .serviceTask("service_task") - .camundaDelegateExpression(delegateExpression) - .endEvent("end") - .done() - - deploy(processDefinitionKey, instance) - - return self() - } - - fun process_with_user_task_is_deployed( - processDefinitionKey: String = "process_with_user_task", - taskDefinitionKey: String = "user_task" - ): ActionStage { - - val instance = Bpmn - .createExecutableProcess(processDefinitionKey) - .startEvent("start") - .userTask(taskDefinitionKey) - .endEvent("end") - .done() - - deploy(processDefinitionKey, instance) - - return self() - } - - fun process_with_user_task_and_delegate_is_deployed( - processDefinitionKey: String = "process_with_user_task", - taskDefinitionKey: String = "user_task", - delegateExpression: String = "\${serviceTaskDelegate}" - ): ActionStage { - - val instance = Bpmn - .createExecutableProcess(processDefinitionKey) - .startEvent("start") - .userTask(taskDefinitionKey) - .serviceTask("service_task") - .camundaDelegateExpression(delegateExpression) - .endEvent("end") - .done() - deploy(processDefinitionKey, instance) - - return self() - } - - fun process_with_user_task_and_listener_is_deployed( - processDefinitionKey: String = "process_with_user_task_and_listener", - taskDefinitionKey: String = "user_task", - delegateExpression: String = "\${listenerDelegate}" - ): ActionStage { - - val instance = Bpmn - .createExecutableProcess(processDefinitionKey) - .startEvent("start") - .userTask(taskDefinitionKey) - .camundaTaskListenerDelegateExpression("complete", delegateExpression) - .endEvent("end") - .done() - deploy(processDefinitionKey, instance) - - return self() - } - - fun process_with_modifying_delegate_is_deployed( - processDefinitionKey: String = "process_with_delegate", - modifyingDelegateExpression: String = "\${modifyingServiceTaskDelegate}", - delegateExpression: String = "\${serviceTaskDelegate}" - ): ActionStage { - - val instance = Bpmn - .createExecutableProcess(processDefinitionKey) - .startEvent("start") - .serviceTask("modifying_service_task") - .camundaDelegateExpression(modifyingDelegateExpression) - .serviceTask("service_task") - .camundaDelegateExpression(delegateExpression) - .endEvent("end") - .done() - - deploy(processDefinitionKey, instance) - return self() - } - - /** - * Starts process with variables. - */ - fun process_is_started_with_variables( - processDefinitionKey: String = this.processDefinition.key, - variables: VariableMap - ): ActionStage { - - processInstance = runtimeService - .startProcessInstanceByKey(processDefinitionKey, variables) - - return self() - } - - /** - * Reads task. - */ - fun process_waits_in_task(taskDefinitionKey: String = "user_task"): ActionStage { - val query = taskService.createTaskQuery().processInstanceId(processInstance.id).taskDefinitionKey(taskDefinitionKey) - assertThat(query.count()).isEqualTo(1L) - task = query.singleResult() - return self() - } - - /** - * Completes the task. - */ - fun task_is_completed(): ActionStage { - taskService.complete(task.id) - return self() - } - - /** - * Calls task callback with task service and task. - */ - fun task_is_accessed_in_user_task(taskServiceTaskCallback: (taskService: TaskService, taskId: String) -> Unit): ActionStage { - taskServiceTaskCallback.invoke(this.taskService, this.task.id) - return self() - } - - /** - * Calls execution callback with runtime service and execution. - */ - fun execution_is_accessed_in_wait_state(runtimeServiceExecutionCallback: (runtimeService: RuntimeService, executionId: String) -> Unit): ActionStage { - runtimeServiceExecutionCallback.invoke(this.runtimeService, this.processInstance.id) - return self() - } - - /** - * Deploys process model instance under specified process definition key. - */ - private fun deploy(processDefinitionKey: String, modelInstance: BpmnModelInstance) { - val deployment = repositoryService - .createDeployment() - .addModelInstance("$processDefinitionKey.bpmn", modelInstance) - .name(processDefinitionKey) - .deploy() - - processDefinition = repositoryService - .createProcessDefinitionQuery() - .deploymentId(deployment.id) - .singleResult() - } + /** + * Deploys process model instance under specified process definition key. + */ + private fun deploy(processDefinitionKey: String, modelInstance: BpmnModelInstance) { + val deployment = repositoryService + .createDeployment() + .addModelInstance("$processDefinitionKey.bpmn", modelInstance) + .name(processDefinitionKey) + .deploy() + + processDefinition = repositoryService + .createProcessDefinitionQuery() + .deploymentId(deployment.id) + .singleResult() + } } /** @@ -534,19 +610,19 @@ class ActionStage : Stage() { @JGivenStage class AssertStage : Stage() { - fun variables_had_value(readValues: Map, variablesWithValue: Set, Any>>): AssertStage { - variablesWithValue.forEach { - assertThat(readValues).containsEntry(it.first.name, it.second) + fun variables_had_value(readValues: Map, variablesWithValue: Set, Any>>): AssertStage { + variablesWithValue.forEach { + assertThat(readValues).containsEntry(it.first.name, it.second) + } + return self() } - return self() - } - fun variables_had_not_value(readValues: Map, vararg variableWithValue: VariableFactory<*>): AssertStage { - val emptyOptional = Optional.empty() + fun variables_had_not_value(readValues: Map, vararg variableWithValue: VariableFactory<*>): AssertStage { + val emptyOptional = Optional.empty() - variableWithValue.forEach { - assertThat(readValues).containsEntry(it.name, emptyOptional) + variableWithValue.forEach { + assertThat(readValues).containsEntry(it.name, emptyOptional) + } + return self() } - return self() - } } diff --git a/example/example-kotlin/src/test/kotlin/itest/RuntimeServiceAdapterITest.kt b/example/example-kotlin/src/test/kotlin/itest/RuntimeServiceAdapterITest.kt index 8363eb3c..f98f6ec0 100644 --- a/example/example-kotlin/src/test/kotlin/itest/RuntimeServiceAdapterITest.kt +++ b/example/example-kotlin/src/test/kotlin/itest/RuntimeServiceAdapterITest.kt @@ -1,118 +1,135 @@ package io.holunda.camunda.bpm.data.itest +import com.google.common.util.concurrent.ExecutionList import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.BOOLEAN import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_LIST +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_MAP +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.COMPLEX_SET import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.DATE import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.DOUBLE import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.INT import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_STRING import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LONG -import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_DATE +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_LONG import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SET_STRING import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SHORT import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.STRING +import org.camunda.bpm.engine.delegate.DelegateExecution +import org.camunda.bpm.engine.delegate.ExecutionListener +import org.camunda.bpm.engine.delegate.JavaDelegate import org.camunda.bpm.engine.variable.Variables.createVariables import org.junit.Test import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Configurable +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import java.time.OffsetDateTime import java.util.* class RuntimeServiceAdapterITest : CamundaBpmDataITestBase() { - @Autowired - lateinit var delegateConfiguration: DelegateConfiguration - - @Test - fun `should write to task service adapter`() { - - val variables = createVariables() - - given() - .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readFromVariableScope.name}}") - .and() - .process_is_started_with_variables(variables = variables) - .and() - .process_waits_in_task() - - whenever() - .execution_is_accessed_in_wait_state { runtimeService, executionId -> - STRING_VAR.on(runtimeService, executionId).set(STRING.value) - DATE_VAR.on(runtimeService, executionId).set(DATE.value) - SHORT_VAR.on(runtimeService, executionId).set(SHORT.value) - INT_VAR.on(runtimeService, executionId).set(INT.value) - LONG_VAR.on(runtimeService, executionId).set(LONG.value) - DOUBLE_VAR.on(runtimeService, executionId).set(DOUBLE.value) - BOOLEAN_VAR.on(runtimeService, executionId).set(BOOLEAN.value) - COMPLEX_VAR.on(runtimeService, executionId).set(COMPLEX.value) - LIST_STRING_VAR.on(runtimeService, executionId).set(LIST_STRING.value) - SET_STRING_VAR.on(runtimeService, executionId).set(SET_STRING.value) - MAP_STRING_DATE_VAR.on(runtimeService, executionId).set(MAP_STRING_DATE.value) - } - .and() - .task_is_completed() - - then() - .variables_had_value(readValues = delegateConfiguration.vars, variablesWithValue = createKeyValuePairs()) - } - - @Test - fun `should remove on runtime service adapter`() { - - given() - .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readOptionalFromVariableScope.name}}") - .and() - .process_is_started_with_variables(variables = createVariableMapUntyped()) - .and() - .process_waits_in_task() - - whenever() - .execution_is_accessed_in_wait_state { runtimeService, executionId -> - STRING_VAR.on(runtimeService, executionId).remove() - LIST_STRING_VAR.on(runtimeService, executionId).remove() - SET_STRING_VAR.on(runtimeService, executionId).remove() - MAP_STRING_DATE_VAR.on(runtimeService, executionId).remove() - } - .and() - .task_is_completed() - - then() - .variables_had_not_value(delegateConfiguration.optionalVars, - STRING_VAR, - LIST_STRING_VAR, - SET_STRING_VAR, - MAP_STRING_DATE_VAR - ) - .and() - .variables_had_value(delegateConfiguration.optionalVars, setOf(LONG_VAR to Optional.of(LONG.value))) - } - - @Test - fun `should write to variables-map and read runtime adapter`() { - - val vars = HashMap() - - given() - .process_with_user_task_is_deployed() - .and() - .process_is_started_with_variables(variables = createVariableMapUntyped()) - - whenever() - .execution_is_accessed_in_wait_state { runtimeService, executionId -> - vars[STRING_VAR.name] = STRING_VAR.from(runtimeService, executionId).get() - vars[DATE_VAR.name] = DATE_VAR.from(runtimeService, executionId).get() - vars[SHORT_VAR.name] = SHORT_VAR.from(runtimeService, executionId).get() - vars[INT_VAR.name] = INT_VAR.from(runtimeService, executionId).get() - vars[LONG_VAR.name] = LONG_VAR.from(runtimeService, executionId).get() - vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(runtimeService, executionId).get() - vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(runtimeService, executionId).get() - vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(runtimeService, executionId).get() - vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(runtimeService, executionId).get() - vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(runtimeService, executionId).get() - vars[MAP_STRING_DATE_VAR.name] = MAP_STRING_DATE_VAR.from(runtimeService, executionId).get() - } - - then() - .variables_had_value(vars, variablesWithValue = createKeyValuePairs()) - } + @Autowired + lateinit var delegateConfiguration: DelegateConfiguration + + @Test + fun `should write to runtime service adapter`() { + + val variables = createVariables() + + given() + .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readFromVariableScope.name}}") + .and() + .process_is_started_with_variables(variables = variables) + .and() + .process_waits_in_task() + + whenever() + .execution_is_accessed_in_wait_state { runtimeService, executionId -> + STRING_VAR.on(runtimeService, executionId).set(STRING.value) + DATE_VAR.on(runtimeService, executionId).set(DATE.value) + SHORT_VAR.on(runtimeService, executionId).set(SHORT.value) + INT_VAR.on(runtimeService, executionId).set(INT.value) + LONG_VAR.on(runtimeService, executionId).set(LONG.value) + DOUBLE_VAR.on(runtimeService, executionId).set(DOUBLE.value) + BOOLEAN_VAR.on(runtimeService, executionId).set(BOOLEAN.value) + COMPLEX_VAR.on(runtimeService, executionId).set(COMPLEX.value) + LIST_STRING_VAR.on(runtimeService, executionId).set(LIST_STRING.value) + SET_STRING_VAR.on(runtimeService, executionId).set(SET_STRING.value) + MAP_STRING_LONG_VAR.on(runtimeService, executionId).set(MAP_STRING_LONG.value) + COMPLEX_SET_VAR.on(runtimeService, executionId).set(COMPLEX_SET.value) + COMPLEX_LIST_VAR.on(runtimeService, executionId).set(COMPLEX_LIST.value) + COMPLEX_MAP_VAR.on(runtimeService, executionId).set(COMPLEX_MAP.value) + } + .and() + .task_is_completed() + + then() + .variables_had_value(readValues = delegateConfiguration.vars, variablesWithValue = createKeyValuePairs()) + } + + @Test + fun `should remove on runtime service adapter`() { + + given() + .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readOptionalFromVariableScope.name}}") + .and() + .process_is_started_with_variables(variables = createVariableMapUntyped()) + .and() + .process_waits_in_task() + + whenever() + .execution_is_accessed_in_wait_state { runtimeService, executionId -> + STRING_VAR.on(runtimeService, executionId).remove() + LIST_STRING_VAR.on(runtimeService, executionId).remove() + SET_STRING_VAR.on(runtimeService, executionId).remove() + MAP_STRING_LONG_VAR.on(runtimeService, executionId).remove() + } + .and() + .task_is_completed() + + then() + .variables_had_not_value(delegateConfiguration.optionalVars, + STRING_VAR, + LIST_STRING_VAR, + SET_STRING_VAR, + MAP_STRING_LONG_VAR + ) + .and() + .variables_had_value(delegateConfiguration.optionalVars, setOf(LONG_VAR to Optional.of(LONG.value))) + } + + @Test + fun `should write to variables-map and read runtime adapter`() { + + val vars = HashMap() + + given() + .process_with_user_task_is_deployed() + .and() + .process_is_started_with_variables(variables = createVariableMapUntyped()) + + whenever() + .execution_is_accessed_in_wait_state { runtimeService, executionId -> + vars[STRING_VAR.name] = STRING_VAR.from(runtimeService, executionId).get() + vars[DATE_VAR.name] = DATE_VAR.from(runtimeService, executionId).get() + vars[SHORT_VAR.name] = SHORT_VAR.from(runtimeService, executionId).get() + vars[INT_VAR.name] = INT_VAR.from(runtimeService, executionId).get() + vars[LONG_VAR.name] = LONG_VAR.from(runtimeService, executionId).get() + vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(runtimeService, executionId).get() + vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(runtimeService, executionId).get() + vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(runtimeService, executionId).get() + vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(runtimeService, executionId).get() + vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(runtimeService, executionId).get() + vars[MAP_STRING_LONG_VAR.name] = MAP_STRING_LONG_VAR.from(runtimeService, executionId).get() + vars[COMPLEX_SET_VAR.name] = COMPLEX_SET_VAR.from(runtimeService, executionId).get() + vars[COMPLEX_LIST_VAR.name] = COMPLEX_LIST_VAR.from(runtimeService, executionId).get() + vars[COMPLEX_MAP_VAR.name] = COMPLEX_MAP_VAR.from(runtimeService, executionId).get() + } + + then() + .variables_had_value(vars, variablesWithValue = createKeyValuePairs()) + } } diff --git a/example/example-kotlin/src/test/kotlin/itest/TaskServiceAdapterITest.kt b/example/example-kotlin/src/test/kotlin/itest/TaskServiceAdapterITest.kt index 7f107fbf..a803f008 100644 --- a/example/example-kotlin/src/test/kotlin/itest/TaskServiceAdapterITest.kt +++ b/example/example-kotlin/src/test/kotlin/itest/TaskServiceAdapterITest.kt @@ -14,8 +14,8 @@ import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Value import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_STRING_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LONG import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LONG_LOCAL -import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_DATE import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_DATE_LOCAL +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_LONG import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SET_STRING import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SET_STRING_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SHORT @@ -30,135 +30,145 @@ import kotlin.collections.HashMap class TaskServiceAdapterITest : CamundaBpmDataITestBase() { - @Autowired - lateinit var delegateConfiguration: DelegateConfiguration - - @Test - fun `should write to task service adapter`() { - - given() - .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readFromVariableScope.name}}") - .and() - .process_is_started_with_variables(variables = createVariables()) - .and() - .process_waits_in_task() - - whenever() - .task_is_accessed_in_user_task { taskService, taskId -> - STRING_VAR.on(taskService, taskId).set(STRING.value) - DATE_VAR.on(taskService, taskId).set(DATE.value) - SHORT_VAR.on(taskService, taskId).set(SHORT.value) - INT_VAR.on(taskService, taskId).set(INT.value) - LONG_VAR.on(taskService, taskId).set(LONG.value) - DOUBLE_VAR.on(taskService, taskId).set(DOUBLE.value) - BOOLEAN_VAR.on(taskService, taskId).set(BOOLEAN.value) - COMPLEX_VAR.on(taskService, taskId).set(COMPLEX.value) - LIST_STRING_VAR.on(taskService, taskId).set(LIST_STRING.value) - SET_STRING_VAR.on(taskService, taskId).set(SET_STRING.value) - MAP_STRING_DATE_VAR.on(taskService, taskId).set(MAP_STRING_DATE.value) - } - .and() - .task_is_completed() - - then() - .variables_had_value(readValues = delegateConfiguration.vars, variablesWithValue = createKeyValuePairs()) - } - - @Test - fun `should remove on task service adapter`() { - - given() - .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readOptionalFromVariableScope.name}}") - .and() - .process_is_started_with_variables(variables = createVariableMapUntyped()) - .and() - .process_waits_in_task() - - whenever() - .task_is_accessed_in_user_task { taskService, taskId -> - STRING_VAR.on(taskService, taskId).remove() - LIST_STRING_VAR.on(taskService, taskId).remove() - SET_STRING_VAR.on(taskService, taskId).remove() - MAP_STRING_DATE_VAR.on(taskService, taskId).remove() - } - .and() - .task_is_completed() - - then() - .variables_had_not_value(delegateConfiguration.optionalVars, - STRING_VAR, - LIST_STRING_VAR, - SET_STRING_VAR, - MAP_STRING_DATE_VAR - ) - .and() - .variables_had_value(delegateConfiguration.optionalVars, - setOf(LONG_VAR to Optional.of(LONG.value)) - ) - } - - - @Test - fun `should write to variables-map and read runtime adapter`() { - - val vars = HashMap() - - given() - .process_with_user_task_is_deployed() - .and() - .process_is_started_with_variables(variables = createVariableMapUntyped()) - .and() - .process_waits_in_task() - - whenever() - .task_is_accessed_in_user_task { taskService, taskId -> - vars[STRING_VAR.name] = STRING_VAR.from(taskService, taskId).get() - vars[DATE_VAR.name] = DATE_VAR.from(taskService, taskId).get() - vars[SHORT_VAR.name] = SHORT_VAR.from(taskService, taskId).get() - vars[INT_VAR.name] = INT_VAR.from(taskService, taskId).get() - vars[LONG_VAR.name] = LONG_VAR.from(taskService, taskId).get() - vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(taskService, taskId).get() - vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(taskService, taskId).get() - vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(taskService, taskId).get() - vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(taskService, taskId).get() - vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(taskService, taskId).get() - vars[MAP_STRING_DATE_VAR.name] = MAP_STRING_DATE_VAR.from(taskService, taskId).get() - } - - then() - .variables_had_value(readValues = vars, variablesWithValue = createKeyValuePairs()) - } - - @Test - fun `should write local variables to task service adapter`() { - - given() - .process_with_user_task_and_listener_is_deployed(delegateExpression = "\${${DelegateConfiguration::readLocalFromDelegateTask.name}}") - .and() - .process_is_started_with_variables(variables = createVariables()) - .and() - .process_waits_in_task() - - whenever() - .task_is_accessed_in_user_task { taskService, taskId -> - STRING_VAR.on(taskService, taskId).setLocal(STRING_LOCAL.value) - DATE_VAR.on(taskService, taskId).setLocal(DATE_LOCAL.value) - SHORT_VAR.on(taskService, taskId).setLocal(SHORT_LOCAL.value) - INT_VAR.on(taskService, taskId).setLocal(INT_LOCAL.value) - LONG_VAR.on(taskService, taskId).setLocal(LONG_LOCAL.value) - DOUBLE_VAR.on(taskService, taskId).setLocal(DOUBLE_LOCAL.value) - BOOLEAN_VAR.on(taskService, taskId).setLocal(BOOLEAN_LOCAL.value) - COMPLEX_VAR.on(taskService, taskId).setLocal(COMPLEX_LOCAL.value) - LIST_STRING_VAR.on(taskService, taskId).setLocal(LIST_STRING_LOCAL.value) - SET_STRING_VAR.on(taskService, taskId).setLocal(SET_STRING_LOCAL.value) - MAP_STRING_DATE_VAR.on(taskService, taskId).setLocal(MAP_STRING_DATE_LOCAL.value) - } - .and() - .task_is_completed() - - then() - .variables_had_value(readValues = delegateConfiguration.vars, variablesWithValue = createKeyLocalValuePairs()) - } + @Autowired + lateinit var delegateConfiguration: DelegateConfiguration + + @Test + fun `should write to task service adapter`() { + + given() + .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readFromVariableScope.name}}") + .and() + .process_is_started_with_variables(variables = createVariables()) + .and() + .process_waits_in_task() + + whenever() + .task_is_accessed_in_user_task { taskService, taskId -> + STRING_VAR.on(taskService, taskId).set(STRING.value) + DATE_VAR.on(taskService, taskId).set(DATE.value) + SHORT_VAR.on(taskService, taskId).set(SHORT.value) + INT_VAR.on(taskService, taskId).set(INT.value) + LONG_VAR.on(taskService, taskId).set(LONG.value) + DOUBLE_VAR.on(taskService, taskId).set(DOUBLE.value) + BOOLEAN_VAR.on(taskService, taskId).set(BOOLEAN.value) + COMPLEX_VAR.on(taskService, taskId).set(COMPLEX.value) + LIST_STRING_VAR.on(taskService, taskId).set(LIST_STRING.value) + SET_STRING_VAR.on(taskService, taskId).set(SET_STRING.value) + MAP_STRING_LONG_VAR.on(taskService, taskId).set(MAP_STRING_LONG.value) + COMPLEX_SET_VAR.on(taskService, taskId).set(Companion.Values.COMPLEX_SET.value) + COMPLEX_LIST_VAR.on(taskService, taskId).set(Companion.Values.COMPLEX_LIST.value) + COMPLEX_MAP_VAR.on(taskService, taskId).set(Companion.Values.COMPLEX_MAP.value) + + } + .and() + .task_is_completed() + + then() + .variables_had_value(readValues = delegateConfiguration.vars, variablesWithValue = createKeyValuePairs()) + } + + @Test + fun `should remove on task service adapter`() { + + given() + .process_with_user_task_and_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readOptionalFromVariableScope.name}}") + .and() + .process_is_started_with_variables(variables = createVariableMapUntyped()) + .and() + .process_waits_in_task() + + whenever() + .task_is_accessed_in_user_task { taskService, taskId -> + STRING_VAR.on(taskService, taskId).remove() + LIST_STRING_VAR.on(taskService, taskId).remove() + SET_STRING_VAR.on(taskService, taskId).remove() + MAP_STRING_LONG_VAR.on(taskService, taskId).remove() + } + .and() + .task_is_completed() + + then() + .variables_had_not_value(delegateConfiguration.optionalVars, + STRING_VAR, + LIST_STRING_VAR, + SET_STRING_VAR, + MAP_STRING_LONG_VAR + ) + .and() + .variables_had_value(delegateConfiguration.optionalVars, + setOf(LONG_VAR to Optional.of(LONG.value)) + ) + } + + + @Test + fun `should write to variables-map and read task service adapter`() { + + val vars = HashMap() + + given() + .process_with_user_task_is_deployed() + .and() + .process_is_started_with_variables(variables = createVariableMapUntyped()) + .and() + .process_waits_in_task() + + whenever() + .task_is_accessed_in_user_task { taskService, taskId -> + vars[STRING_VAR.name] = STRING_VAR.from(taskService, taskId).get() + vars[DATE_VAR.name] = DATE_VAR.from(taskService, taskId).get() + vars[SHORT_VAR.name] = SHORT_VAR.from(taskService, taskId).get() + vars[INT_VAR.name] = INT_VAR.from(taskService, taskId).get() + vars[LONG_VAR.name] = LONG_VAR.from(taskService, taskId).get() + vars[DOUBLE_VAR.name] = DOUBLE_VAR.from(taskService, taskId).get() + vars[BOOLEAN_VAR.name] = BOOLEAN_VAR.from(taskService, taskId).get() + vars[COMPLEX_VAR.name] = COMPLEX_VAR.from(taskService, taskId).get() + vars[LIST_STRING_VAR.name] = LIST_STRING_VAR.from(taskService, taskId).get() + vars[SET_STRING_VAR.name] = SET_STRING_VAR.from(taskService, taskId).get() + vars[MAP_STRING_LONG_VAR.name] = MAP_STRING_LONG_VAR.from(taskService, taskId).get() + vars[COMPLEX_SET_VAR.name] = COMPLEX_SET_VAR.from(taskService, taskId).get() + vars[COMPLEX_LIST_VAR.name] = COMPLEX_LIST_VAR.from(taskService, taskId).get() + vars[COMPLEX_MAP_VAR.name] = COMPLEX_MAP_VAR.from(taskService, taskId).get() + } + + then() + .variables_had_value(readValues = vars, variablesWithValue = createKeyValuePairs()) + } + + @Test + fun `should write local variables to task service adapter`() { + + given() + .process_with_user_task_and_listener_is_deployed(delegateExpression = "\${${DelegateConfiguration::readLocalFromDelegateTask.name}}") + .and() + .process_is_started_with_variables(variables = createVariables()) + .and() + .process_waits_in_task() + + whenever() + .task_is_accessed_in_user_task { taskService, taskId -> + STRING_VAR.on(taskService, taskId).setLocal(STRING_LOCAL.value) + DATE_VAR.on(taskService, taskId).setLocal(DATE_LOCAL.value) + SHORT_VAR.on(taskService, taskId).setLocal(SHORT_LOCAL.value) + INT_VAR.on(taskService, taskId).setLocal(INT_LOCAL.value) + LONG_VAR.on(taskService, taskId).setLocal(LONG_LOCAL.value) + DOUBLE_VAR.on(taskService, taskId).setLocal(DOUBLE_LOCAL.value) + BOOLEAN_VAR.on(taskService, taskId).setLocal(BOOLEAN_LOCAL.value) + COMPLEX_VAR.on(taskService, taskId).setLocal(COMPLEX_LOCAL.value) + LIST_STRING_VAR.on(taskService, taskId).setLocal(LIST_STRING_LOCAL.value) + SET_STRING_VAR.on(taskService, taskId).setLocal(SET_STRING_LOCAL.value) + MAP_STRING_LONG_VAR.on(taskService, taskId).setLocal(MAP_STRING_DATE_LOCAL.value) + COMPLEX_SET_VAR.on(taskService, taskId).setLocal(Companion.Values.COMPLEX_SET_LOCAL.value) + COMPLEX_LIST_VAR.on(taskService, taskId).setLocal(Companion.Values.COMPLEX_LIST_LOCAL.value) + COMPLEX_MAP_VAR.on(taskService, taskId).setLocal(Companion.Values.COMPLEX_MAP_LOCAL.value) + } + .and() + .task_is_completed() + + then() + .variables_had_value(readValues = delegateConfiguration.vars, variablesWithValue = createKeyLocalValuePairs()) + } } diff --git a/example/example-kotlin/src/test/kotlin/itest/VariableMapAdapterITest.kt b/example/example-kotlin/src/test/kotlin/itest/VariableMapAdapterITest.kt index 9514b4ed..0f3bbdc7 100644 --- a/example/example-kotlin/src/test/kotlin/itest/VariableMapAdapterITest.kt +++ b/example/example-kotlin/src/test/kotlin/itest/VariableMapAdapterITest.kt @@ -11,11 +11,10 @@ import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Value import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.INT import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_STRING import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LONG -import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_DATE +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.MAP_STRING_LONG import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SET_STRING import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.SHORT import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.STRING -import org.assertj.core.api.Assertions.assertThat import org.camunda.bpm.engine.variable.Variables.createVariables import org.junit.Rule import org.junit.Test @@ -25,8 +24,9 @@ import java.util.* class VariableMapAdapterITest : CamundaBpmDataITestBase() { + @Suppress("RedundantVisibilityModifier") @get: Rule - public val thrown = ExpectedException.none() + public val thrown: ExpectedException = ExpectedException.none() @Autowired lateinit var delegateConfiguration: DelegateConfiguration @@ -46,7 +46,11 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { COMPLEX_VAR.on(variables).set(COMPLEX.value) LIST_STRING_VAR.on(variables).set(LIST_STRING.value) SET_STRING_VAR.on(variables).set(SET_STRING.value) - MAP_STRING_DATE_VAR.on(variables).set(MAP_STRING_DATE.value) + MAP_STRING_LONG_VAR.on(variables).set(MAP_STRING_LONG.value) + COMPLEX_SET_VAR.on(variables).set(Companion.Values.COMPLEX_SET.value) + COMPLEX_LIST_VAR.on(variables).set(Companion.Values.COMPLEX_LIST.value) + COMPLEX_MAP_VAR.on(variables).set(Companion.Values.COMPLEX_MAP.value) + given() .process_with_delegate_is_deployed(delegateExpression = "\${${delegateConfiguration::readFromVariableScope.name}}") @@ -75,7 +79,7 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { STRING_VAR.on(variables).remove() LIST_STRING_VAR.on(variables).remove() SET_STRING_VAR.on(variables).remove() - MAP_STRING_DATE_VAR.on(variables).remove() + MAP_STRING_LONG_VAR.on(variables).remove() given() .process_with_delegate_is_deployed(delegateExpression = "\${${DelegateConfiguration::readOptionalFromVariableScope.name}}") @@ -88,7 +92,7 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { STRING_VAR, LIST_STRING_VAR, SET_STRING_VAR, - MAP_STRING_DATE_VAR + MAP_STRING_LONG_VAR ) .and() .variables_had_value(delegateConfiguration.optionalVars, @@ -104,98 +108,98 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { } @Test - fun `should throw correct NSO on basic setLocal exception`() { + fun `should throw correct UO exception on basic setLocal`() { thrown.expect(UnsupportedOperationException::class.java) STRING_VAR.on(createVariableMapUntyped()).setLocal(STRING.value) } @Test - fun `should throw correct NSO on list setLocal exception`() { + fun `should throw correct UO exception on list setLocal`() { thrown.expect(UnsupportedOperationException::class.java) LIST_STRING_VAR.on(createVariableMapUntyped()).setLocal(LIST_STRING.value) } @Test - fun `should throw correct NSO on set setLocal exception`() { + fun `should throw correct UO exception on set setLocal`() { thrown.expect(UnsupportedOperationException::class.java) SET_STRING_VAR.on(createVariableMapUntyped()).setLocal(SET_STRING.value) } @Test - fun `should throw correct NSO on map setLocal exception`() { + fun `should throw correct UO exception on map setLocal`() { thrown.expect(UnsupportedOperationException::class.java) - MAP_STRING_DATE_VAR.on(createVariableMapUntyped()).setLocal(MAP_STRING_DATE.value) + MAP_STRING_LONG_VAR.on(createVariableMapUntyped()).setLocal(MAP_STRING_LONG.value) } @Test - fun `should throw correct NSO on basic removeLocal exception`() { + fun `should throw correct UO exception on basic removeLocal`() { thrown.expect(UnsupportedOperationException::class.java) STRING_VAR.on(createVariableMapUntyped()).removeLocal() } @Test - fun `should throw correct NSO on list removeLocal exception`() { + fun `should throw correct UO exception on list removeLocal`() { thrown.expect(UnsupportedOperationException::class.java) LIST_STRING_VAR.on(createVariableMapUntyped()).removeLocal() } @Test - fun `should throw correct NSO on set removeLocal exception`() { + fun `should throw correct UO exception on set removeLocal`() { thrown.expect(UnsupportedOperationException::class.java) SET_STRING_VAR.on(createVariableMapUntyped()).removeLocal() } @Test - fun `should throw correct NSO on map removeLocal exception`() { + fun `should throw correct UO exception on map removeLocal`() { thrown.expect(UnsupportedOperationException::class.java) - MAP_STRING_DATE_VAR.on(createVariableMapUntyped()).removeLocal() + MAP_STRING_LONG_VAR.on(createVariableMapUntyped()).removeLocal() } @Test - fun `should throw correct NSO on basic getLocal exception`() { + fun `should throw correct UO exception on basic getLocal`() { thrown.expect(UnsupportedOperationException::class.java) STRING_VAR.from(createVariableMapUntyped()).local } @Test - fun `should throw correct NSO on list getLocal exception`() { + fun `should throw correct UO exception on list getLocal`() { thrown.expect(UnsupportedOperationException::class.java) LIST_STRING_VAR.from(createVariableMapUntyped()).local } @Test - fun `should throw correct NSO on set getLocal exception`() { + fun `should throw correct UO exception on set getLocal`() { thrown.expect(UnsupportedOperationException::class.java) SET_STRING_VAR.from(createVariableMapUntyped()).local } @Test - fun `should throw correct NSO on map getLocal exception`() { + fun `should throw correct UO exception on map getLocal`() { thrown.expect(UnsupportedOperationException::class.java) - MAP_STRING_DATE_VAR.from(createVariableMapUntyped()).local + MAP_STRING_LONG_VAR.from(createVariableMapUntyped()).local } @Test - fun `should throw correct NSO on basic getLocalOptional exception`() { + fun `should throw correct UO exception on basic getLocalOptional`() { thrown.expect(UnsupportedOperationException::class.java) STRING_VAR.from(createVariableMapUntyped()).localOptional } @Test - fun `should throw correct NSO on list getLocalOptional exception`() { + fun `should throw correct UO exception on list getLocalOptional`() { thrown.expect(UnsupportedOperationException::class.java) LIST_STRING_VAR.from(createVariableMapUntyped()).localOptional } @Test - fun `should throw correct NSO on set getLocalOptional exception`() { + fun `should throw correct UO exception on set getLocalOptional`() { thrown.expect(UnsupportedOperationException::class.java) SET_STRING_VAR.from(createVariableMapUntyped()).localOptional } @Test - fun `should throw correct NSO on map getLocalOptional exception`() { + fun `should throw correct UO exception on map getLocalOptional`() { thrown.expect(UnsupportedOperationException::class.java) - MAP_STRING_DATE_VAR.from(createVariableMapUntyped()).localOptional + MAP_STRING_LONG_VAR.from(createVariableMapUntyped()).localOptional } @Test @@ -342,7 +346,7 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { thrown.expect(WrongVariableTypeException::class.java) val variables = createVariableMapUntyped() - val wrongMapKeyType: VariableFactory> = mapVariable(MAP_STRING_DATE_VAR.name, Date::class.java, Date::class.java) + val wrongMapKeyType: VariableFactory> = mapVariable(MAP_STRING_LONG_VAR.name, Date::class.java, String::class.java) // wrong key type wrongMapKeyType.from(variables).get() } @@ -352,7 +356,7 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { thrown.expect(WrongVariableTypeException::class.java) val variables = createVariableMapUntyped() - val wrongMapKeyType: VariableFactory> = mapVariable(MAP_STRING_DATE_VAR.name, Date::class.java, Date::class.java) + val wrongMapKeyType: VariableFactory> = mapVariable(MAP_STRING_LONG_VAR.name, Date::class.java, String::class.java) // wrong key type wrongMapKeyType.from(variables).optional } @@ -362,7 +366,7 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { thrown.expect(WrongVariableTypeException::class.java) val variables = createVariableMapUntyped() - val wrongMapValueType: VariableFactory> = mapVariable(MAP_STRING_DATE_VAR.name, String::class.java, String::class.java) + val wrongMapValueType: VariableFactory> = mapVariable(MAP_STRING_LONG_VAR.name, String::class.java, Date::class.java) // wrong value type wrongMapValueType.from(variables).get() @@ -373,12 +377,10 @@ class VariableMapAdapterITest : CamundaBpmDataITestBase() { thrown.expect(WrongVariableTypeException::class.java) val variables = createVariableMapUntyped() - val wrongMapValueType: VariableFactory> = mapVariable(MAP_STRING_DATE_VAR.name, String::class.java, String::class.java) + val wrongMapValueType: VariableFactory> = mapVariable(MAP_STRING_LONG_VAR.name, String::class.java, Date::class.java) // wrong value type wrongMapValueType.from(variables).optional } - - } diff --git a/example/example-kotlin/src/test/kotlin/itest/VariableScopeAdapterITest.kt b/example/example-kotlin/src/test/kotlin/itest/VariableScopeAdapterITest.kt index f48b1850..c233b047 100644 --- a/example/example-kotlin/src/test/kotlin/itest/VariableScopeAdapterITest.kt +++ b/example/example-kotlin/src/test/kotlin/itest/VariableScopeAdapterITest.kt @@ -10,6 +10,7 @@ import java.util.* class VariableScopeAdapterITest : CamundaBpmDataITestBase() { + @Suppress("RedundantVisibilityModifier") @get: Rule public val thrown = ExpectedException.none() @@ -57,7 +58,7 @@ class VariableScopeAdapterITest : CamundaBpmDataITestBase() { STRING_VAR, LIST_STRING_VAR, SET_STRING_VAR, - MAP_STRING_DATE_VAR + MAP_STRING_LONG_VAR ) .and() .variables_had_value(delegateConfiguration.optionalVars, diff --git a/example/pom.xml b/example/pom.xml index 7030c72a..54270182 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -6,7 +6,7 @@ io.holunda.data camunda-bpm-data-parent - 0.0.6 + 1.0.0 io.holunda.data.example @@ -25,10 +25,12 @@ example-java example-kotlin + spin-type-detector + io.holunda.data camunda-bpm-data @@ -36,143 +38,106 @@ io.holunda.data - camunda-bpm-data-kotlin + camunda-bpm-data-test + test ${project.version} - io.holunda.data - camunda-bpm-data-mockito - test + io.holunda.data.example + camunda-bpm-data-spin-type-detector ${project.version} - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.camunda.bpm.springboot - camunda-bpm-spring-boot-starter-rest - ${camunda-spring-boot.version} - - - org.camunda.bpm - camunda-engine-plugin-spin - - - org.camunda.spin - camunda-spin-core - - - org.camunda.spin - camunda-spin-dataformat-json-jackson - - - - - com.fasterxml.jackson.datatype - jackson-datatype-jdk8 - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - - - com.fasterxml.jackson.module - jackson-module-kotlin - - - - org.codehaus.groovy - groovy-all - ${groovy.version} - - - com.h2database - h2 - - - - - com.tngtech.jgiven - jgiven-junit - ${jgiven.version} - test - - - com.tngtech.jgiven - jgiven-spring - ${jgiven.version} - test - - - com.tngtech.jgiven - jgiven-html5-report - ${jgiven.version} - test - - - org.springframework.boot - spring-boot-starter-test - test - - - io.holunda.testing - camunda-bpm-jgiven - 0.0.5 - test - - - + + + org.camunda.bpm.springboot + camunda-bpm-spring-boot-starter-rest + ${camunda-spring-boot.version} + - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - - + + + org.codehaus.groovy + groovy-all + ${groovy.version} + + + io.toolisticon.springboot + springboot-swagger-starter + 0.0.4 + + + io.holunda.testing + camunda-bpm-jgiven + 0.0.5 + test + + + org.camunda.bpm.assert + camunda-bpm-assert + 6.0.0 + test + + + com.tngtech.jgiven + jgiven-junit + ${jgiven.version} + test + + com.tngtech.jgiven - jgiven-maven-plugin + jgiven-spring ${jgiven.version} - - - - report - - - - - html - - - - org.jacoco - jacoco-maven-plugin - - - report-aggregate - verify - - report-aggregate - - - - - + test + + + com.tngtech.jgiven + jgiven-html5-report + ${jgiven.version} + test + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + com.tngtech.jgiven + jgiven-maven-plugin + ${jgiven.version} + + + + report + + + + + html + + + + org.jacoco + jacoco-maven-plugin + + + report-aggregate + verify + + report-aggregate + + + + + + diff --git a/example/spin-type-detector/pom.xml b/example/spin-type-detector/pom.xml new file mode 100644 index 00000000..85c73a0e --- /dev/null +++ b/example/spin-type-detector/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + + io.holunda.data.example + camunda-bpm-data-example-parent + 1.0.0 + + + camunda-bpm-data-spin-type-detector + ${project.artifactId} + jar + + + true + + + + + org.camunda.spin + camunda-spin-core + + + org.camunda.spin + camunda-spin-dataformat-json-jackson + + + org.slf4j + slf4j-simple + test + + + + diff --git a/example/spin-type-detector/src/main/java/io/holunda/camunda/bpm/data/spin/ErasedCollectionTypeDetector.java b/example/spin-type-detector/src/main/java/io/holunda/camunda/bpm/data/spin/ErasedCollectionTypeDetector.java new file mode 100644 index 00000000..a5f11cd9 --- /dev/null +++ b/example/spin-type-detector/src/main/java/io/holunda/camunda/bpm/data/spin/ErasedCollectionTypeDetector.java @@ -0,0 +1,98 @@ +package io.holunda.camunda.bpm.data.spin; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; +import org.camunda.spin.spi.TypeDetector; + +import java.lang.reflect.TypeVariable; +import java.util.Collection; +import java.util.Map; + +/** + * Detects erased types of Java Collection classes and Map. + */ +public class ErasedCollectionTypeDetector implements TypeDetector { + /** + * Object instance to use. + */ + public static ErasedCollectionTypeDetector INSTANCE = new ErasedCollectionTypeDetector(); + + + @Override + public boolean canHandle(Object value) { + return value instanceof Collection + || value instanceof Map; + } + + @Override + public String detectType(Object value) { + return constructType(value).toCanonical(); + } + + /** + * Checks if the erased type has the correct number of type bindings. + * + * @param erasedType class of the type. + * @param expectedTypeParametersCount expected number of bindings. + * + * @return true if the number of type binding matches expected value. + */ + private static boolean bindingsArePresent(Class erasedType, int expectedTypeParametersCount) { + if (erasedType == null) { + return false; + } + final TypeVariable>[] typeParameters = erasedType.getTypeParameters(); + int varLen = typeParameters != null ? typeParameters.length : 0; + if (varLen == 0) { + return false; + } + if (varLen != expectedTypeParametersCount) { + throw new IllegalArgumentException("Cannot create TypeBindings for class " + erasedType.getName() + " with " + expectedTypeParametersCount + " type parameter: class expects " + varLen + " type parameters."); + } + return true; + } + + /** + * Constructs Java type based on the content values. + * + * @param value value with values. + * + * @return Java type. + */ + private static JavaType constructType(Object value) { + final TypeFactory typeFactory = TypeFactory.defaultInstance(); + if (value instanceof Collection && !((Collection) value).isEmpty()) { + final Object firstElement = ((Collection) value).iterator().next(); + if (bindingsArePresent(value.getClass(), 1)) { + final JavaType elementType = constructType(firstElement); + return typeFactory.constructCollectionType(guessCollectionType(value), elementType); + } + } else if (value instanceof Map && !((Map) value).isEmpty()) { + final Map.Entry firstEntry = ((Map) value).entrySet().iterator().next(); + if (bindingsArePresent(firstEntry.getClass(), 2)) { + final JavaType keyType = constructType(firstEntry.getKey()); + final JavaType valueType = constructType(firstEntry.getValue()); + return typeFactory.constructMapType(Map.class, keyType, valueType); + } + } + return typeFactory.constructType(value.getClass()); + } + + /** + * Guess collection class. + * + * @param collection collection. + * + * @return class of th collection implementation. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static Class guessCollectionType(Object collection) { + if (collection instanceof Collection) { + return (Class) collection.getClass(); + } else { + throw new IllegalArgumentException("Could not detect class for " + collection + " of type " + collection.getClass().getName()); + } + } +} + + diff --git a/example/spin-type-detector/src/main/java/io/holunda/camunda/bpm/data/spin/SpinTypeDetectorConfigurator.java b/example/spin-type-detector/src/main/java/io/holunda/camunda/bpm/data/spin/SpinTypeDetectorConfigurator.java new file mode 100644 index 00000000..3f37a8b5 --- /dev/null +++ b/example/spin-type-detector/src/main/java/io/holunda/camunda/bpm/data/spin/SpinTypeDetectorConfigurator.java @@ -0,0 +1,21 @@ +package io.holunda.camunda.bpm.data.spin; + +import org.camunda.spin.impl.json.jackson.format.JacksonJsonDataFormat; +import org.camunda.spin.spi.DataFormatConfigurator; + +/** + * Spin configurator referenced in META-INF/services/org.camunda.spin.spi.DataFormatConfigurator. + * Configures the {@link ErasedCollectionTypeDetector}. + */ +public class SpinTypeDetectorConfigurator implements DataFormatConfigurator { + + @Override + public Class getDataFormatClass() { + return JacksonJsonDataFormat.class; + } + + @Override + public void configure(JacksonJsonDataFormat dataFormat) { + dataFormat.addTypeDetector(ErasedCollectionTypeDetector.INSTANCE); + } +} diff --git a/example/spin-type-detector/src/main/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator b/example/spin-type-detector/src/main/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator new file mode 100644 index 00000000..d616156a --- /dev/null +++ b/example/spin-type-detector/src/main/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator @@ -0,0 +1 @@ +io.holunda.camunda.bpm.data.spin.SpinTypeDetectorConfigurator \ No newline at end of file diff --git a/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/JacksonDeserializationTest.java b/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/JacksonDeserializationTest.java new file mode 100644 index 00000000..6fba8581 --- /dev/null +++ b/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/JacksonDeserializationTest.java @@ -0,0 +1,28 @@ +package io.holunda.camunda.bpm.data.jackson; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.CollectionType; +import org.junit.Test; + +import java.util.List; + +import static org.camunda.bpm.model.xml.test.assertions.ModelAssertions.assertThat; + +public class JacksonDeserializationTest { + + private static final MyComplexType value1 = new MyComplexType("value", 17); + private static final MyComplexType value2 = new MyComplexType("value2", 11); + + @Test + public void deserializeList() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + + String json = "[ { \"foo\": \"value\", \"bar\": 17 }, { \"foo\": \"value2\", \"bar\": 11 } ]"; + + CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, MyComplexType.class); + List deserialized = objectMapper.readValue(json, collectionType); + assertThat(deserialized).containsExactlyInAnyOrder(value1, value2); + + } +} diff --git a/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/MyComplexType.java b/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/MyComplexType.java new file mode 100644 index 00000000..0d6a68ff --- /dev/null +++ b/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/MyComplexType.java @@ -0,0 +1,54 @@ +package io.holunda.camunda.bpm.data.jackson; + +public class MyComplexType { + private String foo; + private Integer bar; + + public MyComplexType() { + } + + public MyComplexType(String foo, Integer bar) { + this.bar = bar; + this.foo = foo; + } + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + + public Integer getBar() { + return bar; + } + + public void setBar(Integer bar) { + this.bar = bar; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MyComplexType that = (MyComplexType) o; + + if (foo != null ? !foo.equals(that.foo) : that.foo != null) { + return false; + } + return bar != null ? bar.equals(that.bar) : that.bar == null; + } + + @Override + public int hashCode() { + int result = foo != null ? foo.hashCode() : 0; + result = 31 * result + (bar != null ? bar.hashCode() : 0); + return result; + } +} diff --git a/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/SpinDeserializationTest.java b/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/SpinDeserializationTest.java new file mode 100644 index 00000000..d96818d9 --- /dev/null +++ b/example/spin-type-detector/src/test/java/io/holunda/camunda/bpm/data/jackson/SpinDeserializationTest.java @@ -0,0 +1,33 @@ +package io.holunda.camunda.bpm.data.jackson; + +import org.assertj.core.util.Lists; +import org.camunda.spin.json.SpinJsonNode; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.camunda.spin.Spin.JSON; + +public class SpinDeserializationTest { + + private static final MyComplexType value1 = new MyComplexType("value", 17); + private static final MyComplexType value2 = new MyComplexType("value2", 11); + + @Test + public void deserializeList() { + + String json = "[{\"foo\":\"value\",\"bar\":17},{\"foo\":\"value2\",\"bar\":11}]"; + SpinJsonNode spinNode = JSON(json); + List deserialized = spinNode.mapTo("java.util.ArrayList<" + MyComplexType.class.getName() + ">"); + assertThat(deserialized).containsExactlyInAnyOrder(value1, value2); + } + + @Test + public void serializeList() { + List list = Lists.list(value1, value2); + String json = JSON(list).toString(); + assertThat(json).isEqualTo("[{\"foo\":\"value\",\"bar\":17},{\"foo\":\"value2\",\"bar\":11}]"); + } + +} diff --git a/extension-kotlin/pom.xml b/extension-kotlin/pom.xml deleted file mode 100644 index ca71779e..00000000 --- a/extension-kotlin/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - 4.0.0 - - - io.holunda.data - camunda-bpm-data-parent - 0.0.6 - - - camunda-bpm-data-kotlin - ${project.artifactId} - jar - - - false - - - - - io.holunda.data - camunda-bpm-data - ${project.version} - - - - - org.jetbrains.kotlin - kotlin-stdlib - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - - - org.jetbrains.kotlin - kotlin-stdlib-jdk7 - - - - - org.jetbrains.kotlin - kotlin-stdlib-jdk7 - - - org.jetbrains.kotlin - kotlin-reflect - - - io.github.microutils - kotlin-logging - - - org.jetbrains.kotlin - kotlin-stdlib - - - - - - - - - org.jetbrains.kotlin - kotlin-maven-plugin - - - - - - - release - - - release - - - - - - org.jetbrains.dokka - dokka-maven-plugin - - - org.codehaus.mojo - build-helper-maven-plugin - - - - - - - diff --git a/extension-kotlin/src/main/kotlin/CamundaBpmDataKotlin.kt b/extension-kotlin/src/main/kotlin/CamundaBpmDataKotlin.kt deleted file mode 100644 index bc354ff8..00000000 --- a/extension-kotlin/src/main/kotlin/CamundaBpmDataKotlin.kt +++ /dev/null @@ -1,42 +0,0 @@ -package io.holunda.camunda.bpm.data - -import io.holunda.camunda.bpm.data.factory.* - -/** - * Provides reified methods for variable factory construction. - */ -object CamundaBpmDataKotlin { - - /** - * Reified version of the basic variable factory. - * @param name The name of the variable. - * @param T The type of the variable. - * @return instance of [VariableFactory] - */ - inline fun customVariable(name: String): VariableFactory = BasicVariableFactory(name, T::class.java) - - /** - * Reified version of list variable factory. - * @param name The name of the variable. - * @param T The type of the variable. - * @return instance of [VariableFactory] - */ - inline fun listVariable(name: String): VariableFactory> = ListVariableFactory(name, T::class.java) - - /** - * Reified version of set variable factory. - * @param name The name of the variable. - * @param T The type of the variable. - * @return instance of [VariableFactory] - */ - inline fun setVariable(name: String): VariableFactory> = SetVariableFactory(name, T::class.java) - - /** - * Reified version of map variable factory. - * @param name The name of the variable. - * @param K The type of the variable key. - * @param V The type of the variable value. - * @return instance of [VariableFactory] - */ - inline fun mapVariable(name: String): VariableFactory> = MapVariableFactory(name, K::class.java, V::class.java) -} diff --git a/extension/pom.xml b/extension/core/pom.xml similarity index 63% rename from extension/pom.xml rename to extension/core/pom.xml index a1a98874..5c5c95d8 100644 --- a/extension/pom.xml +++ b/extension/core/pom.xml @@ -6,7 +6,8 @@ io.holunda.data camunda-bpm-data-parent - 0.0.6 + 1.0.0 + ../.. camunda-bpm-data @@ -57,6 +58,40 @@ slf4j-simple test + + org.camunda.bpm.assert + camunda-bpm-assert + test + + + com.h2database + h2 + test + + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + test + + + com.fasterxml.jackson.module + jackson-module-kotlin + test + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-databind + diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/CamundaBpmData.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/CamundaBpmData.java similarity index 59% rename from extension/src/main/java/io/holunda/camunda/bpm/data/CamundaBpmData.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/CamundaBpmData.java index 0457fabe..f3717bb5 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/CamundaBpmData.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/CamundaBpmData.java @@ -1,39 +1,45 @@ package io.holunda.camunda.bpm.data; -import io.holunda.camunda.bpm.data.builder.ProcessExecutionVariableBuilder; -import io.holunda.camunda.bpm.data.builder.UserTaskVariableBuilder; import io.holunda.camunda.bpm.data.builder.VariableMapBuilder; -import io.holunda.camunda.bpm.data.builder.VariableScopeBuilder; import io.holunda.camunda.bpm.data.factory.BasicVariableFactory; import io.holunda.camunda.bpm.data.factory.ListVariableFactory; import io.holunda.camunda.bpm.data.factory.MapVariableFactory; import io.holunda.camunda.bpm.data.factory.SetVariableFactory; import io.holunda.camunda.bpm.data.factory.VariableFactory; +import io.holunda.camunda.bpm.data.reader.RuntimeServiceVariableReader; +import io.holunda.camunda.bpm.data.reader.TaskServiceVariableReader; +import io.holunda.camunda.bpm.data.reader.VariableMapReader; +import io.holunda.camunda.bpm.data.reader.VariableReader; +import io.holunda.camunda.bpm.data.reader.VariableScopeReader; +import io.holunda.camunda.bpm.data.writer.RuntimeServiceVariableWriter; +import io.holunda.camunda.bpm.data.writer.TaskServiceVariableWriter; +import io.holunda.camunda.bpm.data.writer.VariableMapWriter; +import io.holunda.camunda.bpm.data.writer.VariableScopeWriter; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.delegate.VariableScope; import org.camunda.bpm.engine.variable.VariableMap; import org.jetbrains.annotations.NotNull; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * Provides a collection of factory methods for creating variable factories. */ public class CamundaBpmData { + /** * Hide the instantiations. */ - private CamundaBpmData() { } + private CamundaBpmData() { + } /** * Creates a string variable factory. * * @param variableName name of the variable. - * * @return variable factory for string. */ @NotNull @@ -45,7 +51,6 @@ public static VariableFactory stringVariable(@NotNull String variableNam * Creates a date variable factory. * * @param variableName name of the variable. - * * @return variable factory for date. */ @NotNull @@ -57,7 +62,6 @@ public static VariableFactory dateVariable(@NotNull String variableName) { * Creates an integer variable factory. * * @param variableName name of the variable. - * * @return variable factory for integer. */ @NotNull @@ -69,7 +73,6 @@ public static VariableFactory intVariable(@NotNull String variableName) * Creates a long variable factory. * * @param variableName name of the variable. - * * @return variable factory for long. */ @NotNull @@ -81,7 +84,6 @@ public static VariableFactory longVariable(@NotNull String variableName) { * Creates a short variable factory. * * @param variableName name of the variable. - * * @return variable factory for short. */ @NotNull @@ -93,7 +95,6 @@ public static VariableFactory shortVariable(@NotNull String variableName) * Creates a double variable factory. * * @param variableName name of the variable. - * * @return variable factory for double. */ @NotNull @@ -105,7 +106,6 @@ public static VariableFactory doubleVariable(@NotNull String variableNam * Creates a boolean variable factory. * * @param variableName name of the variable. - * * @return variable factory for boolean. */ @NotNull @@ -117,9 +117,8 @@ public static VariableFactory booleanVariable(@NotNull String variableN * Creates a variable factory for custom type. * * @param variableName name of the variable. - * @param clazz class of specifying the type. - * @param factory type. - * + * @param clazz class of specifying the type. + * @param factory type. * @return variable factory for given type. */ @NotNull @@ -131,9 +130,8 @@ public static VariableFactory customVariable(@NotNull String variableName * Creates a variable factory for list of custom type. * * @param variableName name of the variable. - * @param clazz class of specifying the member type. - * @param factory type. - * + * @param clazz class of specifying the member type. + * @param factory type. * @return variable factory for given type. */ @NotNull @@ -145,9 +143,8 @@ public static VariableFactory> listVariable(@NotNull String variable * Creates a variable factory for set of custom type. * * @param variableName name of the variable. - * @param clazz class of specifying the member type. - * @param factory type. - * + * @param clazz class of specifying the member type. + * @param factory type. * @return variable factory for given type. */ @NotNull @@ -159,67 +156,112 @@ public static VariableFactory> setVariable(@NotNull String variableNa * Creates a variable factory for map of custom key and custom value type. * * @param variableName name of the variable. - * @param keyClazz class of specifying the key member type. - * @param valueClazz class of specifying the value member type. - * @param factory key type. - * @param factory value type. - * + * @param keyClazz class of specifying the key member type. + * @param valueClazz class of specifying the value member type. + * @param factory key type. + * @param factory value type. * @return variable factory for given type. */ @NotNull - public static VariableFactory> mapVariable(@NotNull String variableName, @NotNull Class keyClazz, @NotNull Class valueClazz) { + public static VariableFactory> mapVariable(@NotNull String variableName, @NotNull Class keyClazz, + @NotNull Class valueClazz) { return new MapVariableFactory<>(variableName, keyClazz, valueClazz); } /** * Creates a new variable map builder. - * @return new builder with empty variable map. + * + * @return new writer with empty variable map. */ - @NotNull public static VariableMapBuilder builder() { return new VariableMapBuilder(); } /** * Creates a new variable map builder. - * @param variables pre-filled variables. - * @return new builder with a variable map containing a copy of provided variables. + * + * @param variables pre-created, potentially non-empty variables. + * @return new writer */ @NotNull - public static VariableMapBuilder builder(VariableMap variables) { - return new VariableMapBuilder(variables); + public static VariableMapWriter writer(VariableMap variables) { + return new VariableMapWriter(variables); } /** - * Creates a new variable scope builder. + * Creates a new variable scope writer. + * * @param variableScope scope to work on (delegate execution or delegate task). - * @return new builder working on provided variable scope. + * @return new writer working on provided variable scope. */ @NotNull - public static VariableScopeBuilder builder(VariableScope variableScope) { - return new VariableScopeBuilder(variableScope); + public static VariableScopeWriter writer(VariableScope variableScope) { + return new VariableScopeWriter(variableScope); } /** - * Creates a new execution variable builder. + * Creates a new execution variable writer. + * * @param runtimeService runtime service to use. * @param executionId id of the execution. - * @return new builder working on provided process execution. + * @return new writer working on provided process execution. */ @NotNull - public static ProcessExecutionVariableBuilder builder(RuntimeService runtimeService, String executionId) { - return new ProcessExecutionVariableBuilder(runtimeService, executionId); + public static RuntimeServiceVariableWriter writer(RuntimeService runtimeService, String executionId) { + return new RuntimeServiceVariableWriter(runtimeService, executionId); } /** - * Creates a new task variable builder. + * Creates a new task variable writer. + * * @param taskService task service to use. * @param taskId task id. - * @return new builder working on provided user task. + * @return new writer working on provided user task. + */ + @NotNull + public static TaskServiceVariableWriter writer(TaskService taskService, String taskId) { + return new TaskServiceVariableWriter(taskService, taskId); + } + + /** + * Creates a new task variable reader. + * + * @param taskService the Camunda task service + * @param taskId the id of the task to use + * @return variable reader working on task */ @NotNull - public static UserTaskVariableBuilder builder(TaskService taskService, String taskId) { - return new UserTaskVariableBuilder(taskService, taskId); + public static VariableReader reader(TaskService taskService, String taskId) { + return new TaskServiceVariableReader(taskService, taskId); } + /** + * Creates a new execution variable reader. + * + * @param runtimeService the Camunda runtime service + * @param executionId the executionId to use + * @return variable reader working on execution + */ + public static VariableReader reader(RuntimeService runtimeService, String executionId) { + return new RuntimeServiceVariableReader(runtimeService, executionId); + } + + /** + * Creates a new variableScope variable reader. + * + * @param variableScope the variable scope to use (DelegateExecution, DelegateTask) + * @return variable reader working on variableScope + */ + public static VariableReader reader(VariableScope variableScope) { + return new VariableScopeReader(variableScope); + } + + /** + * Creates a new variableMap variable reader. + * @param variableMap the variableMap to use + * @return variable reader working on variableMap + */ + public static VariableReader reader(VariableMap variableMap) { + return new VariableMapReader(variableMap); + } } diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/AbstractReadWriteAdapter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/AbstractReadWriteAdapter.java similarity index 100% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/AbstractReadWriteAdapter.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/AbstractReadWriteAdapter.java diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/ReadAdapter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/ReadAdapter.java similarity index 83% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/ReadAdapter.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/ReadAdapter.java index 980b0ae6..2a9f4022 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/ReadAdapter.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/ReadAdapter.java @@ -18,7 +18,6 @@ public interface ReadAdapter { /** * Reads a variable and returns a value if exists or an empty. * @return optional. - * @exception IllegalStateException if the required variable can't be read. */ Optional getOptional(); @@ -32,7 +31,6 @@ public interface ReadAdapter { /** * Reads a local variable and returns a value if exists or an empty. * @return optional. - * @exception IllegalStateException if the required variable can't be read. */ Optional getLocalOptional(); diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtil.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtil.java new file mode 100644 index 00000000..e9857360 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtil.java @@ -0,0 +1,151 @@ +package io.holunda.camunda.bpm.data.adapter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.CollectionType; +import com.fasterxml.jackson.databind.type.MapType; +import org.camunda.bpm.engine.variable.impl.value.ObjectValueImpl; +import org.camunda.bpm.engine.variable.value.ObjectValue; +import org.camunda.bpm.engine.variable.value.TypedValue; + +import java.util.Collection; +import java.util.Date; +import java.util.Map; + +import static org.camunda.bpm.engine.variable.Variables.*; + +/** + * Static util methods. + */ +public class ValueWrapperUtil { + + /** + * Hide instantiation. + */ + private ValueWrapperUtil() { + + } + + /** + * Delivers typed value for a given type and value. + * + * @param clazz class of value. + * @param value value to encapsulate. + * @param isTransient transient flag. + * @param type of value. + * + * @return typed value. + * + * @throws IllegalArgumentException if value and clazz are incompatible. + */ + public static TypedValue getTypedValue(Class clazz, Object value, boolean isTransient) { + if (value != null && !clazz.isAssignableFrom(value.getClass())) { + throw new IllegalArgumentException("Couldn't create TypedValue for " + clazz.getSimpleName() + " from value " + value); + } + + if (String.class.equals(clazz)) { + return stringValue((String) value, isTransient); + } else if (Boolean.class.equals(clazz)) { + return booleanValue((Boolean) value, isTransient); + } else if (Integer.class.equals(clazz)) { + return integerValue((Integer) value, isTransient); + } else if (Short.class.equals(clazz)) { + return shortValue((Short) value, isTransient); + } else if (Long.class.equals(clazz)) { + return longValue((Long) value, isTransient); + } else if (Date.class.equals(clazz)) { + return dateValue((Date) value, isTransient); + } else if (Double.class.equals(clazz)) { + return doubleValue((Double) value, isTransient); + } else if (Object.class.equals(clazz)) { + return objectValue(value, isTransient).create(); + } else { + // fallback for unknown-type + return untypedValue(value, isTransient); + } + } + + /** + * Tries to read a collection type from a typed value containing the serialized json. + * + * @param typedValue value from camunda. + * @param variableName name of the variable. + * @param memberClazz clazz of the collection member. + * @param objectMapper jackson object mapper. + * @param collectionType constructed collection type. + * @param type of collection member. + * @param type of collection. + * + * @return collection of specified type or null. + */ + public static > C readFromTypedValue( + TypedValue typedValue, String variableName, Class memberClazz, ObjectMapper objectMapper, CollectionType collectionType) { + if (typedValue == null) { + return null; + } + if (typedValue instanceof ObjectValueImpl) { + final ObjectValue objectValue = (ObjectValueImpl) typedValue; + final String json = objectValue.getValueSerialized(); + try { + final C values = objectMapper.readValue(json, collectionType); + if (values.isEmpty()) { + return values; + } else { + if (memberClazz.isAssignableFrom(values.iterator().next().getClass())) { + return values; + } else { + throw new WrongVariableTypeException("Error reading " + variableName + ": Wrong member type detected, expected " + memberClazz.getName() + ", but was not found in " + values); + } + } + } catch (JsonProcessingException jpe) { + throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value from " + json); + } + } else { + throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value from " + typedValue); + } + } + + /** + * Tries to read a collection type from a typed value containing the serialized json. + * + * @param typedValue value from camunda. + * @param variableName name of the variable. + * @param keyClazz clazz of the map key. + * @param valueClazz clazz of the map value. + * @param objectMapper jackson object mapper. + * @param mapType constructed map type. + * @param type of map key. + * @param type of myp value. + * + * @return map of specified types or null. + */ + public static Map readFromTypedValue( + TypedValue typedValue, String variableName, Class keyClazz, Class valueClazz, + ObjectMapper objectMapper, MapType mapType) { + if (typedValue == null) { + return null; + } + if (typedValue instanceof ObjectValueImpl) { + final ObjectValue objectValue = (ObjectValueImpl) typedValue; + final String json = objectValue.getValueSerialized(); + try { + final Map map = objectMapper.readValue(json, mapType); + if (map.isEmpty()) { + return map; + } else { + final Map.Entry entry = map.entrySet().iterator().next(); + if (valueClazz.isAssignableFrom(entry.getValue().getClass()) && keyClazz.isAssignableFrom(entry.getKey().getClass())) { + return map; + } else { + throw new WrongVariableTypeException("Error reading " + variableName + ": Wrong map type detected, expected key " + + keyClazz.getName() + " and value " + valueClazz.getName() + ", but was not found in " + map); + } + } + } catch (JsonProcessingException jpe) { + throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value from " + json); + } + } else { + throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value from " + typedValue); + } + } +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/VariableNotFoundException.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/VariableNotFoundException.java similarity index 52% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/VariableNotFoundException.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/VariableNotFoundException.java index b7ec47d3..e2858b54 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/VariableNotFoundException.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/VariableNotFoundException.java @@ -4,12 +4,13 @@ * Exception indicating that a variable is not found. */ public class VariableNotFoundException extends RuntimeException { - /** - * Constructs the exception. - * @param reason reason. - */ - VariableNotFoundException(String reason) { - super(reason); - } + /** + * Constructs the exception. + * + * @param reason reason. + */ + VariableNotFoundException(String reason) { + super(reason); + } } diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/WriteAdapter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/WriteAdapter.java similarity index 98% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/WriteAdapter.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/WriteAdapter.java index e5e0517c..fe47ac10 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/WriteAdapter.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/WriteAdapter.java @@ -21,7 +21,7 @@ public interface WriteAdapter { /** * Writes a value as a transient variable. * - * @param value value to rite. + * @param value value to write. * @param isTransient allows to specify if the variable is transient. */ void set(T value, boolean isTransient); diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/WrongVariableTypeException.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/WrongVariableTypeException.java similarity index 56% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/WrongVariableTypeException.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/WrongVariableTypeException.java index 7e07d3f0..6920ee5f 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/WrongVariableTypeException.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/WrongVariableTypeException.java @@ -4,10 +4,10 @@ * Exception indicating that a variable has a different type than requested. */ public class WrongVariableTypeException extends RuntimeException { - /** - * Constructs the exception. - * - * @param reason reason. - */ - public WrongVariableTypeException(String reason) { super(reason); } + /** + * Constructs the exception. + * + * @param reason reason. + */ + public WrongVariableTypeException(String reason) { super(reason); } } diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/AbstractBasicReadWriteAdapter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/AbstractBasicReadWriteAdapter.java new file mode 100644 index 00000000..9c1d191e --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/AbstractBasicReadWriteAdapter.java @@ -0,0 +1,54 @@ +package io.holunda.camunda.bpm.data.adapter.basic; + +import io.holunda.camunda.bpm.data.adapter.AbstractReadWriteAdapter; +import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil; +import io.holunda.camunda.bpm.data.adapter.WrongVariableTypeException; +import org.camunda.bpm.engine.variable.value.TypedValue; + +/** + * Base class for all basic read-write-adapter. + * + * @param variable type. + */ +public abstract class AbstractBasicReadWriteAdapter extends AbstractReadWriteAdapter { + /** + * Variable type. + */ + protected final Class clazz; + + /** + * Constructs the adapter. + * + * @param variableName name of the variable. + * @param clazz variable type. + */ + public AbstractBasicReadWriteAdapter(String variableName, Class clazz) { + super(variableName); + this.clazz = clazz; + } + + /** + * Retrieves the value or null. + * + * @param value raw value. + * + * @return value or null. + */ + @SuppressWarnings("unchecked") + protected T getOrNull(Object value) { + + if (value == null) { + return null; + } + + if (clazz.isAssignableFrom(value.getClass())) { + return (T) value; + } + throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value of " + clazz + " from " + value); + } + + @Override + public TypedValue getTypedValue(Object value, boolean isTransient) { + return ValueWrapperUtil.getTypedValue(clazz, value, isTransient); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterRuntimeService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterRuntimeService.java new file mode 100644 index 00000000..c67c38da --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterRuntimeService.java @@ -0,0 +1,60 @@ +package io.holunda.camunda.bpm.data.adapter.basic; + +import org.camunda.bpm.engine.RuntimeService; + +import java.util.Optional; + +/** + * Read write adapter for runtime service access. + * + * @param type of value. + */ +public class ReadWriteAdapterRuntimeService extends AbstractBasicReadWriteAdapter { + + private final RuntimeService runtimeService; + private final String executionId; + + /** + * Constructs the adapter. + * + * @param runtimeService runtime service to use. + * @param executionId id of the execution to read from and write to. + * @param variableName name of the variable. + * @param clazz class of the variable. + */ + public ReadWriteAdapterRuntimeService(RuntimeService runtimeService, String executionId, String variableName, Class clazz) { + super(variableName, clazz); + this.runtimeService = runtimeService; + this.executionId = executionId; + } + + @Override + public Optional getOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); + } + + @Override + public void set(T value, boolean isTransient) { + runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional getLocalOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); + } + + @Override + public void setLocal(T value, boolean isTransient) { + runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + runtimeService.removeVariable(executionId, variableName); + } + + @Override + public void removeLocal() { + runtimeService.removeVariableLocal(executionId, variableName); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterTaskService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterTaskService.java new file mode 100644 index 00000000..95845fd2 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterTaskService.java @@ -0,0 +1,60 @@ +package io.holunda.camunda.bpm.data.adapter.basic; + +import org.camunda.bpm.engine.TaskService; + +import java.util.Optional; + +/** + * Read write adapter for task service access. + * + * @param type of value. + */ +public class ReadWriteAdapterTaskService extends AbstractBasicReadWriteAdapter { + + private final TaskService taskService; + private final String taskId; + + /** + * Constructs the adapter. + * + * @param taskService task service to use. + * @param taskId id of the task to read from and write to. + * @param variableName name of the variable. + * @param clazz class of the variable. + */ + public ReadWriteAdapterTaskService(TaskService taskService, String taskId, String variableName, Class clazz) { + super(variableName, clazz); + this.taskService = taskService; + this.taskId = taskId; + } + + @Override + public Optional getOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); + } + + @Override + public void set(T value, boolean isTransient) { + taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional getLocalOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); + } + + @Override + public void setLocal(T value, boolean isTransient) { + taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + taskService.removeVariable(taskId, variableName); + } + + @Override + public void removeLocal() { + taskService.removeVariableLocal(taskId, variableName); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableMap.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableMap.java new file mode 100644 index 00000000..ac997a3a --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableMap.java @@ -0,0 +1,57 @@ +package io.holunda.camunda.bpm.data.adapter.basic; + +import org.camunda.bpm.engine.variable.VariableMap; + +import java.util.Optional; + +/** + * Read-write adapter for variable map. + * + * @param type of value. + */ +public class ReadWriteAdapterVariableMap extends AbstractBasicReadWriteAdapter { + + private final VariableMap variableMap; + + /** + * Constructs the adapter. + * + * @param variableMap variable map to access. + * @param variableName variable to access. + * @param clazz class of variable value. + */ + public ReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class clazz) { + super(variableName, clazz); + this.variableMap = variableMap; + } + + @Override + public Optional getOptional() { + return Optional.ofNullable(getOrNull(variableMap.get(variableName))); + } + + @Override + public void set(T value, boolean isTransient) { + variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional getLocalOptional() { + throw new UnsupportedOperationException("Can't get a local variable on a variable map"); + } + + @Override + public void setLocal(T value, boolean isTransient) { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } + + @Override + public void remove() { + variableMap.remove(variableName); + } + + @Override + public void removeLocal() { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableScope.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableScope.java new file mode 100644 index 00000000..c8315f6f --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableScope.java @@ -0,0 +1,57 @@ +package io.holunda.camunda.bpm.data.adapter.basic; + +import org.camunda.bpm.engine.delegate.VariableScope; + +import java.util.Optional; + +/** + * Read-write adapter for variable scope. + * + * @param type of value. + */ +public class ReadWriteAdapterVariableScope extends AbstractBasicReadWriteAdapter { + + private final VariableScope variableScope; + + /** + * Constructs the adapter. + * + * @param variableScope variable scope to access. + * @param variableName variable to access. + * @param clazz class of variable value. + */ + public ReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class clazz) { + super(variableName, clazz); + this.variableScope = variableScope; + } + + @Override + public void set(T value, boolean isTransient) { + variableScope.setVariable(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional getLocalOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); + } + + @Override + public void setLocal(T value, boolean isTransient) { + variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional getOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); + } + + @Override + public void remove() { + variableScope.removeVariable(variableName); + } + + @Override + public void removeLocal() { + variableScope.removeVariableLocal(variableName); + } +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/package-info.java similarity index 98% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/package-info.java index 8feaf636..20cbb819 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/package-info.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/package-info.java @@ -1,6 +1,7 @@ /** * Read/Write adapters for basic variable factory. - * @since 0.0.2 + * * @see io.holunda.camunda.bpm.data.factory.BasicVariableFactory for more details + * @since 0.0.2 */ package io.holunda.camunda.bpm.data.adapter.basic; diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.java new file mode 100644 index 00000000..548e35b8 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.java @@ -0,0 +1,68 @@ +package io.holunda.camunda.bpm.data.adapter.list; + +import io.holunda.camunda.bpm.data.adapter.AbstractReadWriteAdapter; +import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil; +import io.holunda.camunda.bpm.data.adapter.WrongVariableTypeException; +import org.camunda.bpm.engine.variable.value.TypedValue; + +import java.util.Collections; +import java.util.List; + +/** + * Base class for all list read-write adapter. + * + * @param member type. + */ +public abstract class AbstractListReadWriteAdapter extends AbstractReadWriteAdapter> { + + /** + * Member class. + */ + protected final Class memberClazz; + + /** + * Constructs the adapter. + * + * @param variableName name of variable. + * @param memberClazz member class. + */ + public AbstractListReadWriteAdapter(String variableName, Class memberClazz) { + super(variableName); + this.memberClazz = memberClazz; + } + + /** + * Read the value of null. + * + * @param value raw value. + * + * @return list or null. + */ + @SuppressWarnings("unchecked") + protected List getOrNull(Object value) { + if (value == null) { + return null; + } + + if (List.class.isAssignableFrom(value.getClass())) { + List valueAsList = (List) value; + if (valueAsList.isEmpty()) { + return Collections.emptyList(); + } else { + if (memberClazz.isAssignableFrom(valueAsList.iterator().next().getClass())) { + return (List) valueAsList; + } else { + throw new WrongVariableTypeException("Error reading " + variableName + ": Wrong list type detected, expected " + memberClazz.getName() + ", but was not found in " + valueAsList); + } + } + } + + throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value of type List from " + value); + } + + @Override + public TypedValue getTypedValue(Object value, boolean isTransient) { + return ValueWrapperUtil.getTypedValue(List.class, value, isTransient); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterRuntimeService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterRuntimeService.java new file mode 100644 index 00000000..2deb4ffd --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterRuntimeService.java @@ -0,0 +1,61 @@ +package io.holunda.camunda.bpm.data.adapter.list; + +import org.camunda.bpm.engine.RuntimeService; + +import java.util.List; +import java.util.Optional; + +/** + * Read write adapter for runtime service access. + * + * @param type of value. + */ +public class ListReadWriteAdapterRuntimeService extends AbstractListReadWriteAdapter { + + private final RuntimeService runtimeService; + private final String executionId; + + /** + * Constructs the adapter. + * + * @param runtimeService runtime service to use. + * @param executionId id of the execution to read from and write to. + * @param variableName name of the variable. + * @param memberClazz class of the variable. + */ + public ListReadWriteAdapterRuntimeService(RuntimeService runtimeService, String executionId, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.runtimeService = runtimeService; + this.executionId = executionId; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); + } + + @Override + public void set(List value, boolean isTransient) { + runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); + } + + @Override + public void setLocal(List value, boolean isTransient) { + runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + runtimeService.removeVariable(executionId, variableName); + } + + @Override + public void removeLocal() { + runtimeService.removeVariableLocal(executionId, variableName); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterTaskService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterTaskService.java new file mode 100644 index 00000000..350e2824 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterTaskService.java @@ -0,0 +1,62 @@ +package io.holunda.camunda.bpm.data.adapter.list; + +import org.camunda.bpm.engine.TaskService; + +import java.util.List; +import java.util.Optional; + +/** + * Read write adapter for task service access. + * + * @param type of value. + */ +public class ListReadWriteAdapterTaskService extends AbstractListReadWriteAdapter { + + private final TaskService taskService; + private final String taskId; + + /** + * Constructs the adapter. + * + * @param taskService task service to use. + * @param taskId id of the task to read from and write to. + * @param variableName name of the variable. + * @param memberClazz class of the variable. + */ + public ListReadWriteAdapterTaskService(TaskService taskService, String taskId, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.taskService = taskService; + this.taskId = taskId; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); + } + + @Override + public void set(List value, boolean isTransient) { + taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); + } + + @Override + public void setLocal(List value, boolean isTransient) { + taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + taskService.removeVariable(taskId, variableName); + } + + @Override + public void removeLocal() { + taskService.removeVariableLocal(taskId, variableName); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableMap.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableMap.java new file mode 100644 index 00000000..2d5e6715 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableMap.java @@ -0,0 +1,59 @@ +package io.holunda.camunda.bpm.data.adapter.list; + +import org.camunda.bpm.engine.variable.VariableMap; + +import java.util.List; +import java.util.Optional; + +/** + * Read-write adapter for variable map. + * + * @param type of value. + */ +public class ListReadWriteAdapterVariableMap extends AbstractListReadWriteAdapter { + + private final VariableMap variableMap; + + /** + * Constructs the adapter. + * + * @param variableMap variable map to access. + * @param variableName variable to access. + * @param memberClazz class of variable value. + */ + public ListReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.variableMap = variableMap; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(variableMap.get(variableName))); + } + + @Override + public void set(List value, boolean isTransient) { + variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + throw new UnsupportedOperationException("Can't get a local variable on a variable map"); + } + + @Override + public void setLocal(List value, boolean isTransient) { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } + + @Override + public void remove() { + variableMap.remove(variableName); + } + + @Override + public void removeLocal() { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableScope.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableScope.java new file mode 100644 index 00000000..d0dbcf08 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableScope.java @@ -0,0 +1,59 @@ +package io.holunda.camunda.bpm.data.adapter.list; + +import org.camunda.bpm.engine.delegate.VariableScope; + +import java.util.List; +import java.util.Optional; + +/** + * Read-write adapter for variable scope. + * + * @param type of value. + */ +public class ListReadWriteAdapterVariableScope extends AbstractListReadWriteAdapter { + + private final VariableScope variableScope; + + /** + * Constructs the adapter. + * + * @param variableScope variable scope to access. + * @param variableName variable to access. + * @param memberClazz class of member variable value. + */ + public ListReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.variableScope = variableScope; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); + } + + @Override + public void set(List value, boolean isTransient) { + variableScope.setVariable(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); + } + + @Override + public void setLocal(List value, boolean isTransient) { + variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + variableScope.removeVariable(variableName); + } + + @Override + public void removeLocal() { + variableScope.removeVariableLocal(variableName); + } + +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/package-info.java similarity index 98% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/package-info.java index 40642338..4a592c9e 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/package-info.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/list/package-info.java @@ -1,6 +1,7 @@ /** * Read/Write adapters for list variable factory. - * @since 0.0.2 + * * @see io.holunda.camunda.bpm.data.factory.ListVariableFactory for more details + * @since 0.0.2 */ package io.holunda.camunda.bpm.data.adapter.list; diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.java similarity index 97% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.java index b0795bcf..95a8d0cb 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.java @@ -54,7 +54,7 @@ protected Map getOrNull(Object value) { if (Map.class.isAssignableFrom(value.getClass())) { Map valueAsMap = (Map) value; if (valueAsMap.isEmpty()) { - return Collections.emptyMap(); + return Collections.emptyMap(); } else { Map.Entry entry = valueAsMap.entrySet().iterator().next(); if (keyClazz.isAssignableFrom(entry.getKey().getClass()) && valueClazz.isAssignableFrom(entry.getValue().getClass())) { diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterRuntimeService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterRuntimeService.java new file mode 100644 index 00000000..6d78f75d --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterRuntimeService.java @@ -0,0 +1,64 @@ +package io.holunda.camunda.bpm.data.adapter.map; + +import org.camunda.bpm.engine.RuntimeService; + +import java.util.Map; +import java.util.Optional; + +/** + * Read write adapter for runtime service access. + * + * @param type of key. + * @param type of value. + */ +public class MapReadWriteAdapterRuntimeService extends AbstractMapReadWriteAdapter { + + private final RuntimeService runtimeService; + private final String executionId; + + /** + * Constructs the adapter. + * + * @param runtimeService runtime service to use. + * @param executionId id of the execution to read from and write to. + * @param variableName name of the variable. + * @param keyClazz class of the key variable. + * @param valueClazz class of the value variable. + */ + public MapReadWriteAdapterRuntimeService( + RuntimeService runtimeService, String executionId, String variableName, Class keyClazz, Class valueClazz) { + super(variableName, keyClazz, valueClazz); + this.runtimeService = runtimeService; + this.executionId = executionId; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); + } + + @Override + public void set(Map value, boolean isTransient) { + runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); + } + + @Override + public void setLocal(Map value, boolean isTransient) { + runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + runtimeService.removeVariable(executionId, variableName); + } + + @Override + public void removeLocal() { + runtimeService.removeVariableLocal(executionId, variableName); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterTaskService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterTaskService.java new file mode 100644 index 00000000..75089aee --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterTaskService.java @@ -0,0 +1,65 @@ +package io.holunda.camunda.bpm.data.adapter.map; + +import org.camunda.bpm.engine.TaskService; + +import java.util.Map; +import java.util.Optional; + +/** + * Read write adapter for task service access. + * + * @param type of key. + * @param type of value. + */ +public class MapReadWriteAdapterTaskService extends AbstractMapReadWriteAdapter { + + private final TaskService taskService; + private final String taskId; + + /** + * Constructs the adapter. + * + * @param taskService task service to use. + * @param taskId id of the task to read from and write to. + * @param variableName name of the variable. + * @param keyClazz class of the key of variable. + * @param valueClazz class of variable. + */ + public MapReadWriteAdapterTaskService( + TaskService taskService, String taskId, String variableName, Class keyClazz, Class valueClazz) { + super(variableName, keyClazz, valueClazz); + this.taskService = taskService; + this.taskId = taskId; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); + } + + @Override + public void set(Map value, boolean isTransient) { + taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); + } + + @Override + public void setLocal(Map value, boolean isTransient) { + taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + taskService.removeVariable(taskId, variableName); + } + + @Override + public void removeLocal() { + taskService.removeVariableLocal(taskId, variableName); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableMap.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableMap.java new file mode 100644 index 00000000..2c202a8a --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableMap.java @@ -0,0 +1,61 @@ +package io.holunda.camunda.bpm.data.adapter.map; + +import org.camunda.bpm.engine.variable.VariableMap; + +import java.util.Map; +import java.util.Optional; + +/** + * Read-write adapter for variable map. + * + * @param type of key. + * @param type of value. + */ +public class MapReadWriteAdapterVariableMap extends AbstractMapReadWriteAdapter { + + private final VariableMap variableMap; + + /** + * Constructs the adapter. + * + * @param variableMap variable map to access. + * @param variableName variable to access. + * @param keyClazz class of variable key. + * @param valueClazz class of variable value. + */ + public MapReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class keyClazz, Class valueClazz) { + super(variableName, keyClazz, valueClazz); + this.variableMap = variableMap; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(variableMap.get(variableName))); + } + + @Override + public void set(Map value, boolean isTransient) { + variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + throw new UnsupportedOperationException("Can't get a local variable on a variable map"); + } + + @Override + public void setLocal(Map value, boolean isTransient) { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } + + @Override + public void remove() { + variableMap.remove(variableName); + } + + @Override + public void removeLocal() { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableScope.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableScope.java new file mode 100644 index 00000000..fa89f147 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableScope.java @@ -0,0 +1,61 @@ +package io.holunda.camunda.bpm.data.adapter.map; + +import org.camunda.bpm.engine.delegate.VariableScope; + +import java.util.Map; +import java.util.Optional; + +/** + * Read-write adapter for variable scope. + * + * @param type of key. + * @param type of value. + */ +public class MapReadWriteAdapterVariableScope extends AbstractMapReadWriteAdapter { + + private final VariableScope variableScope; + + /** + * Constructs the adapter. + * + * @param variableScope variable scope to access. + * @param variableName variable to access. + * @param keyClazz class of variable key. + * @param valueClazz class of variable value. + */ + public MapReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class keyClazz, Class valueClazz) { + super(variableName, keyClazz, valueClazz); + this.variableScope = variableScope; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); + } + + @Override + public void set(Map value, boolean isTransient) { + variableScope.setVariable(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); + } + + @Override + public void setLocal(Map value, boolean isTransient) { + variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + variableScope.removeVariable(variableName); + } + + @Override + public void removeLocal() { + variableScope.removeVariableLocal(variableName); + } + +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/package-info.java similarity index 98% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/package-info.java index 1403a80d..42bcc4e9 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/package-info.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/map/package-info.java @@ -1,6 +1,7 @@ /** * Read/Write adapters for map variable factory. - * @since 0.0.2 + * * @see io.holunda.camunda.bpm.data.factory.MapVariableFactory for more details + * @since 0.0.2 */ package io.holunda.camunda.bpm.data.adapter.map; diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/package-info.java similarity index 98% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/package-info.java index 7a10d20a..f4a6bb30 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/package-info.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/package-info.java @@ -1,7 +1,8 @@ /** * Read and Write adapters for different factories to handle different contexts. - * @since 0.0.2 + * * @see io.holunda.camunda.bpm.data.adapter.ReadAdapter * @see io.holunda.camunda.bpm.data.adapter.WriteAdapter + * @since 0.0.2 */ package io.holunda.camunda.bpm.data.adapter; diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.java similarity index 97% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.java index ade698af..5dee4b39 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.java @@ -47,7 +47,7 @@ protected Set getOrNull(Object value) { if (Set.class.isAssignableFrom(value.getClass())) { Set valueAsList = (Set) value; if (valueAsList.isEmpty()) { - return Collections.emptySet(); + return Collections.emptySet(); } else { if (memberClazz.isAssignableFrom(valueAsList.iterator().next().getClass())) { return (Set) valueAsList; diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterRuntimeService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterRuntimeService.java new file mode 100644 index 00000000..b09ea4e3 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterRuntimeService.java @@ -0,0 +1,62 @@ +package io.holunda.camunda.bpm.data.adapter.set; + +import org.camunda.bpm.engine.RuntimeService; + +import java.util.Optional; +import java.util.Set; + +/** + * Read write adapter for runtime service access. + * + * @param type of value. + */ +public class SetReadWriteAdapterRuntimeService extends AbstractSetReadWriteAdapter { + + private final RuntimeService runtimeService; + private final String executionId; + + /** + * Constructs the adapter. + * + * @param runtimeService runtime service to use. + * @param executionId id of the execution to read from and write to. + * @param variableName name of the variable. + * @param memberClazz class of the variable. + */ + public SetReadWriteAdapterRuntimeService(RuntimeService runtimeService, String executionId, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.runtimeService = runtimeService; + this.executionId = executionId; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); + } + + @Override + public void set(Set value, boolean isTransient) { + runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); + } + + @Override + public void setLocal(Set value, boolean isTransient) { + runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + runtimeService.removeVariable(executionId, variableName); + } + + @Override + public void removeLocal() { + runtimeService.removeVariableLocal(executionId, variableName); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterTaskService.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterTaskService.java new file mode 100644 index 00000000..462e812c --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterTaskService.java @@ -0,0 +1,62 @@ +package io.holunda.camunda.bpm.data.adapter.set; + +import org.camunda.bpm.engine.TaskService; + +import java.util.Optional; +import java.util.Set; + +/** + * Read write adapter for task service access. + * + * @param type of value. + */ +public class SetReadWriteAdapterTaskService extends AbstractSetReadWriteAdapter { + + private final TaskService taskService; + private final String taskId; + + /** + * Constructs the adapter. + * + * @param taskService task service to use. + * @param taskId id of the task to read from and write to. + * @param variableName name of the variable. + * @param memberClazz class of the variable. + */ + public SetReadWriteAdapterTaskService(TaskService taskService, String taskId, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.taskService = taskService; + this.taskId = taskId; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); + } + + @Override + public void set(Set value, boolean isTransient) { + taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); + } + + @Override + public void setLocal(Set value, boolean isTransient) { + taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + taskService.removeVariable(taskId, variableName); + } + + @Override + public void removeLocal() { + taskService.removeVariableLocal(taskId, variableName); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableMap.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableMap.java new file mode 100644 index 00000000..8deb4266 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableMap.java @@ -0,0 +1,59 @@ +package io.holunda.camunda.bpm.data.adapter.set; + +import org.camunda.bpm.engine.variable.VariableMap; + +import java.util.Optional; +import java.util.Set; + +/** + * Read-write adapter for variable map. + * + * @param type of value. + */ +public class SetReadWriteAdapterVariableMap extends AbstractSetReadWriteAdapter { + + private final VariableMap variableMap; + + /** + * Constructs the adapter. + * + * @param variableMap variable map to access. + * @param variableName variable to access. + * @param memberClazz class of variable value. + */ + public SetReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.variableMap = variableMap; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(variableMap.get(variableName))); + } + + @Override + public void set(Set value, boolean isTransient) { + variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + throw new UnsupportedOperationException("Can't get a local variable on a variable map"); + } + + @Override + public void setLocal(Set value, boolean isTransient) { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } + + @Override + public void remove() { + variableMap.remove(variableName); + } + + @Override + public void removeLocal() { + throw new UnsupportedOperationException("Can't set a local variable on a variable map"); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableScope.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableScope.java new file mode 100644 index 00000000..f86ec650 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableScope.java @@ -0,0 +1,59 @@ +package io.holunda.camunda.bpm.data.adapter.set; + +import org.camunda.bpm.engine.delegate.VariableScope; + +import java.util.Optional; +import java.util.Set; + +/** + * Read-write adapter for variable scope. + * + * @param type of value. + */ +public class SetReadWriteAdapterVariableScope extends AbstractSetReadWriteAdapter { + + private final VariableScope variableScope; + + /** + * Constructs the adapter. + * + * @param variableScope variable scope to access. + * @param variableName variable to access. + * @param memberClazz class of member variable value. + */ + public SetReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class memberClazz) { + super(variableName, memberClazz); + this.variableScope = variableScope; + } + + @Override + public Optional> getOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); + } + + @Override + public void set(Set value, boolean isTransient) { + variableScope.setVariable(variableName, getTypedValue(value, isTransient)); + } + + @Override + public Optional> getLocalOptional() { + return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); + } + + @Override + public void setLocal(Set value, boolean isTransient) { + variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); + } + + @Override + public void remove() { + variableScope.removeVariable(variableName); + } + + @Override + public void removeLocal() { + variableScope.removeVariableLocal(variableName); + } + +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/package-info.java similarity index 98% rename from extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/package-info.java index 1bc5e4ca..86da78a3 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/package-info.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/adapter/set/package-info.java @@ -1,6 +1,7 @@ /** * Read/Write adapters for set variable factory. - * @since 0.0.2 + * * @see io.holunda.camunda.bpm.data.factory.SetVariableFactory for more details + * @since 0.0.2 */ package io.holunda.camunda.bpm.data.adapter.set; diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilder.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilder.java new file mode 100644 index 00000000..25af90b4 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilder.java @@ -0,0 +1,60 @@ +package io.holunda.camunda.bpm.data.builder; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import io.holunda.camunda.bpm.data.writer.VariableMapWriter; +import java.util.Collections; +import org.camunda.bpm.engine.variable.VariableMap; +import org.camunda.bpm.engine.variable.Variables; +import org.jetbrains.annotations.NotNull; + +/** + * Builder to create {@link VariableMap} using {@link VariableFactory}. + */ +public class VariableMapBuilder { + + private final VariableMapWriter writer; + + /** + * Constructs a builder. + */ + public VariableMapBuilder() { + this.writer = new VariableMapWriter(Variables.createVariables()); + } + + /** + * Sets the value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param value the value + * @param type of value + * @return current builder instance + */ + @NotNull + public VariableMapBuilder set(VariableFactory variableFactory, T value) { + writer.set(variableFactory, value); + return this; + } + + /** + * Sets the (transient) value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param value the value + * @param isTransient if true, the variable is transient, default false. + * @param type of value + * @return current builder instance + */ + @NotNull + public VariableMapBuilder set(VariableFactory variableFactory, T value, boolean isTransient) { + writer.set(variableFactory, value, isTransient); + return this; + } + + /** + * @return instance of {@link VariableMap} containing set values + */ + @NotNull + public VariableMap build() { + return Variables.fromMap(Collections.unmodifiableMap(writer.variables())); + } +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/builder/package-info.java similarity index 62% rename from extension/src/main/java/io/holunda/camunda/bpm/data/builder/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/builder/package-info.java index 9bcc09c2..dbc0b924 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/package-info.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/builder/package-info.java @@ -1,7 +1,7 @@ /** - * Builder are used to define interact with multiple variables in the same context. + * Writers are used to create multiple variables inside a variable map. * - * @since 0.0.5 * @see io.holunda.camunda.bpm.data.CamundaBpmData#builder() methods. + * @since 0.0.5 */ package io.holunda.camunda.bpm.data.builder; diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/BasicVariableFactory.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/BasicVariableFactory.java similarity index 95% rename from extension/src/main/java/io/holunda/camunda/bpm/data/factory/BasicVariableFactory.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/BasicVariableFactory.java index 6354bf64..e72ac8ad 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/BasicVariableFactory.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/BasicVariableFactory.java @@ -126,7 +126,16 @@ public Class getVariableClass() { clazz.equals(that.clazz); } - @Override public int hashCode() { + @Override + public int hashCode() { return Objects.hash(name, clazz); } + + @Override + public String toString() { + return "BasicVariableFactory{" + + "name='" + name + '\'' + + ", clazz=" + clazz + + '}'; + } } diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/ListVariableFactory.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/ListVariableFactory.java similarity index 94% rename from extension/src/main/java/io/holunda/camunda/bpm/data/factory/ListVariableFactory.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/ListVariableFactory.java index a035efab..4943ee85 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/ListVariableFactory.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/ListVariableFactory.java @@ -97,4 +97,12 @@ public Class getMemberClass() { @Override public int hashCode() { return Objects.hash(name, memberClazz); } + + @Override + public String toString() { + return "ListVariableFactory{" + + "name='" + name + '\'' + + ", memberClazz=" + memberClazz + + '}'; + } } diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/MapVariableFactory.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/MapVariableFactory.java similarity index 94% rename from extension/src/main/java/io/holunda/camunda/bpm/data/factory/MapVariableFactory.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/MapVariableFactory.java index df099075..a9a53977 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/MapVariableFactory.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/MapVariableFactory.java @@ -118,4 +118,13 @@ public Class getValueClass() { @Override public int hashCode() { return Objects.hash(name, keyClazz, valueClazz); } + + @Override + public String toString() { + return "MapVariableFactory{" + + "name='" + name + '\'' + + ", keyClazz=" + keyClazz + + ", valueClazz=" + valueClazz + + '}'; + } } diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/RuntimeServiceAdapterBuilder.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/RuntimeServiceAdapterBuilder.java new file mode 100644 index 00000000..62a123e7 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/RuntimeServiceAdapterBuilder.java @@ -0,0 +1,51 @@ +package io.holunda.camunda.bpm.data.factory; + + +import io.holunda.camunda.bpm.data.adapter.ReadAdapter; +import io.holunda.camunda.bpm.data.adapter.WriteAdapter; +import io.holunda.camunda.bpm.data.adapter.basic.ReadWriteAdapterRuntimeService; +import org.camunda.bpm.engine.RuntimeService; + +/** + * Creates a builder to encapsulate the runtime service access. + * + * @param type of builder. + */ +public class RuntimeServiceAdapterBuilder { + + private final RuntimeService runtimeService; + private final BasicVariableFactory basicVariableFactory; + + /** + * Constructs the builder. + * + * @param basicVariableFactory variable factory to use. + * @param runtimeService task service to build adapter with. + */ + public RuntimeServiceAdapterBuilder(BasicVariableFactory basicVariableFactory, RuntimeService runtimeService) { + this.runtimeService = runtimeService; + this.basicVariableFactory = basicVariableFactory; + } + + /** + * Creates a write adapter on execution. + * + * @param executionId id identifying execution. + * + * @return write adapter + */ + public WriteAdapter on(String executionId) { + return new ReadWriteAdapterRuntimeService<>(runtimeService, executionId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); + } + + /** + * Creates a read adapter on execution. + * + * @param executionId id identifying execution. + * + * @return read adapter. + */ + public ReadAdapter from(String executionId) { + return new ReadWriteAdapterRuntimeService<>(runtimeService, executionId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); + } +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/SetVariableFactory.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/SetVariableFactory.java similarity index 94% rename from extension/src/main/java/io/holunda/camunda/bpm/data/factory/SetVariableFactory.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/SetVariableFactory.java index 12ebbee7..0068548f 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/SetVariableFactory.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/SetVariableFactory.java @@ -97,4 +97,12 @@ public Class getMemberClass() { @Override public int hashCode() { return Objects.hash(name, memberClazz); } + + @Override + public String toString() { + return "SetVariableFactory{" + + "name='" + name + '\'' + + ", memberClazz=" + memberClazz + + '}'; + } } diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/TaskServiceAdapterBuilder.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/TaskServiceAdapterBuilder.java new file mode 100644 index 00000000..9037ff77 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/TaskServiceAdapterBuilder.java @@ -0,0 +1,51 @@ +package io.holunda.camunda.bpm.data.factory; + +import io.holunda.camunda.bpm.data.adapter.ReadAdapter; +import io.holunda.camunda.bpm.data.adapter.WriteAdapter; +import io.holunda.camunda.bpm.data.adapter.basic.ReadWriteAdapterTaskService; +import org.camunda.bpm.engine.TaskService; + +/** + * Creates a builder to encapsulate the task service access. + * + * @param type of builder. + */ +public class TaskServiceAdapterBuilder { + + private final TaskService taskService; + private final BasicVariableFactory basicVariableFactory; + + /** + * Constructs the builder. + * + * @param basicVariableFactory variable factory to use. + * @param taskService task service to build adapter with. + */ + public TaskServiceAdapterBuilder(BasicVariableFactory basicVariableFactory, TaskService taskService) { + this.taskService = taskService; + this.basicVariableFactory = basicVariableFactory; + } + + /** + * Creates a write adapter on task. + * + * @param taskId id identifying task. + * + * @return write adapter + */ + public WriteAdapter on(String taskId) { + return new ReadWriteAdapterTaskService<>(taskService, taskId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); + } + + /** + * Creates a read adapter on task. + * + * @param taskId id identifying task. + * + * @return read adapter. + */ + public ReadAdapter from(String taskId) { + return new ReadWriteAdapterTaskService<>(taskService, taskId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/VariableFactory.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/VariableFactory.java new file mode 100644 index 00000000..eb8a9642 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/VariableFactory.java @@ -0,0 +1,98 @@ +package io.holunda.camunda.bpm.data.factory; + +import io.holunda.camunda.bpm.data.adapter.ReadAdapter; +import io.holunda.camunda.bpm.data.adapter.WriteAdapter; +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.TaskService; +import org.camunda.bpm.engine.delegate.VariableScope; +import org.camunda.bpm.engine.variable.VariableMap; + +/** + * Typed variable factory. + * + * @param type of the factory. + */ +public interface VariableFactory { + /** + * Creates a write adapter for variable scope. + * + * @param variableScope underlying scope to work on. + * + * @return write adapter. + */ + WriteAdapter on(VariableScope variableScope); + + /** + * Creates a read adapter on variable scope. + * + * @param variableScope underlying scope to work on. + * + * @return read adapter. + */ + ReadAdapter from(VariableScope variableScope); + + /** + * Creates a write adapter for variable map. + * + * @param variableMap underlying scope to work on. + * + * @return write adapter. + */ + WriteAdapter on(VariableMap variableMap); + + /** + * Creates a read adapter on variable scope. + * + * @param variableMap underlying map to work on. + * + * @return read adapter. + */ + ReadAdapter from(VariableMap variableMap); + + /** + * Creates a write adapter on execution. + * + * @param runtimeService underlying runtime service to work on. + * @param executionId id identifying execution. + * + * @return write adapter + */ + WriteAdapter on(RuntimeService runtimeService, String executionId); + + /** + * Creates a read adapter on execution. + * + * @param runtimeService underlying runtime service to work on. + * @param executionId id identifying execution. + * + * @return read adapter. + */ + ReadAdapter from(RuntimeService runtimeService, String executionId); + + /** + * Creates a write adapter on task. + * + * @param taskService underlying runtime service to work on. + * @param taskId id identifying task. + * + * @return write adapter + */ + WriteAdapter on(TaskService taskService, String taskId); + + /** + * Creates a read adapter on task. + * + * @param taskService underlying runtime service to work on. + * @param taskId id identifying task. + * + * @return read adapter. + */ + ReadAdapter from(TaskService taskService, String taskId); + + /** + * Retrieves the variable name. + * + * @return name of the variable. + */ + String getName(); +} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/package-info.java similarity index 100% rename from extension/src/main/java/io/holunda/camunda/bpm/data/factory/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/package-info.java index dcc4549b..1d505dbe 100644 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/package-info.java +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/factory/package-info.java @@ -1,7 +1,7 @@ /** * Process Variable Factories are used to define process variables. * - * @since 0.0.2 * @see io.holunda.camunda.bpm.data.factory.VariableFactory as the main starting point. + * @since 0.0.2 */ package io.holunda.camunda.bpm.data.factory; diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/package-info.java similarity index 100% rename from extension/src/main/java/io/holunda/camunda/bpm/data/package-info.java rename to extension/core/src/main/java/io/holunda/camunda/bpm/data/package-info.java diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/RuntimeServiceVariableReader.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/RuntimeServiceVariableReader.java new file mode 100644 index 00000000..14345e11 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/RuntimeServiceVariableReader.java @@ -0,0 +1,49 @@ +package io.holunda.camunda.bpm.data.reader; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.Optional; +import org.camunda.bpm.engine.RuntimeService; +import org.jetbrains.annotations.NotNull; + +/** + * Allows reading multiple variable values from {@link RuntimeService#getVariable(String, String)}. + */ +public class RuntimeServiceVariableReader implements VariableReader { + + private final RuntimeService runtimeService; + private final String executionId; + + /** + * Constructs a reader operating on execution. + * @param runtimeService runtime service to use. + * @param executionId execution id. + */ + public RuntimeServiceVariableReader(RuntimeService runtimeService, String executionId) { + this.runtimeService = runtimeService; + this.executionId = executionId; + } + + @NotNull + @Override + public Optional getOptional(VariableFactory variableFactory) { + return variableFactory.from(runtimeService, executionId).getOptional(); + } + + @NotNull + @Override + public T get(VariableFactory variableFactory) { + return variableFactory.from(runtimeService, executionId).get(); + } + + @NotNull + @Override + public T getLocal(VariableFactory variableFactory) { + return variableFactory.from(runtimeService, executionId).getLocal(); + } + + @NotNull + @Override + public Optional getLocalOptional(VariableFactory variableFactory) { + return variableFactory.from(runtimeService, executionId).getLocalOptional(); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/TaskServiceVariableReader.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/TaskServiceVariableReader.java new file mode 100644 index 00000000..7e4b2e87 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/TaskServiceVariableReader.java @@ -0,0 +1,50 @@ +package io.holunda.camunda.bpm.data.reader; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.Optional; +import org.camunda.bpm.engine.TaskService; +import org.jetbrains.annotations.NotNull; + +/** + * Allows reading multiple variable values from {@link TaskService#getVariable(String, String)}. + */ +public class TaskServiceVariableReader implements VariableReader { + + private final TaskService taskService; + private final String taskId; + + /** + * Constructs a reader operating on task service. + * @param taskService task service to operate on. + * @param taskId task id. + */ + public TaskServiceVariableReader(TaskService taskService, String taskId) { + this.taskService = taskService; + this.taskId = taskId; + } + + + @NotNull + @Override + public Optional getOptional(VariableFactory variableFactory) { + return variableFactory.from(taskService, taskId).getOptional(); + } + + @NotNull + @Override + public T get(VariableFactory variableFactory) { + return variableFactory.from(taskService, taskId).get(); + } + + @NotNull + @Override + public T getLocal(VariableFactory variableFactory) { + return variableFactory.from(taskService, taskId).getLocal(); + } + + @NotNull + @Override + public Optional getLocalOptional(VariableFactory variableFactory) { + return variableFactory.from(taskService, taskId).getLocalOptional(); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableMapReader.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableMapReader.java new file mode 100644 index 00000000..584f8c01 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableMapReader.java @@ -0,0 +1,41 @@ +package io.holunda.camunda.bpm.data.reader; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.Optional; +import org.camunda.bpm.engine.variable.VariableMap; + +/** + * Allows reading multiple variable values from {@link VariableMap#getValue(String, Class)}. + */ +public class VariableMapReader implements VariableReader { + + private final VariableMap variableMap; + + /** + * Constructs the reader using the specified variable map. + * @param variableMap map to operate on. + */ + public VariableMapReader(VariableMap variableMap) { + this.variableMap = variableMap; + } + + @Override + public Optional getOptional(VariableFactory variableFactory) { + return variableFactory.from(variableMap).getOptional(); + } + + @Override + public T get(VariableFactory variableFactory) { + return variableFactory.from(variableMap).get(); + } + + @Override + public T getLocal(VariableFactory variableFactory) { + return variableFactory.from(variableMap).getLocal(); + } + + @Override + public Optional getLocalOptional(VariableFactory variableFactory) { + return variableFactory.from(variableMap).getLocalOptional(); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableReader.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableReader.java new file mode 100644 index 00000000..261f850b --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableReader.java @@ -0,0 +1,56 @@ +package io.holunda.camunda.bpm.data.reader; + +import io.holunda.camunda.bpm.data.adapter.ReadAdapter; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +/** + * Inverting calls to {@link io.holunda.camunda.bpm.data.adapter.ReadAdapter}. + */ +public interface VariableReader { + + /** + * Uses {@link ReadAdapter#getOptional()} to access variable value. + * + * @param variableFactory the variable to read + * @param type of value + * @return value of variable or empty() + */ + @NotNull + Optional getOptional(VariableFactory variableFactory); + + /** + * Uses {@link ReadAdapter#get()} to access variable value. + * + * @param variableFactory the variable to read + * @param type of value + * @return value of variable + * @throws IllegalStateException if variable is not set + */ + @NotNull + T get(VariableFactory variableFactory); + + /** + * Uses {@link ReadAdapter#getLocal()} to access variable value. + * + * @param variableFactory the variable to read + * @param type of value + * @return value of variable + * @throws IllegalStateException if variable is not set + */ + @NotNull + T getLocal(VariableFactory variableFactory); + + /** + * Uses {@link ReadAdapter#getLocalOptional()} ()} to access variable value. + * + * @param variableFactory the variable to read + * @param type of value + * @return value of variable or empty() + */ + @NotNull + Optional getLocalOptional(VariableFactory variableFactory); + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableScopeReader.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableScopeReader.java new file mode 100644 index 00000000..4e00a3c7 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/VariableScopeReader.java @@ -0,0 +1,46 @@ +package io.holunda.camunda.bpm.data.reader; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.Optional; +import org.camunda.bpm.engine.delegate.VariableScope; +import org.jetbrains.annotations.NotNull; + +/** + * Allows reading multiple variable values from {@link VariableScope} (such as {@link org.camunda.bpm.engine.delegate.DelegateExecution} and {@link org.camunda.bpm.engine.delegate.DelegateTask}). + */ +public class VariableScopeReader implements VariableReader{ + + private final VariableScope variableScope; + + /** + * Constructs a reader operating on variable scope (e.g. DelegateExecution or DelegateTask). + * @param variableScope scope to operate on. + */ + public VariableScopeReader(VariableScope variableScope) { + this.variableScope = variableScope; + } + + @Override + @NotNull + public Optional getOptional(VariableFactory variableFactory) { + return variableFactory.from(variableScope).getOptional(); + } + + @Override + @NotNull + public T get(VariableFactory variableFactory) { + return variableFactory.from(variableScope).get(); + } + + @Override + @NotNull + public T getLocal(VariableFactory variableFactory) { + return variableFactory.from(variableScope).getLocal(); + } + + @Override + @NotNull + public Optional getLocalOptional(VariableFactory variableFactory) { + return variableFactory.from(variableScope).getLocalOptional(); + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/package-info.java new file mode 100644 index 00000000..b13f67f6 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/reader/package-info.java @@ -0,0 +1,7 @@ +/** + * Readers are used to interact with multiple variables in the same context. + * + * @see io.holunda.camunda.bpm.data.CamundaBpmData#reader() methods. + * @since 1.0.0 + */ +package io.holunda.camunda.bpm.data.reader; diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/LocalVariableWriter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/LocalVariableWriter.java new file mode 100644 index 00000000..e08b28ed --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/LocalVariableWriter.java @@ -0,0 +1,55 @@ +package io.holunda.camunda.bpm.data.writer; + +import io.holunda.camunda.bpm.data.adapter.WriteAdapter; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.variable.VariableMap; +import org.jetbrains.annotations.NotNull; + +/** + * Inverting calls to {@link WriteAdapter}. + * + * @param type of concrete Writer for fluent usage. + */ +public interface LocalVariableWriter> extends VariableWriter { + + /** + * Sets the local value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param value the value + * @param type of value + * @return current writer instance + * @see WriteAdapter#setLocal(Object) + */ + S setLocal(VariableFactory variableFactory, T value); + + /** + * Sets the local (transient) value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param value the value + * @param isTransient if true, the variable is transient + * @param type of value + * @return current writer instance + * @see WriteAdapter#setLocal(Object, boolean) + */ + S setLocal(VariableFactory variableFactory, T value, boolean isTransient); + + /** + * Removes the local value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param type of value + * @return current writer instance + * @see WriteAdapter#removeLocal() + */ + S removeLocal(VariableFactory variableFactory); + + /** + * Returns the resulting local variables. + * + * @return local variables. + */ + @NotNull + VariableMap variablesLocal(); +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/RuntimeServiceVariableWriter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/RuntimeServiceVariableWriter.java new file mode 100644 index 00000000..26e7b13e --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/RuntimeServiceVariableWriter.java @@ -0,0 +1,75 @@ +package io.holunda.camunda.bpm.data.writer; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.variable.VariableMap; +import org.jetbrains.annotations.NotNull; + +/** + * Process execution builder allowing for fluent variable setting. + */ +public class RuntimeServiceVariableWriter implements LocalVariableWriter { + + private final RuntimeService runtimeService; + private final String executionId; + + /** + * Creates a writer working on process execution. + */ + public RuntimeServiceVariableWriter(RuntimeService runtimeService, String executionId) { + this.runtimeService = runtimeService; + this.executionId = executionId; + } + + @Override + @NotNull + public VariableMap variables() { + return this.runtimeService.getVariablesTyped(this.executionId); + } + + @Override + @NotNull + public VariableMap variablesLocal() { + return this.runtimeService.getVariablesLocalTyped(this.executionId); + } + + @Override + @NotNull + public RuntimeServiceVariableWriter set(VariableFactory factory, T value) { + return this.set(factory, value, false); + } + + @Override + @NotNull + public RuntimeServiceVariableWriter set(VariableFactory factory, T value, boolean isTransient) { + factory.on(this.runtimeService, this.executionId).set(value, isTransient); + return this; + } + + @Override + @NotNull + public RuntimeServiceVariableWriter setLocal(VariableFactory factory, T value) { + return this.setLocal(factory, value, false); + } + + @Override + @NotNull + public RuntimeServiceVariableWriter setLocal(VariableFactory factory, T value, boolean isTransient) { + factory.on(this.runtimeService, this.executionId).setLocal(value, isTransient); + return this; + } + + @Override + @NotNull + public RuntimeServiceVariableWriter remove(VariableFactory factory) { + factory.on(this.runtimeService, this.executionId).remove(); + return this; + } + + @Override + @NotNull + public RuntimeServiceVariableWriter removeLocal(VariableFactory factory) { + factory.on(this.runtimeService, this.executionId).removeLocal(); + return this; + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/TaskServiceVariableWriter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/TaskServiceVariableWriter.java new file mode 100644 index 00000000..1aebfe24 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/TaskServiceVariableWriter.java @@ -0,0 +1,76 @@ +package io.holunda.camunda.bpm.data.writer; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.TaskService; +import org.camunda.bpm.engine.variable.VariableMap; +import org.jetbrains.annotations.NotNull; + +/** + * User task builder allowing for fluent variable setting. + */ +public class TaskServiceVariableWriter implements LocalVariableWriter { + + private final TaskService taskService; + private final String taskId; + + /** + * Creates a builder working on a user task. + */ + public TaskServiceVariableWriter(TaskService taskService, String taskId) { + this.taskService = taskService; + this.taskId = taskId; + } + + @Override + @NotNull + public VariableMap variables() { + return this.taskService.getVariablesTyped(this.taskId); + } + + @Override + @NotNull + public VariableMap variablesLocal() { + return this.taskService.getVariablesLocalTyped(this.taskId); + } + + @Override + @NotNull + public TaskServiceVariableWriter set(VariableFactory factory, T value) { + return this.set(factory, value, false); + } + + @Override + @NotNull + public TaskServiceVariableWriter set(VariableFactory factory, T value, boolean isTransient) { + factory.on(this.taskService, this.taskId).set(value, isTransient); + return this; + } + + @Override + @NotNull + public TaskServiceVariableWriter setLocal(VariableFactory factory, T value) { + return this.setLocal(factory, value, false); + } + + @Override + @NotNull + public TaskServiceVariableWriter setLocal(VariableFactory factory, T value, boolean isTransient) { + factory.on(this.taskService, this.taskId).setLocal(value, isTransient); + return this; + } + + @Override + @NotNull + public TaskServiceVariableWriter remove(VariableFactory factory) { + factory.on(this.taskService, this.taskId).remove(); + return this; + } + + @Override + @NotNull + public TaskServiceVariableWriter removeLocal(VariableFactory factory) { + factory.on(this.taskService, this.taskId).removeLocal(); + return this; + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableMapWriter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableMapWriter.java new file mode 100644 index 00000000..1ae318eb --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableMapWriter.java @@ -0,0 +1,48 @@ +package io.holunda.camunda.bpm.data.writer; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.variable.VariableMap; +import org.jetbrains.annotations.NotNull; + +/** + * Variable map builder allowing for fluent variable setting. + */ +public class VariableMapWriter implements VariableWriter { + + private final VariableMap variables; + + /** + * Creates a builder with provided variable map. + * + * @param variables variables to work on. + */ + public VariableMapWriter(VariableMap variables) { + this.variables = variables; + } + + @Override + @NotNull + public VariableMapWriter set(VariableFactory factory, T value) { + return this.set(factory, value, false); + } + + @Override + @NotNull + public VariableMapWriter set(VariableFactory factory, T value, boolean isTransient) { + factory.on(this.variables).set(value, isTransient); + return this; + } + + @Override + @NotNull + public VariableMapWriter remove(VariableFactory factory) { + factory.on(this.variables).remove(); + return this; + } + + @Override + @NotNull + public VariableMap variables() { + return variables; + } +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableScopeWriter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableScopeWriter.java new file mode 100644 index 00000000..1e317f2d --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableScopeWriter.java @@ -0,0 +1,77 @@ +package io.holunda.camunda.bpm.data.writer; + +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.delegate.VariableScope; +import org.camunda.bpm.engine.variable.VariableMap; +import org.jetbrains.annotations.NotNull; + +/** + * Variable scope builder allowing for fluent variable setting. + */ +public class VariableScopeWriter implements LocalVariableWriter { + + private final VariableScope scope; + + /** + * Creates a builder with provided variable map. + *

The provided variables are modified by reference.

+ * + * @param variables variables to work on. + */ + public VariableScopeWriter(VariableScope variables) { + this.scope = variables; + } + + @Override + @NotNull + public VariableScopeWriter set(VariableFactory factory, T value) { + return this.set(factory, value, false); + } + + @Override + @NotNull + public VariableScopeWriter set(VariableFactory factory, T value, boolean isTransient) { + factory.on(this.scope).set(value, isTransient); + return this; + } + + @Override + @NotNull + public VariableScopeWriter setLocal(VariableFactory factory, T value) { + return this.setLocal(factory, value, false); + } + + @Override + @NotNull + public VariableScopeWriter setLocal(VariableFactory factory, T value, boolean isTransient) { + factory.on(this.scope).setLocal(value, isTransient); + return this; + } + + @Override + @NotNull + public VariableScopeWriter remove(VariableFactory factory) { + factory.on(this.scope).remove(); + return this; + } + + @Override + @NotNull + public VariableScopeWriter removeLocal(VariableFactory factory) { + factory.on(this.scope).removeLocal(); + return this; + } + + @Override + @NotNull + public VariableMap variables() { + return scope.getVariablesTyped(); + } + + @Override + @NotNull + public VariableMap variablesLocal() { + return scope.getVariablesLocalTyped(); + } + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableWriter.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableWriter.java new file mode 100644 index 00000000..9529956f --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/VariableWriter.java @@ -0,0 +1,59 @@ +package io.holunda.camunda.bpm.data.writer; + +import io.holunda.camunda.bpm.data.adapter.WriteAdapter; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.variable.VariableMap; +import org.jetbrains.annotations.NotNull; + +/** + * Inverting calls to {@link io.holunda.camunda.bpm.data.adapter.WriteAdapter}. + * + * @param type of concrete Writer for fluent usage. + */ +public interface VariableWriter> { + + /** + * Sets the value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param value the value + * @param type of value + * @return current writer instance + * @see io.holunda.camunda.bpm.data.adapter.WriteAdapter#set(Object) + */ + @NotNull + S set(VariableFactory variableFactory, T value); + + /** + * Sets the (transient) value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param value the value + * @param isTransient if true, the variable is transient, default false. + * @param type of value + * @return current writer instance + * @see io.holunda.camunda.bpm.data.adapter.WriteAdapter#set(Object, boolean) + */ + @NotNull + S set(VariableFactory variableFactory, T value, boolean isTransient); + + /** + * Removes the value for the provided variable and returns the builder (fluently). + * + * @param variableFactory the variable + * @param type of value + * @return current writer instance + * @see WriteAdapter#remove() + */ + @NotNull + S remove(VariableFactory variableFactory); + + /** + * Returns the resulting variables. + * + * @return variables. + */ + @NotNull + VariableMap variables(); + +} diff --git a/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/package-info.java b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/package-info.java new file mode 100644 index 00000000..72ddbee5 --- /dev/null +++ b/extension/core/src/main/java/io/holunda/camunda/bpm/data/writer/package-info.java @@ -0,0 +1,7 @@ +/** + * Writers are used to interact with multiple variables in the same context. + * + * @see io.holunda.camunda.bpm.data.CamundaBpmData#writer() methods. + * @since 0.0.5 + */ +package io.holunda.camunda.bpm.data.writer; diff --git a/extension/core/src/main/kotlin/CamundaBpmDataKotlin.kt b/extension/core/src/main/kotlin/CamundaBpmDataKotlin.kt new file mode 100644 index 00000000..07542cbb --- /dev/null +++ b/extension/core/src/main/kotlin/CamundaBpmDataKotlin.kt @@ -0,0 +1,108 @@ +package io.holunda.camunda.bpm.data + +import io.holunda.camunda.bpm.data.factory.* +import java.util.* + +/** + * Provides reified methods for variable factory construction. + */ +object CamundaBpmDataKotlin { + + /** + * Creates a string variable factory. + * + * @param variableName name of the variable. + * + * @return variable factory for string. + */ + fun stringVariable(variableName: String): VariableFactory = BasicVariableFactory(variableName, String::class.java) + + /** + * Creates a date variable factory. + * + * @param variableName name of the variable. + * + * @return variable factory for date. + */ + fun dateVariable(variableName: String): VariableFactory = BasicVariableFactory(variableName, Date::class.java) + + /** + * Creates an integer variable factory. + * + * @param variableName name of the variable. + * + * @return variable factory for integer. + */ + fun intVariable(variableName: String): VariableFactory = BasicVariableFactory(variableName, Int::class.java) + + /** + * Creates a long variable factory. + * + * @param variableName name of the variable. + * + * @return variable factory for long. + */ + fun longVariable(variableName: String): VariableFactory = BasicVariableFactory(variableName, Long::class.java) + + /** + * Creates a short variable factory. + * + * @param variableName name of the variable. + * + * @return variable factory for short. + */ + fun shortVariable(variableName: String): VariableFactory = BasicVariableFactory(variableName, Short::class.java) + + /** + * Creates a double variable factory. + * + * @param variableName name of the variable. + * + * @return variable factory for double. + */ + fun doubleVariable(variableName: String): VariableFactory = BasicVariableFactory(variableName, Double::class.java) + + /** + * Creates a boolean variable factory. + * + * @param variableName name of the variable. + * + * @return variable factory for boolean. + */ + fun booleanVariable(variableName: String): VariableFactory = BasicVariableFactory(variableName, Boolean::class.java) + + /** + * Reified version of the basic variable factory. + * @param name The name of the variable. + * @param T The type of the variable. + * @return instance of [VariableFactory] + */ + inline fun customVariable(name: String): VariableFactory = BasicVariableFactory(name, T::class.java) + + /** + * Reified version of list variable factory. + * @param name The name of the variable. + * @param T The type of the variable. + * @return instance of [VariableFactory] + */ + inline fun listVariable(name: String): VariableFactory> = ListVariableFactory(name, T::class.java) + + /** + * Reified version of set variable factory. + * @param name The name of the variable. + * @param T The type of the variable. + * @param wrap a boolean flag controlling if the serializer should wrap a list into a wrapper object. Set this flag to true, if you use complex types as T. + * @return instance of [VariableFactory] + */ + inline fun setVariable(name: String): VariableFactory> = SetVariableFactory(name, T::class.java) + + /** + * Reified version of map variable factory. + * @param name The name of the variable. + * @param K The type of the variable key. + * @param V The type of the variable value. + * @return instance of [VariableFactory] + */ + inline fun mapVariable(name: String): VariableFactory> = MapVariableFactory(name, K::class.java, V::class.java) + +} diff --git a/extension-kotlin/src/main/kotlin/VariableFactoryFluentApi.kt b/extension/core/src/main/kotlin/VariableFactoryFluentApi.kt similarity index 77% rename from extension-kotlin/src/main/kotlin/VariableFactoryFluentApi.kt rename to extension/core/src/main/kotlin/VariableFactoryFluentApi.kt index 552af011..ab087492 100644 --- a/extension-kotlin/src/main/kotlin/VariableFactoryFluentApi.kt +++ b/extension/core/src/main/kotlin/VariableFactoryFluentApi.kt @@ -1,8 +1,10 @@ package io.holunda.camunda.bpm.data -import io.holunda.camunda.bpm.data.builder.ProcessExecutionVariableBuilder -import io.holunda.camunda.bpm.data.builder.UserTaskVariableBuilder +import io.holunda.camunda.bpm.data.writer.RuntimeServiceVariableWriter +import io.holunda.camunda.bpm.data.writer.TaskServiceVariableWriter import io.holunda.camunda.bpm.data.factory.VariableFactory +import io.holunda.camunda.bpm.data.reader.RuntimeServiceVariableReader +import io.holunda.camunda.bpm.data.reader.TaskServiceVariableReader import org.camunda.bpm.engine.RuntimeService import org.camunda.bpm.engine.TaskService import org.camunda.bpm.engine.delegate.VariableScope @@ -94,13 +96,25 @@ fun VariableScope.updateLocal(factory: VariableFactory, valueProcessor: ( } /** - * Helper to access runtime service builder. + * Helper to access runtime service writer. * @param executionId id of the execution. */ -fun RuntimeService.builder(executionId: String) = ProcessExecutionVariableBuilder(this, executionId) +fun RuntimeService.writer(executionId: String) = RuntimeServiceVariableWriter(this, executionId) /** - * Helper to access task service builder. + * Helper to access task service writer. * @param taskId id of the task. */ -fun TaskService.builder(taskId: String) = UserTaskVariableBuilder(this, taskId) +fun TaskService.writer(taskId: String) = TaskServiceVariableWriter(this, taskId) + +/** + * Helper to access runtime service reader. + * @param executionId id of the execution. + */ +fun RuntimeService.reader(executionId: String) = RuntimeServiceVariableReader(this, executionId) + +/** + * Helper to access task service reader. + * @param taskId id of the task. + */ +fun TaskService.reader(taskId: String) = TaskServiceVariableReader(this, taskId) diff --git a/extension/core/src/main/kotlin/acl/AntiCorruptionLayer.kt b/extension/core/src/main/kotlin/acl/AntiCorruptionLayer.kt new file mode 100644 index 00000000..cb87a576 --- /dev/null +++ b/extension/core/src/main/kotlin/acl/AntiCorruptionLayer.kt @@ -0,0 +1,104 @@ +package io.holunda.camunda.bpm.data.acl + +import io.holunda.camunda.bpm.data.acl.assign.ValueApplicationStrategy +import io.holunda.camunda.bpm.data.acl.transform.VariableMapTransformer +import io.holunda.camunda.bpm.data.factory.VariableFactory +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import io.holunda.camunda.bpm.data.guard.integration.GuardViolationException +import org.camunda.bpm.engine.delegate.ExecutionListener +import org.camunda.bpm.engine.delegate.TaskListener +import org.camunda.bpm.engine.variable.VariableMap +import org.camunda.bpm.engine.variable.Variables + +/** + * Defines the ACL (Anti-Corruption-Layer). + *

+ * An ACL consists of a variables guard and a mapping function, which is applied, if the condition is matched. + * A typical application of an ACL is the protection of external access to the process (signal, message correlation). + * To do so, signal / correlate with transient variables only and those got pumped into the execution if the guard is satisfied. + *

+ */ +class AntiCorruptionLayer( + /** + * Precondition to be fulfilled to pass the ACL. + */ + val precondition: VariablesGuard, + /** + * Mapping to be applied. + */ + val variableMapTransformer: VariableMapTransformer, + /** + * Factory to use. + */ + internal val factory: VariableFactory, + /** + * Strategy to apply values from transformer to given variable scope. + */ + internal val valueApplicationStrategy: ValueApplicationStrategy +) { + + companion object { + const val DEFAULT = "_transient" + + /** + * Helper to create a Map containing transient variables hidden in the given map under the given key. + * + * @param variableName the variable name to use for the additional variables + * @param variables the variables to store + * + * @return a newly created map containing the given variables as transient objectTypedValue. + */ + fun wrapAsTypedTransientVariable(variableName: String, variables: VariableMap): VariableMap { + return Variables.createVariables() + .putValueTyped(variableName, Variables + .objectValue(variables, true) + .serializationDataFormat(Variables.SerializationDataFormats.JAVA) + .create() + ) + } + } + + /** + * Retrieves the ACL in form of an execution listener. + */ + fun getExecutionListener() = ExecutionListener { execution -> + val variablesExternal = factory.from(execution).get() + if (precondition.evaluate(variablesExternal).isEmpty()) { + val variableInternal = variableMapTransformer.transform(variablesExternal) + valueApplicationStrategy.apply(variableInternal, execution) + } + } + + /** + * Retrieves the ACL in form of a task listener. + */ + fun getTaskListener() = TaskListener { task -> + val variablesExternal = factory.from(task).get() + if (precondition.evaluate(variablesExternal).isEmpty()) { + val variableInternal = variableMapTransformer.transform(variablesExternal) + valueApplicationStrategy.apply(variableInternal, task) + } + } + + /** + * Checks if the preconditions are satisfied and constructs a variable map wrapping the variables. + * @param variableMap variable map containing the variables. + * @return new variables + */ + fun checkAndWrap(variableMap: VariableMap): VariableMap { + val violations = precondition.evaluate(variableMap) + if (violations.isNotEmpty()) { + throw GuardViolationException(violations = violations, reason = "ACL Guard Error:") + } + return wrap(variableMap) + } + + /** + * Constructs a variable map wrapping the variables. + * @param variableMap variable map containing the variables. + * @return new variables + */ + fun wrap(variableMap: VariableMap): VariableMap { + return wrapAsTypedTransientVariable(variableName = factory.name, variables = variableMap) + } +} \ No newline at end of file diff --git a/extension/core/src/main/kotlin/acl/CamundaBpmDataACL.kt b/extension/core/src/main/kotlin/acl/CamundaBpmDataACL.kt new file mode 100644 index 00000000..979046aa --- /dev/null +++ b/extension/core/src/main/kotlin/acl/CamundaBpmDataACL.kt @@ -0,0 +1,57 @@ +package io.holunda.camunda.bpm.data.acl + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.acl.apply.GlobalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.apply.LocalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.transform.VariableMapTransformer +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Helper methods to create anti corruption layers. + */ +object CamundaBpmDataACL { + + /** + * Constructs an ACL with a guard, maps variables using transformer and replaces them in a local scope. + * @param variableName name of the transient variable to use. + * @param variableMapTransformer transformer to map from external to internal representation. + * @param variablesGuard preconditions protecting the ACL. + */ + @JvmStatic + fun guardTransformingLocalReplace(variableName: String, variablesGuard: VariablesGuard, variableMapTransformer: VariableMapTransformer) = AntiCorruptionLayer( + precondition = variablesGuard, + variableMapTransformer = variableMapTransformer, + factory = CamundaBpmData.customVariable(variableName, VariableMap::class.java), + valueApplicationStrategy = LocalScopeReplaceStrategy + ) + + /** + * Constructs an ACL with a guard, maps variables using transformer and replaces them in a global scope. + * @param variableName name of the transient variable to use. + * @param variableMapTransformer transformer to map from external to internal representation. + * @param variablesGuard preconditions protecting the ACL. + */ + @JvmStatic + fun guardTransformingGlobalReplace(variableName: String, variablesGuard: VariablesGuard, variableMapTransformer: VariableMapTransformer) = AntiCorruptionLayer( + precondition = variablesGuard, + variableMapTransformer = variableMapTransformer, + factory = CamundaBpmData.customVariable(variableName, VariableMap::class.java), + valueApplicationStrategy = GlobalScopeReplaceStrategy + ) + + /** + * Constructs an ACL with a guard, maps variables using transformer and replaces them in a scope controlled by the . + * @param variableName name of the transient variable to use. + * @param local flag to control the scope. + * @param variableMapTransformer transformer to map from external to internal representation. + * @param variablesGuard preconditions protecting the ACL. + */ + @JvmStatic + fun guardTransformingReplace(variableName: String, local: Boolean, variablesGuard: VariablesGuard, variableMapTransformer: VariableMapTransformer) = if (local) { + guardTransformingLocalReplace(variableName, variablesGuard, variableMapTransformer) + } else { + guardTransformingGlobalReplace(variableName, variablesGuard, variableMapTransformer) + } + +} \ No newline at end of file diff --git a/extension/core/src/main/kotlin/acl/CamundaBpmDataMapper.kt b/extension/core/src/main/kotlin/acl/CamundaBpmDataMapper.kt new file mode 100644 index 00000000..c1587969 --- /dev/null +++ b/extension/core/src/main/kotlin/acl/CamundaBpmDataMapper.kt @@ -0,0 +1,90 @@ +package io.holunda.camunda.bpm.data.acl + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.acl.apply.GlobalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.apply.LocalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.transform.IdentityVariableMapTransformer +import io.holunda.camunda.bpm.data.acl.transform.VariableMapTransformer +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Helper methods to create unconditional transient variable mappers. + */ +object CamundaBpmDataMapper { + /** + * Constructs a mapper, maps variables using transformer and replaces them in a local scope. + * @param variableName name of the transient variable to use. + * @param variableMapTransformer transformer to map from external to internal representation. + */ + @JvmStatic + fun transformingLocalReplace(variableName: String, variableMapTransformer: VariableMapTransformer) = AntiCorruptionLayer( + precondition = VariablesGuard.EMPTY, + variableMapTransformer = variableMapTransformer, + factory = CamundaBpmData.customVariable(variableName, VariableMap::class.java), + valueApplicationStrategy = LocalScopeReplaceStrategy + ) + + /** + * Constructs a mapper, maps variables using transformer and replaces them in a global scope. + * @param variableName name of the transient variable to use. + * @param variableMapTransformer transformer to map from external to internal representation. + */ + @JvmStatic + fun transformingGlobalReplace(variableName: String, variableMapTransformer: VariableMapTransformer) = AntiCorruptionLayer( + precondition = VariablesGuard.EMPTY, + variableMapTransformer = variableMapTransformer, + factory = CamundaBpmData.customVariable(variableName, VariableMap::class.java), + valueApplicationStrategy = GlobalScopeReplaceStrategy + ) + + /** + * Constructs a mapper, maps variables using transformer and replaces them in a scope depending on flag. + * @param variableName name of the transient variable to use. + * @param variableMapTransformer transformer to map from external to internal representation. + * @param local flag to control local or global scope + */ + @JvmStatic + fun transformingReplace(variableName: String, local: Boolean, variableMapTransformer: VariableMapTransformer) = if (local) { + transformingLocalReplace(variableName, variableMapTransformer) + } else { + transformingGlobalReplace(variableName, variableMapTransformer) + } + + /** + * Constructs a mapper, maps variables 1:1 and replaces them in a local scope. + * @param variableName name of the transient variable to use. + */ + @JvmStatic + fun identityLocalReplace(variableName: String) = AntiCorruptionLayer( + precondition = VariablesGuard.EMPTY, + variableMapTransformer = IdentityVariableMapTransformer, + factory = CamundaBpmData.customVariable(variableName, VariableMap::class.java), + valueApplicationStrategy = LocalScopeReplaceStrategy + ) + + /** + * Constructs a mapper, maps variables 1:1 and replaces them in a global scope. + * @param variableName name of the transient variable to use. + */ + @JvmStatic + fun identityGlobalReplace(variableName: String) = AntiCorruptionLayer( + precondition = VariablesGuard.EMPTY, + variableMapTransformer = IdentityVariableMapTransformer, + factory = CamundaBpmData.customVariable(variableName, VariableMap::class.java), + valueApplicationStrategy = GlobalScopeReplaceStrategy + ) + + /** + * Constructs a mapper, maps variables 1:1 and replaces them in scope depending on flag. + * @param variableName name of the transient variable to use. + * @param local flag to control local or global scope + */ + @JvmStatic + fun identityReplace(variableName: String, local: Boolean) = if (local) { + identityLocalReplace(variableName) + } else { + identityGlobalReplace(variableName) + } + +} \ No newline at end of file diff --git a/extension/core/src/main/kotlin/acl/apply/GlobalScopeReplaceStrategy.kt b/extension/core/src/main/kotlin/acl/apply/GlobalScopeReplaceStrategy.kt new file mode 100644 index 00000000..84d6f1bc --- /dev/null +++ b/extension/core/src/main/kotlin/acl/apply/GlobalScopeReplaceStrategy.kt @@ -0,0 +1,20 @@ +package io.holunda.camunda.bpm.data.acl.apply + +import io.holunda.camunda.bpm.data.acl.assign.ValueApplicationStrategy +import org.camunda.bpm.engine.delegate.VariableScope +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Replaces variables of (global) scope with given variable map. + */ +object GlobalScopeReplaceStrategy : ValueApplicationStrategy { + + override fun apply(variableMap: VariableMap, variableScope: VariableScope): VariableScope = + variableScope.apply { + this.variables = variableMap + } + + override fun toString(): String { + return javaClass.canonicalName + } +} \ No newline at end of file diff --git a/extension/core/src/main/kotlin/acl/apply/LocalScopeReplaceStrategy.kt b/extension/core/src/main/kotlin/acl/apply/LocalScopeReplaceStrategy.kt new file mode 100644 index 00000000..78ea0862 --- /dev/null +++ b/extension/core/src/main/kotlin/acl/apply/LocalScopeReplaceStrategy.kt @@ -0,0 +1,20 @@ +package io.holunda.camunda.bpm.data.acl.apply + +import io.holunda.camunda.bpm.data.acl.assign.ValueApplicationStrategy +import org.camunda.bpm.engine.delegate.VariableScope +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Replaces variables of local scope with given variable map. + */ +object LocalScopeReplaceStrategy : ValueApplicationStrategy { + + override fun apply(variableMap: VariableMap, variableScope: VariableScope): VariableScope = + variableScope.apply { + this.variablesLocal = variableMap + } + + override fun toString(): String { + return javaClass.canonicalName + } +} \ No newline at end of file diff --git a/extension/core/src/main/kotlin/acl/apply/ValueApplicationStrategy.kt b/extension/core/src/main/kotlin/acl/apply/ValueApplicationStrategy.kt new file mode 100644 index 00000000..f58692f7 --- /dev/null +++ b/extension/core/src/main/kotlin/acl/apply/ValueApplicationStrategy.kt @@ -0,0 +1,16 @@ +package io.holunda.camunda.bpm.data.acl.assign + +import org.camunda.bpm.engine.delegate.VariableScope +import org.camunda.bpm.engine.variable.VariableMap + + +/** + * Interface describing the strategy to assign values. + */ +@FunctionalInterface +interface ValueApplicationStrategy { + /** + * Strategy to assign variables stored in a map to the given variable scope. + */ + fun apply(variableMap: VariableMap, variableScope: VariableScope): VariableScope +} \ No newline at end of file diff --git a/extension/core/src/main/kotlin/acl/package-info.kt b/extension/core/src/main/kotlin/acl/package-info.kt new file mode 100644 index 00000000..20937e29 --- /dev/null +++ b/extension/core/src/main/kotlin/acl/package-info.kt @@ -0,0 +1,8 @@ +/** + * Package providing resources for building of Anti-Corruption-Layer (ACL). + * + * @since 1.0.0 + * @see {@link io.holunda.camunda.bpm.data.acl.ACL} for more details. + * + */ +package io.holunda.camunda.bpm.data.acl diff --git a/extension/core/src/main/kotlin/acl/transform/IdentityVariableMapTransformer.kt b/extension/core/src/main/kotlin/acl/transform/IdentityVariableMapTransformer.kt new file mode 100644 index 00000000..a97b85c4 --- /dev/null +++ b/extension/core/src/main/kotlin/acl/transform/IdentityVariableMapTransformer.kt @@ -0,0 +1,10 @@ +package io.holunda.camunda.bpm.data.acl.transform + +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Performs no transformation (1:1 mapping). + */ +object IdentityVariableMapTransformer : VariableMapTransformer { + override fun transform(variableMap: VariableMap): VariableMap = variableMap +} \ No newline at end of file diff --git a/extension/core/src/main/kotlin/acl/transform/VariableMapTransformer.kt b/extension/core/src/main/kotlin/acl/transform/VariableMapTransformer.kt new file mode 100644 index 00000000..ee3b3106 --- /dev/null +++ b/extension/core/src/main/kotlin/acl/transform/VariableMapTransformer.kt @@ -0,0 +1,16 @@ +package io.holunda.camunda.bpm.data.acl.transform + +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Transforms values to the internal representation protected by the ACL. + */ +@FunctionalInterface +interface VariableMapTransformer { + /** + * Performs transformation on variable map. + * @param variableMap containing the values. + * @return new variable map + */ + fun transform(variableMap: VariableMap): VariableMap +} \ No newline at end of file diff --git a/extension/src/main/kotlin/guard/CamundaBpmDataGuards.kt b/extension/core/src/main/kotlin/guard/CamundaBpmDataGuards.kt similarity index 94% rename from extension/src/main/kotlin/guard/CamundaBpmDataGuards.kt rename to extension/core/src/main/kotlin/guard/CamundaBpmDataGuards.kt index ec5d9c9d..70491656 100644 --- a/extension/src/main/kotlin/guard/CamundaBpmDataGuards.kt +++ b/extension/core/src/main/kotlin/guard/CamundaBpmDataGuards.kt @@ -82,8 +82,7 @@ object CamundaBpmDataGuards { */ @JvmStatic fun matches(variableFactory: VariableFactory, - local: Boolean = false, - matcher: Function) = variableFactory.matches(local) { matcher.apply(it) } + matcher: Function, local: Boolean = false) = variableFactory.matches(local) { matcher.apply(it) } /** * Creates matches condition. @@ -92,7 +91,7 @@ object CamundaBpmDataGuards { */ @JvmStatic fun matches(variableFactory: VariableFactory, - matcher: Function) = variableFactory.matches() { matcher.apply(it) } + matcher: Function) = variableFactory.matches { matcher.apply(it) } } diff --git a/extension/src/main/kotlin/guard/GuardViolation.kt b/extension/core/src/main/kotlin/guard/GuardViolation.kt similarity index 100% rename from extension/src/main/kotlin/guard/GuardViolation.kt rename to extension/core/src/main/kotlin/guard/GuardViolation.kt diff --git a/extension/core/src/main/kotlin/guard/VariablesGuard.kt b/extension/core/src/main/kotlin/guard/VariablesGuard.kt new file mode 100644 index 00000000..a8129f5c --- /dev/null +++ b/extension/core/src/main/kotlin/guard/VariablesGuard.kt @@ -0,0 +1,99 @@ +package io.holunda.camunda.bpm.data.guard + +import io.holunda.camunda.bpm.data.guard.condition.VariableGuardCondition +import org.camunda.bpm.engine.RuntimeService +import org.camunda.bpm.engine.TaskService +import org.camunda.bpm.engine.delegate.VariableScope +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Guard on a set of variables. + * @param variableConditions a list of conditions to add to the guard. + */ +class VariablesGuard( + private val variableConditions: List> +) { + + companion object { + val EMPTY = VariablesGuard(listOf()) + } + + /** + * Constructs a guard with exactly one condition. + * @param condition condition to add to gurad. + */ + constructor(condition: VariableGuardCondition<*>) : this(listOf(condition)) + + /** + * Fluent builer to create a new guard from existing one adding one additional condition. + * @param condition to add to existing guard. + */ + fun fromExisting(condition: VariableGuardCondition<*>) = VariablesGuard(variableConditions.plus(condition)) + + /** + * Evaluates the contained conditions on variables from given variable map. + * @param variableMap variable map to work on. + * @return list of violations if any. + */ + fun evaluate(variableMap: VariableMap): List> = + variableConditions.flatMap { it.evaluate(variableMap) } + + /** + * Evaluates the contained conditions on variables from given variable scope. + * @param variableScope variable scope to work on. + * @return list of violations if any. + */ + fun evaluate(variableScope: VariableScope): List> = + variableConditions.flatMap { it.evaluate(variableScope) } + + /** + * Evaluates the contained conditions on variables retrieved from task service. + * @param taskService task service to access the task. + * @param taskId task id. + * @return list of violations if any. + */ + fun evaluate(taskService: TaskService, taskId: String): List> = + variableConditions.flatMap { it.evaluate(taskService, taskId) } + + /** + * Evaluates the contained conditions on variables retrieved from runtime service. + * @param runtimeService runtime service to access the execution. + * @param executionId execution id. + * @return list of violations if any. + */ + fun evaluate(runtimeService: RuntimeService, executionId: String): List> = + variableConditions.flatMap { it.evaluate(runtimeService, executionId) } + + /** + * Retrieves a list of local variables addressed by this guard. + * @return variable factories extracted from condition with scope local. + */ + fun getLocalVariables() = variableConditions.filter { it.local }.map { it.variableFactory } + + /** + * Retrieves a list of variables addressed by this guard. + * @return variable factories extracted from condition with scope global. + */ + fun getVariables() = variableConditions.filter { !it.local }.map { it.variableFactory } + + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as VariablesGuard + + if (variableConditions != other.variableConditions) return false + + return true + } + + override fun hashCode(): Int { + return variableConditions.hashCode() + } + + override fun toString(): String { + return "VariablesGuard(variableConditions=$variableConditions)" + } + +} diff --git a/extension/src/main/kotlin/guard/condition/VariableExistsGuardCondition.kt b/extension/core/src/main/kotlin/guard/condition/VariableExistsGuardCondition.kt similarity index 56% rename from extension/src/main/kotlin/guard/condition/VariableExistsGuardCondition.kt rename to extension/core/src/main/kotlin/guard/condition/VariableExistsGuardCondition.kt index df5bc2dc..21dea549 100644 --- a/extension/src/main/kotlin/guard/condition/VariableExistsGuardCondition.kt +++ b/extension/core/src/main/kotlin/guard/condition/VariableExistsGuardCondition.kt @@ -10,19 +10,23 @@ import java.util.* * @param local flag indicating if local or global scope is required. */ class VariableExistsGuardCondition( - variableFactory: VariableFactory, - local: Boolean = false + variableFactory: VariableFactory, + local: Boolean = false ) : VariableGuardCondition(variableFactory, local) { - override fun evaluate(option: Optional) = - if (option.isPresent) { - super.evaluate(option) - } else { - listOf(GuardViolation( - condition = this, - option = option, - message = "Expecting$localLabel variable '${variableFactory.name}' to be set, but it was not found.") - ) + override fun evaluate(option: Optional) = + if (option.isPresent) { + super.evaluate(option) + } else { + listOf(GuardViolation( + condition = this, + option = option, + message = "Expecting$localLabel variable '${variableFactory.name}' to be set, but it was not found.") + ) + } + + override fun toString(): String { + return "Exists condition for$localLabel variable '${super.variableFactory.name}'" } } diff --git a/extension/core/src/main/kotlin/guard/condition/VariableGuardCondition.kt b/extension/core/src/main/kotlin/guard/condition/VariableGuardCondition.kt new file mode 100644 index 00000000..a6c9f053 --- /dev/null +++ b/extension/core/src/main/kotlin/guard/condition/VariableGuardCondition.kt @@ -0,0 +1,94 @@ +package io.holunda.camunda.bpm.data.guard.condition + +import io.holunda.camunda.bpm.data.factory.VariableFactory +import io.holunda.camunda.bpm.data.guard.GuardViolation +import org.camunda.bpm.engine.RuntimeService +import org.camunda.bpm.engine.TaskService +import org.camunda.bpm.engine.delegate.VariableScope +import org.camunda.bpm.engine.variable.VariableMap +import java.util.* + +/** + * Abstract guard condition. + * @since 0.0.6 + * @param T variable type. + * @param variableFactory factory to work on. + * @param local flag indicating the variable scope (global/local). Defaults to global. + *

+ * This class is intended to be subclassed by developers of new variable guards. + *

+ */ +abstract class VariableGuardCondition( + internal val variableFactory: VariableFactory, + internal val local: Boolean = false +) { + + /** + * Label for messages indicating the variable scope (local or global, which is a default). + */ + val localLabel: String by lazy { if (local) " local" else "" } + + /** + * Evaluate the condition on a value option. + * @param option optional value for the variable, contaning the value or nothing. + * @return list of guard violations. + */ + internal open fun evaluate(option: Optional): List> = emptyList() + + /** + * Evaluate the condition on a value retrieved from the variable map. + * @param variableMap variables to run the evaluation on. + * @return list of guard violations + */ + fun evaluate(variableMap: VariableMap): List> { + return evaluate(if (local) variableFactory.from(variableMap).localOptional else variableFactory.from(variableMap).optional) + } + + /** + * Evaluate the condition on a value retrieved from the variable map. + * @param variableScope variable scope (e.g. delegate execution or delegate task) to run the evaluation on. + * @return list of guard violations + */ + fun evaluate(variableScope: VariableScope): List> { + return evaluate(if (local) variableFactory.from(variableScope).localOptional else variableFactory.from(variableScope).optional) + } + + /** + * Evaluate the condition on a value retrieved from the task service. + * @param taskService to retrieve the task from. + * @param taskId id of the task to work on. + * @return list of guard violations + */ + fun evaluate(taskService: TaskService, taskId: String): List> { + return evaluate(if (local) variableFactory.from(taskService, taskId).localOptional else variableFactory.from(taskService, taskId).optional) + } + + /** + * Evaluate the condition on a value retrieved from the runtime service. + * @param runtimeService to retrieve the execution from. + * @param executionId id of the execution to work on. + * @return list of guard violations + */ + fun evaluate(runtimeService: RuntimeService, executionId: String): List> { + return evaluate(if (local) variableFactory.from(runtimeService, executionId).localOptional else variableFactory.from(runtimeService, executionId).optional) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as VariableGuardCondition<*> + + if (variableFactory != other.variableFactory) return false + if (local != other.local) return false + + return true + } + + override fun hashCode(): Int { + var result = variableFactory.hashCode() + result = 31 * result + local.hashCode() + return result + } + +} diff --git a/extension/src/main/kotlin/guard/condition/VariableMatchesGuardCondition.kt b/extension/core/src/main/kotlin/guard/condition/VariableMatchesGuardCondition.kt similarity index 85% rename from extension/src/main/kotlin/guard/condition/VariableMatchesGuardCondition.kt rename to extension/core/src/main/kotlin/guard/condition/VariableMatchesGuardCondition.kt index 38f92a2a..1da3946c 100644 --- a/extension/src/main/kotlin/guard/condition/VariableMatchesGuardCondition.kt +++ b/extension/core/src/main/kotlin/guard/condition/VariableMatchesGuardCondition.kt @@ -24,7 +24,7 @@ class VariableMatchesGuardCondition( override fun evaluate(option: Optional): List> { val violations = existsCondition.evaluate(option).toMutableList() - if (!matcher.invoke(option.get())) { + if (option.isPresent && !matcher.invoke(option.get())) { violations.add( GuardViolation( condition = this, @@ -35,6 +35,11 @@ class VariableMatchesGuardCondition( } return violations } + + override fun toString(): String { + return "Matches condition for$localLabel variable '${super.variableFactory.name}'" + } + } /** @@ -43,5 +48,4 @@ class VariableMatchesGuardCondition( * @param matcher function that must match the value. * @return instance of [VariableMatchesGuardCondition] on current factory. */ -fun VariableFactory.matches(local: Boolean = false, matcher: (value: T) -> Boolean) - = VariableMatchesGuardCondition(this, local, matcher) \ No newline at end of file +fun VariableFactory.matches(local: Boolean = false, matcher: (value: T) -> Boolean) = VariableMatchesGuardCondition(this, local, matcher) \ No newline at end of file diff --git a/extension/src/main/kotlin/guard/condition/VariableNotExistsGuardCondition.kt b/extension/core/src/main/kotlin/guard/condition/VariableNotExistsGuardCondition.kt similarity index 55% rename from extension/src/main/kotlin/guard/condition/VariableNotExistsGuardCondition.kt rename to extension/core/src/main/kotlin/guard/condition/VariableNotExistsGuardCondition.kt index 0137b468..fdcf8cb6 100644 --- a/extension/src/main/kotlin/guard/condition/VariableNotExistsGuardCondition.kt +++ b/extension/core/src/main/kotlin/guard/condition/VariableNotExistsGuardCondition.kt @@ -10,20 +10,25 @@ import java.util.* * @param local flag indicating if local or global scope is required. */ class VariableNotExistsGuardCondition( - variableFactory: VariableFactory, - local: Boolean = false + variableFactory: VariableFactory, + local: Boolean = false ) : VariableGuardCondition(variableFactory, local) { - override fun evaluate(option: Optional) = - if (!option.isPresent) { - super.evaluate(option) - } else { - listOf(GuardViolation( - condition = this, - option = option, - message = "Expecting$localLabel variable '${variableFactory.name}' not to be set, but it had a value of '${option.get()}'.") - ) + override fun evaluate(option: Optional) = + if (!option.isPresent) { + super.evaluate(option) + } else { + listOf(GuardViolation( + condition = this, + option = option, + message = "Expecting$localLabel variable '${variableFactory.name}' not to be set, but it had a value of '${option.get()}'.") + ) + } + + override fun toString(): String { + return "NotExists condition for$localLabel variable '${super.variableFactory.name}'" } + } /** diff --git a/extension/core/src/main/kotlin/guard/condition/VariableValueGuardCondition.kt b/extension/core/src/main/kotlin/guard/condition/VariableValueGuardCondition.kt new file mode 100644 index 00000000..754538ba --- /dev/null +++ b/extension/core/src/main/kotlin/guard/condition/VariableValueGuardCondition.kt @@ -0,0 +1,50 @@ +package io.holunda.camunda.bpm.data.guard.condition + +import io.holunda.camunda.bpm.data.factory.VariableFactory +import io.holunda.camunda.bpm.data.guard.GuardViolation +import java.util.* + +/** + * Condition to check if the variable has provided value. + * @param variableFactory factory to work on. + * @param value set of values to compare with. + * @param local flag indicating if local or global scope is required. + */ +class VariableValueGuardCondition( + variableFactory: VariableFactory, + val value: T, + local: Boolean = false +) : VariableGuardCondition(variableFactory, local) { + + private val existsCondition = VariableExistsGuardCondition(variableFactory, local) + + override fun evaluate(option: Optional): List> { + val violations = existsCondition.evaluate(option).toMutableList() + if (option.isPresent) { + if (option.get() != value) { + violations.add( + GuardViolation( + condition = this, + option = option, + message = "Expecting$localLabel variable '${variableFactory.name}' to have value '$value', but it was '${option.get()}'." + ) + ) + } + } + return violations + } + + override fun toString(): String { + return "Value condition for$localLabel variable '${super.variableFactory.name}', value $value" + } + +} + +/** + * Creation extension for the condition. + * @param value value to check for. + * @param local if the variable should be local. + * @return instance of [VariableValueGuardCondition] on current factory. + */ +fun VariableFactory.hasValue(value: T, local: Boolean = false) = VariableValueGuardCondition(this, value, local) + diff --git a/extension/core/src/main/kotlin/guard/condition/VariableValueOneOfGuardCondition.kt b/extension/core/src/main/kotlin/guard/condition/VariableValueOneOfGuardCondition.kt new file mode 100644 index 00000000..c621f4ea --- /dev/null +++ b/extension/core/src/main/kotlin/guard/condition/VariableValueOneOfGuardCondition.kt @@ -0,0 +1,50 @@ +package io.holunda.camunda.bpm.data.guard.condition + +import io.holunda.camunda.bpm.data.factory.VariableFactory +import io.holunda.camunda.bpm.data.guard.GuardViolation +import java.util.* + +/** + * Condition to check if the variable has on of the provided values. + * @param variableFactory factory to work on. + * @param values set of values to compare with. + * @param local flag indicating if local or global scope is required. + */ +class VariableValueOneOfGuardCondition( + variableFactory: VariableFactory, + val values: Set, + local: Boolean = false +) : VariableGuardCondition(variableFactory, local) { + + private val existsCondition = VariableExistsGuardCondition(variableFactory, local) + private val valueConditions = values.map { VariableValueGuardCondition(variableFactory, it, local) } + + override fun evaluate(option: Optional): List> { + val violations = existsCondition.evaluate(option).toMutableList() + if (option.isPresent) { + if (valueConditions.none { it.evaluate(option).isEmpty() }) { + violations.add( + GuardViolation( + condition = this, + option = option, + message = "Expecting$localLabel variable '${variableFactory.name}' to be one of [${values.joinToString("', '", "'", "'")}], but it was '${option.get()}'." + ) + ) + } + } + return violations + } + + override fun toString(): String { + return "ValueIn condition for$localLabel variable '${super.variableFactory.name}', values [${values.joinToString("', '", "'", "'")}]" + } + +} + +/** + * Creation extension for the condition. + * @param local is the variable should be local. + * @param values set of values which are allowed. + * @return instance of [VariableValueOneOfGuardCondition] on current factory. + */ +fun VariableFactory.hasOneOfValues(values: Set, local: Boolean = false) = VariableValueOneOfGuardCondition(this, values, local) diff --git a/extension/src/main/kotlin/guard/integration/AbstractGuardExecutionListener.kt b/extension/core/src/main/kotlin/guard/integration/DefaultGuardExecutionListener.kt similarity index 58% rename from extension/src/main/kotlin/guard/integration/AbstractGuardExecutionListener.kt rename to extension/core/src/main/kotlin/guard/integration/DefaultGuardExecutionListener.kt index dbca01be..98e6e494 100644 --- a/extension/src/main/kotlin/guard/integration/AbstractGuardExecutionListener.kt +++ b/extension/core/src/main/kotlin/guard/integration/DefaultGuardExecutionListener.kt @@ -7,20 +7,25 @@ import org.camunda.bpm.engine.delegate.ExecutionListener import org.slf4j.LoggerFactory /** - * Abstract guard execution listener, evaluating the given guard conditions on the execution. - * @param variableConditions condition to check by the guard. + * Default guard execution listener, evaluating the given guard conditions on the execution. + * @param guard guard to check. * @param throwViolations flag controlling if the violation should lead to an exception. */ -abstract class AbstractGuardExecutionListener( - val variableConditions: List>, +class DefaultGuardExecutionListener( + val guard: VariablesGuard, val throwViolations: Boolean = true ) : ExecutionListener { companion object { - private val logger = LoggerFactory.getLogger(AbstractGuardExecutionListener::class.java) + private val logger = LoggerFactory.getLogger(DefaultGuardExecutionListener::class.java) } - private val guard = VariablesGuard(variableConditions) + /** + * Constructs an execution listener using the provided conditions. + * @param variableConditions condition to check by the guard. + * @param throwViolations flag controlling if the violation should lead to an exception. + */ + constructor(variableConditions: List>, throwViolations: Boolean) : this(VariablesGuard(variableConditions), throwViolations) override fun notify(execution: DelegateExecution) { val violations = guard.evaluate(execution) @@ -30,7 +35,7 @@ abstract class AbstractGuardExecutionListener( logger.error("$message: ${it.message}") } if (throwViolations) { - throw GuardViolationException(violations = violations, message = message) + throw GuardViolationException(violations = violations, reason = message) } } } diff --git a/extension/src/main/kotlin/guard/integration/AbstractGuardTaskListener.kt b/extension/core/src/main/kotlin/guard/integration/DefaultGuardTaskListener.kt similarity index 61% rename from extension/src/main/kotlin/guard/integration/AbstractGuardTaskListener.kt rename to extension/core/src/main/kotlin/guard/integration/DefaultGuardTaskListener.kt index a7c69c6b..8bea4d32 100644 --- a/extension/src/main/kotlin/guard/integration/AbstractGuardTaskListener.kt +++ b/extension/core/src/main/kotlin/guard/integration/DefaultGuardTaskListener.kt @@ -7,20 +7,25 @@ import org.camunda.bpm.engine.delegate.TaskListener import org.slf4j.LoggerFactory /** - * Abstract guard execution listener, evaluating the given guard conditions on the task. - * @param variableConditions condition to check by the guard. + * Default guard execution listener, evaluating the given guard conditions on the task. + * @param guard guard to check. * @param throwViolations flag controlling if the violation should lead to an exception. */ -abstract class AbstractGuardTaskListener( - val variableConditions: List>, +class DefaultGuardTaskListener( + val guard: VariablesGuard, val throwViolations: Boolean = true ) : TaskListener { companion object { - private val logger = LoggerFactory.getLogger(AbstractGuardExecutionListener::class.java) + private val logger = LoggerFactory.getLogger(DefaultGuardTaskListener::class.java) } - private val guard = VariablesGuard(variableConditions) + /** + * Constructs an execution listener using the provided conditions. + * @param variableConditions condition to check by the guard. + * @param throwViolations flag controlling if the violation should lead to an exception. + */ + constructor(variableConditions: List>, throwViolations: Boolean) : this(VariablesGuard(variableConditions), throwViolations) override fun notify(task: DelegateTask) { val violations = guard.evaluate(task) @@ -30,7 +35,7 @@ abstract class AbstractGuardTaskListener( logger.error("$message: ${it.message}") } if (throwViolations) { - throw GuardViolationException(violations = violations, message = message) + throw GuardViolationException(violations = violations, reason = message) } } } diff --git a/extension/src/main/kotlin/guard/integration/GuardViolationException.kt b/extension/core/src/main/kotlin/guard/integration/GuardViolationException.kt similarity index 67% rename from extension/src/main/kotlin/guard/integration/GuardViolationException.kt rename to extension/core/src/main/kotlin/guard/integration/GuardViolationException.kt index 7fab1acb..db164443 100644 --- a/extension/src/main/kotlin/guard/integration/GuardViolationException.kt +++ b/extension/core/src/main/kotlin/guard/integration/GuardViolationException.kt @@ -5,11 +5,13 @@ import org.camunda.bpm.engine.ProcessEngineException /** * Exception indicating a guard violation. + * @param violations list of guard violations. + * @param reason reason of failure. */ class GuardViolationException( - val violations: List>, - override val message: String -) : ProcessEngineException(createMessage(message, violations)) { + violations: List>, + reason: String +) : ProcessEngineException(createMessage(reason, violations)) { companion object { /** * Create a message from a provided message prefix and a list of violations. @@ -19,7 +21,7 @@ class GuardViolationException( */ @JvmStatic fun createMessage(message: String, violations: List>): String { - return "$message\n" + violations.joinToString { "\t${it.message}\n" } + return "$message\n" + violations.joinToString(separator = ",\n") { "\t${it.message}" } } } } \ No newline at end of file diff --git a/extension/core/src/main/kotlin/guard/package-info.kt b/extension/core/src/main/kotlin/guard/package-info.kt new file mode 100644 index 00000000..4307db83 --- /dev/null +++ b/extension/core/src/main/kotlin/guard/package-info.kt @@ -0,0 +1,7 @@ +/** + * Package providing resources for building Variable Guards. + * + * @since 0.0.4 + * @see io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards for more details. + */ +package io.holunda.camunda.bpm.data.guard diff --git a/extension/src/main/kotlin/package-info.java b/extension/core/src/main/kotlin/package-info.kt similarity index 81% rename from extension/src/main/kotlin/package-info.java rename to extension/core/src/main/kotlin/package-info.kt index 8ffe536e..6a97145d 100644 --- a/extension/src/main/kotlin/package-info.java +++ b/extension/core/src/main/kotlin/package-info.kt @@ -4,3 +4,4 @@ * @see io.holunda.camunda.bpm.data.CamundaBpmData as entry point for variable factory definition. * @since 0.0.2 */ +package io.holunda.camunda.bpm.data diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/acl/CamundaBpmDataACLFactoryTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/acl/CamundaBpmDataACLFactoryTest.java new file mode 100644 index 00000000..09e5469a --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/acl/CamundaBpmDataACLFactoryTest.java @@ -0,0 +1,26 @@ +package io.holunda.camunda.bpm.data.acl; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.acl.transform.IdentityVariableMapTransformer; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import io.holunda.camunda.bpm.data.guard.VariablesGuard; +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.variable.VariableMap; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.exists; + +public class CamundaBpmDataACLFactoryTest { + + private RuntimeService runtimeService; + private static VariableFactory FOO = stringVariable("foo"); + private static AntiCorruptionLayer MY_ACL = CamundaBpmDataACL.guardTransformingReplace("__transient", true, + new VariablesGuard(exists(FOO)), + IdentityVariableMapTransformer.INSTANCE + ); + + public void testCallFromJava(String value) { + VariableMap variableMap = MY_ACL.checkAndWrap(CamundaBpmData.builder().set(FOO, value).build()); + runtimeService.correlateMessage("message", variableMap); + } +} diff --git a/extension/src/test/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtilTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtilTest.java similarity index 68% rename from extension/src/test/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtilTest.java rename to extension/core/src/test/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtilTest.java index 244caaa3..0d026d21 100644 --- a/extension/src/test/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtilTest.java +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtilTest.java @@ -1,5 +1,10 @@ package io.holunda.camunda.bpm.data.adapter; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.time.Instant; +import java.util.Date; import org.camunda.bpm.engine.variable.type.PrimitiveValueType; import org.camunda.bpm.engine.variable.value.BooleanValue; import org.camunda.bpm.engine.variable.value.DateValue; @@ -12,11 +17,6 @@ import org.camunda.bpm.engine.variable.value.TypedValue; import org.junit.Test; -import java.time.Instant; -import java.util.Date; - -import static org.assertj.core.api.Assertions.assertThat; - public class ValueWrapperUtilTest { @Test @@ -32,6 +32,12 @@ public void shouldReturnDoubleValue() { assertThat(doubleValue.getType()).isExactlyInstanceOf(PrimitiveValueType.DOUBLE.getClass()); assertThat(doubleValue.getValue()).isEqualTo(Double.MAX_VALUE); assertThat(doubleValue.isTransient()).isTrue(); + + doubleValue = ValueWrapperUtil.getTypedValue(Double.class, null, true); + assertThat(doubleValue).isInstanceOf(DoubleValue.class); + assertThat(doubleValue.getType()).isExactlyInstanceOf(PrimitiveValueType.DOUBLE.getClass()); + assertThat(doubleValue.getValue()).isNull(); + assertThat(doubleValue.isTransient()).isTrue(); } @Test @@ -47,6 +53,13 @@ public void shouldReturnIntegerValue() { assertThat(integerValue.getType()).isExactlyInstanceOf(PrimitiveValueType.INTEGER.getClass()); assertThat(integerValue.getValue()).isEqualTo(Integer.MAX_VALUE); assertThat(integerValue.isTransient()).isTrue(); + + integerValue = ValueWrapperUtil.getTypedValue(Integer.class, null, true); + assertThat(integerValue).isInstanceOf(IntegerValue.class); + assertThat(integerValue.getType()).isExactlyInstanceOf(PrimitiveValueType.INTEGER.getClass()); + assertThat(integerValue.getValue()).isNull(); + assertThat(integerValue.isTransient()).isTrue(); + } @Test @@ -64,6 +77,13 @@ public void shouldReturnDateValue() { assertThat(dateValue.getType()).isExactlyInstanceOf(PrimitiveValueType.DATE.getClass()); assertThat(dateValue.getValue()).isEqualTo(value); assertThat(dateValue.isTransient()).isTrue(); + + dateValue = ValueWrapperUtil.getTypedValue(Date.class, null, true); + assertThat(dateValue).isInstanceOf(DateValue.class); + assertThat(dateValue.getType()).isExactlyInstanceOf(PrimitiveValueType.DATE.getClass()); + assertThat(dateValue.getValue()).isNull(); + assertThat(dateValue.isTransient()).isTrue(); + } @Test @@ -79,6 +99,13 @@ public void shouldReturnBooleanValue() { assertThat(booleanValue.getType()).isExactlyInstanceOf(PrimitiveValueType.BOOLEAN.getClass()); assertThat(booleanValue.getValue()).isEqualTo(Boolean.FALSE); assertThat(booleanValue.isTransient()).isTrue(); + + booleanValue = ValueWrapperUtil.getTypedValue(Boolean.class, null, true); + assertThat(booleanValue).isInstanceOf(BooleanValue.class); + assertThat(booleanValue.getType()).isExactlyInstanceOf(PrimitiveValueType.BOOLEAN.getClass()); + assertThat(booleanValue.getValue()).isNull(); + assertThat(booleanValue.isTransient()).isTrue(); + } @Test @@ -94,20 +121,33 @@ public void shouldReturnLongValue() { assertThat(longValue.getType()).isExactlyInstanceOf(PrimitiveValueType.LONG.getClass()); assertThat(longValue.getValue()).isEqualTo(Long.MAX_VALUE); assertThat(longValue.isTransient()).isTrue(); + + longValue = ValueWrapperUtil.getTypedValue(Long.class, null, true); + assertThat(longValue).isInstanceOf(LongValue.class); + assertThat(longValue.getType()).isExactlyInstanceOf(PrimitiveValueType.LONG.getClass()); + assertThat(longValue.getValue()).isNull(); + assertThat(longValue.isTransient()).isTrue(); + } @Test public void shouldReturnStringValue() { - TypedValue stringValue = ValueWrapperUtil.getTypedValue(String.class, String.class.getName(), false); + TypedValue stringValue = ValueWrapperUtil.getTypedValue(String.class, "foo", false); assertThat(stringValue).isInstanceOf(StringValue.class); assertThat(stringValue.getType()).isExactlyInstanceOf(PrimitiveValueType.STRING.getClass()); - assertThat(stringValue.getValue()).isEqualTo(String.class.getName()); + assertThat(stringValue.getValue()).isEqualTo("foo"); assertThat(stringValue.isTransient()).isFalse(); - stringValue = ValueWrapperUtil.getTypedValue(String.class, String.class.getName(), true); + stringValue = ValueWrapperUtil.getTypedValue(String.class, "foo", true); assertThat(stringValue).isInstanceOf(StringValue.class); assertThat(stringValue.getType()).isExactlyInstanceOf(PrimitiveValueType.STRING.getClass()); - assertThat(stringValue.getValue()).isEqualTo(String.class.getName()); + assertThat(stringValue.getValue()).isEqualTo("foo"); + assertThat(stringValue.isTransient()).isTrue(); + + stringValue = ValueWrapperUtil.getTypedValue(String.class, null, true); + assertThat(stringValue).isInstanceOf(StringValue.class); + assertThat(stringValue.getType()).isExactlyInstanceOf(PrimitiveValueType.STRING.getClass()); + assertThat(stringValue.getValue()).isNull(); assertThat(stringValue.isTransient()).isTrue(); } @@ -124,6 +164,13 @@ public void shouldReturnShortValue() { assertThat(shortValue.getType()).isExactlyInstanceOf(PrimitiveValueType.SHORT.getClass()); assertThat(shortValue.getValue()).isEqualTo(Short.MAX_VALUE); assertThat(shortValue.isTransient()).isTrue(); + + shortValue = ValueWrapperUtil.getTypedValue(Short.class, null, true); + assertThat(shortValue).isInstanceOf(ShortValue.class); + assertThat(shortValue.getType()).isExactlyInstanceOf(PrimitiveValueType.SHORT.getClass()); + assertThat(shortValue.getValue()).isNull(); + assertThat(shortValue.isTransient()).isTrue(); + } @Test @@ -140,6 +187,13 @@ public void shouldReturnObjectValue() { assertThat(objectValue.getType()).isExactlyInstanceOf(PrimitiveValueType.OBJECT.getClass()); assertThat(objectValue.getValue()).isEqualTo(value); assertThat(objectValue.isTransient()).isTrue(); + + objectValue = ValueWrapperUtil.getTypedValue(Object.class, null, true); + assertThat(objectValue).isInstanceOf(ObjectValue.class); + assertThat(objectValue.getType()).isExactlyInstanceOf(PrimitiveValueType.OBJECT.getClass()); + assertThat(objectValue.getValue()).isNull(); + assertThat(objectValue.isTransient()).isTrue(); + } @Test @@ -154,11 +208,18 @@ public void shouldReturnUntypedValue() { assertThat(untypedValue.getType()).isNull(); assertThat(untypedValue.getValue()).isEqualTo(value); assertThat(untypedValue.isTransient()).isTrue(); + + untypedValue = ValueWrapperUtil.getTypedValue(Instant.class, null, true); + assertThat(untypedValue.getType()).isInstanceOf(PrimitiveValueType.NULL.getClass()); + assertThat(untypedValue.getValue()).isNull(); + assertThat(untypedValue.isTransient()).isTrue(); + } - @Test(expected = IllegalArgumentException.class) + @Test public void shouldThrowExceptionOnWrongType() { - ValueWrapperUtil.getTypedValue(Date.class, Instant.now(), false); + assertThatThrownBy(() -> ValueWrapperUtil.getTypedValue(Date.class, Instant.now(), false)) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilderTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilderTest.java new file mode 100644 index 00000000..3b2d30a4 --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilderTest.java @@ -0,0 +1,48 @@ +package io.holunda.camunda.bpm.data.builder; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.assertj.core.api.Assertions.assertThat; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.variable.VariableMap; +import org.junit.Test; + +public class VariableMapBuilderTest { + + private static final VariableFactory FOO = stringVariable("foo"); + + @Test + public void builderCanCreateEmptyVariableMap() { + assertThat(CamundaBpmData.builder().build()).isEmpty(); + } + + @Test + public void builderCanWriteVariable() { + VariableMap variables = CamundaBpmData.builder().set(FOO, "bar").build(); + + assertThat(FOO.from(variables).get()).isEqualTo("bar"); + } + + @Test + public void buildCreatesANewInstanceEveryTime() { + VariableMapBuilder builder = CamundaBpmData.builder().set(FOO, "bar"); + + // build copy with "bar" + VariableMap bar = builder.build(); + assertThat(bar).containsEntry("foo", "bar"); + + // modify builder, build copy with "baz" + VariableMap baz = builder.set(FOO, "baz").build(); + assertThat(baz).containsEntry("foo", "baz"); + + // "bar" is not changed + assertThat(bar).containsEntry("foo", "bar"); + + // modify "baz" + FOO.on(baz).set("xxx"); + + // build again + assertThat(builder.build()).containsEntry("foo", "baz"); + } +} diff --git a/extension/src/test/java/io/holunda/camunda/bpm/data/factory/VariableFactoryTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/factory/VariableFactoryTest.java similarity index 100% rename from extension/src/test/java/io/holunda/camunda/bpm/data/factory/VariableFactoryTest.java rename to extension/core/src/test/java/io/holunda/camunda/bpm/data/factory/VariableFactoryTest.java diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/ProcessExecutionVariableReaderTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/ProcessExecutionVariableReaderTest.java new file mode 100644 index 00000000..994f280a --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/ProcessExecutionVariableReaderTest.java @@ -0,0 +1,56 @@ +package io.holunda.camunda.bpm.data.reader; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.UUID; +import org.camunda.bpm.engine.RuntimeService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class ProcessExecutionVariableReaderTest { + + private static final VariableFactory STRING = stringVariable("myString"); + private final RuntimeService runtimeService = Mockito.mock(RuntimeService.class); + private final String executionId = UUID.randomUUID().toString(); + private String value = "value"; + private String valueLocal = "valueLocal"; + + @Before + public void mockExecution() { + when(runtimeService.getVariable(this.executionId, STRING.getName())).thenReturn(value); + when(runtimeService.getVariableLocal(this.executionId, STRING.getName())).thenReturn(valueLocal); + } + + @After + public void after() { + Mockito.reset(runtimeService); + } + + @Test + public void shouldDelegateGet() { + assertThat(CamundaBpmData.reader(runtimeService, executionId).get(STRING)).isEqualTo(value); + } + + @Test + public void shouldDelegateGetOptional() { + assertThat(CamundaBpmData.reader(runtimeService, executionId).getOptional(STRING)).hasValue(value); + assertThat(CamundaBpmData.reader(runtimeService, executionId).getOptional(stringVariable("xxx"))).isEmpty(); + } + + @Test + public void shouldDelegateGetLocalOptional() { + assertThat(CamundaBpmData.reader(runtimeService, executionId).getLocalOptional(STRING)).hasValue(valueLocal); + assertThat(CamundaBpmData.reader(runtimeService, executionId).getLocalOptional(stringVariable("xxx"))).isEmpty(); + } + + @Test + public void shouldDelegateGetLocal() { + assertThat(CamundaBpmData.reader(runtimeService, executionId).getLocal(STRING)).isEqualTo(valueLocal); + } +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/UserTaskVariableReaderTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/UserTaskVariableReaderTest.java new file mode 100644 index 00000000..2880657c --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/UserTaskVariableReaderTest.java @@ -0,0 +1,56 @@ +package io.holunda.camunda.bpm.data.reader; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.UUID; +import org.camunda.bpm.engine.TaskService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class UserTaskVariableReaderTest { + + private static final VariableFactory STRING = stringVariable("myString"); + private final TaskService taskService = Mockito.mock(TaskService.class); + private final String taskId = UUID.randomUUID().toString(); + private final String value = "value"; + private final String localValue = "localValue"; + + @Before + public void mockExecution() { + when(taskService.getVariable(this.taskId, STRING.getName())).thenReturn(value); + when(taskService.getVariableLocal(this.taskId, STRING.getName())).thenReturn(localValue); + } + + @After + public void after() { + Mockito.reset(taskService); + } + + @Test + public void shouldDelegateGet() { + assertThat(CamundaBpmData.reader(taskService, taskId).get(STRING)).isEqualTo(value); + } + + @Test + public void shouldDelegateGetOptional() { + assertThat(CamundaBpmData.reader(taskService, taskId).getOptional(STRING)).hasValue(value); + assertThat(CamundaBpmData.reader(taskService, taskId).getOptional(stringVariable("xxx"))).isEmpty(); + } + + @Test + public void shouldDelegateGetLocalOptional() { + assertThat(CamundaBpmData.reader(taskService, taskId).getLocalOptional(STRING)).hasValue(localValue); + assertThat(CamundaBpmData.reader(taskService, taskId).getLocalOptional(stringVariable("xxx"))).isEmpty(); + } + + @Test + public void shouldDelegateGetLocal() { + assertThat(CamundaBpmData.reader(taskService, taskId).getLocal(STRING)).isEqualTo(localValue); + } +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/VariableMapReaderTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/VariableMapReaderTest.java new file mode 100644 index 00000000..b595be44 --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/VariableMapReaderTest.java @@ -0,0 +1,40 @@ +package io.holunda.camunda.bpm.data.reader; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.variable.VariableMap; +import org.junit.Test; + +public class VariableMapReaderTest { + + private static final VariableFactory STRING = stringVariable("myString"); + + private final String value = "value"; + + private final VariableMap variableMap = CamundaBpmData.builder().set(STRING, value).build(); + + @Test + public void shouldDelegateGet() { + assertThat(CamundaBpmData.reader(variableMap).get(STRING)).isEqualTo(value); + } + + @Test + public void shouldDelegateGetOptional() { + assertThat(CamundaBpmData.reader(variableMap).getOptional(STRING)).hasValue(value); + assertThat(CamundaBpmData.reader(variableMap).getOptional(stringVariable("xxx"))).isEmpty(); + } + + @Test + public void shouldDelegateGetLocalOptional() { + assertThatThrownBy(() -> CamundaBpmData.reader(variableMap).getLocalOptional(STRING)).isInstanceOf(UnsupportedOperationException.class); + } + + @Test + public void shouldDelegateGetLocal() { + assertThatThrownBy(() -> CamundaBpmData.reader(variableMap).getLocalOptional(STRING)).isInstanceOf(UnsupportedOperationException.class); + } +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/VariableScopeReaderTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/VariableScopeReaderTest.java new file mode 100644 index 00000000..886c4911 --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/reader/VariableScopeReaderTest.java @@ -0,0 +1,50 @@ +package io.holunda.camunda.bpm.data.reader; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.assertj.core.api.Assertions.assertThat; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.extension.mockito.delegate.DelegateExecutionFake; +import org.junit.Test; + +// Testing is a bit different here because DelegateExecutionFake does not correctly support local variables. +public class VariableScopeReaderTest { + + private static final VariableFactory STRING = stringVariable("myString"); + + private final String value = "value"; + private final String localValue = "localValue"; + + + @Test + public void shouldDelegateGet() { + DelegateExecution execution = new DelegateExecutionFake(); + STRING.on(execution).set(value); + assertThat(CamundaBpmData.reader(execution).get(STRING)).isEqualTo(value); + } + + @Test + public void shouldDelegateGetOptional() { + DelegateExecution execution = new DelegateExecutionFake(); + STRING.on(execution).set(value); + assertThat(CamundaBpmData.reader(execution).getOptional(STRING)).hasValue(value); + assertThat(CamundaBpmData.reader(execution).getOptional(stringVariable("xxx"))).isEmpty(); + } + + @Test + public void shouldDelegateGetLocalOptional() { + DelegateExecution execution = new DelegateExecutionFake(); + STRING.on(execution).setLocal(localValue); + assertThat(CamundaBpmData.reader(execution).getLocalOptional(STRING)).hasValue(localValue); + assertThat(CamundaBpmData.reader(execution).getLocalOptional(stringVariable("xxx"))).isEmpty(); + } + + @Test + public void shouldDelegateGetLocal() { + DelegateExecution execution = new DelegateExecutionFake(); + STRING.on(execution).setLocal(localValue); + assertThat(CamundaBpmData.reader(execution).getLocal(STRING)).isEqualTo(localValue); + } +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/ProcessExecutionVariableWriterTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/ProcessExecutionVariableWriterTest.java new file mode 100644 index 00000000..e065ae2a --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/ProcessExecutionVariableWriterTest.java @@ -0,0 +1,64 @@ +package io.holunda.camunda.bpm.data.writer; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.UUID; +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.variable.Variables; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class ProcessExecutionVariableWriterTest { + + private static final VariableFactory STRING = stringVariable("myString"); + private final RuntimeService runtimeService = Mockito.mock(RuntimeService.class); + private final String executionId = UUID.randomUUID().toString(); + private final String value = "value"; + private final String localValue = "localValue"; + + @Before + public void setUp() { + when(runtimeService.getVariable(this.executionId, STRING.getName())).thenReturn(value); + when(runtimeService.getVariableLocal(this.executionId, STRING.getName())).thenReturn(localValue); + } + + @After + public void after() { + Mockito.reset(runtimeService); + } + + @Test + public void testSet() { + CamundaBpmData.writer(runtimeService, executionId) + .set(STRING, "value"); + verify(runtimeService).setVariable(this.executionId, STRING.getName(), Variables.stringValue("value")); + } + + @Test + public void testSetLocal() { + CamundaBpmData.writer(runtimeService, executionId) + .setLocal(STRING, "value"); + verify(runtimeService).setVariableLocal(this.executionId, STRING.getName(), Variables.stringValue("value")); + } + + @Test + public void testRemove() { + CamundaBpmData.writer(runtimeService, executionId) + .remove(STRING); + verify(runtimeService).removeVariable(this.executionId, STRING.getName()); + } + + @Test + public void testRemoveLocal() { + CamundaBpmData.writer(runtimeService, executionId) + .removeLocal(STRING); + verify(runtimeService).removeVariableLocal(this.executionId, STRING.getName()); + } + +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/UserTaskVariableWriterTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/UserTaskVariableWriterTest.java new file mode 100644 index 00000000..f62cb6e7 --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/UserTaskVariableWriterTest.java @@ -0,0 +1,65 @@ +package io.holunda.camunda.bpm.data.writer; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import java.util.UUID; +import org.camunda.bpm.engine.TaskService; +import org.camunda.bpm.engine.variable.Variables; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class UserTaskVariableWriterTest { + + private static final VariableFactory STRING = stringVariable("myString"); + private final TaskService taskService = Mockito.mock(TaskService.class); + private final String taskId = UUID.randomUUID().toString(); + private String value = "value"; + + @Before + public void setUp() { + when(taskService.getVariable(this.taskId, STRING.getName())).thenReturn(value); + when(taskService.getVariableLocal(this.taskId, STRING.getName())).thenReturn(value); + } + + @After + public void after() { + Mockito.reset(taskService); + } + + @Test + public void testSet() { + CamundaBpmData + .writer(taskService, taskId) + .set(STRING, "value"); + verify(taskService).setVariable(this.taskId, STRING.getName(), Variables.stringValue("value")); + } + + @Test + public void testSetLocal() { + CamundaBpmData.writer(taskService, taskId) + .setLocal(STRING, "value"); + verify(taskService).setVariableLocal(this.taskId, STRING.getName(), Variables.stringValue("value")); + } + + @Test + public void testRemove() { + CamundaBpmData + .writer(taskService, taskId) + .remove(STRING); + verify(taskService).removeVariable(this.taskId, STRING.getName()); + } + + @Test + public void testRemoveLocal() { + CamundaBpmData.writer(taskService, taskId) + .removeLocal(STRING); + verify(taskService).removeVariableLocal(this.taskId, STRING.getName()); + } + +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/VariableMapWriterTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/VariableMapWriterTest.java new file mode 100644 index 00000000..bbb68cad --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/VariableMapWriterTest.java @@ -0,0 +1,32 @@ +package io.holunda.camunda.bpm.data.writer; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.engine.variable.VariableMap; +import org.camunda.bpm.engine.variable.Variables; +import org.junit.Test; + +public class VariableMapWriterTest { + + private static final VariableFactory STRING = CamundaBpmData.stringVariable("myString"); + + private final VariableMap variables = Variables.createVariables(); + + @Test + public void testSet() { + CamundaBpmData.writer(variables) + .set(STRING, "value"); + assertThat(variables.get(STRING.getName())).isEqualTo("value"); + } + + @Test + public void testRemove() { + STRING.on(variables).set("value"); + CamundaBpmData.writer(variables) + .remove(STRING); + assertThat(variables).isEmpty(); + } + +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/VariableScopeWriterTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/VariableScopeWriterTest.java new file mode 100644 index 00000000..b59535e2 --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/writer/VariableScopeWriterTest.java @@ -0,0 +1,54 @@ +package io.holunda.camunda.bpm.data.writer; + +import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; +import static org.assertj.core.api.Assertions.assertThat; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.factory.VariableFactory; +import org.camunda.bpm.extension.mockito.delegate.DelegateExecutionFake; +import org.junit.Test; + +public class VariableScopeWriterTest { + + private static final VariableFactory STRING = stringVariable("myString"); + + @Test + public void testSet() { + DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); + + CamundaBpmData + .writer(execution) + .set(STRING, "value") + .variables(); + assertThat(execution.getVariable(STRING.getName())).isEqualTo("value"); + } + + @Test + public void testSetLocal() { + DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); + CamundaBpmData + .writer(execution) + .setLocal(STRING, "value"); + assertThat(execution.getVariableLocal(STRING.getName())).isEqualTo("value"); + } + + @Test + public void testRemove() { + DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); + STRING.on(execution).set("value"); + CamundaBpmData.writer(execution) + .remove(STRING); + assertThat(execution.getVariableNames()).isEmpty(); + } + + @Test + public void testRemoveLocal() { + DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); + STRING.on(execution).setLocal("value"); + CamundaBpmData + .writer(execution) + .removeLocal(STRING); + assertThat(execution.getVariableNames()).isEmpty(); + } + +} diff --git a/extension/src/test/kotlin/ExtensionTestRoot.kt b/extension/core/src/test/kotlin/ExtensionTestRoot.kt similarity index 100% rename from extension/src/test/kotlin/ExtensionTestRoot.kt rename to extension/core/src/test/kotlin/ExtensionTestRoot.kt diff --git a/extension/core/src/test/kotlin/VariablesGuardTest.kt b/extension/core/src/test/kotlin/VariablesGuardTest.kt new file mode 100644 index 00000000..3d854985 --- /dev/null +++ b/extension/core/src/test/kotlin/VariablesGuardTest.kt @@ -0,0 +1,37 @@ +package io.holunda.camunda.bpm.data + +import io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable +import io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.exists +import io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.hasOneOfValues +import io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.hasValue +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class VariablesGuardTest { + + val FOO = stringVariable("foo") + val c1 = exists(FOO) + val c2 = hasValue(FOO, "bar") + val c3 = hasOneOfValues(FOO, setOf("bar", "baz")) + + @Test + fun equals() { + val g1 = VariablesGuard(c1) + val g2 = VariablesGuard(listOf(c2, c3)) + val g3 = VariablesGuard(listOf(c2, c3)) + + assertThat(g1).isNotEqualTo(g2) + + assertThat(g2).isNotSameAs(g3) + assertThat(g2).isEqualTo(g3) + } + + @Test + fun fromExisting() { + val g1 = VariablesGuard.EMPTY + val g2 = g1.fromExisting(c1).fromExisting(c2).fromExisting(c3) + assertThat(g2).isEqualTo(VariablesGuard(listOf(c1, c2, c3))) + + } +} \ No newline at end of file diff --git a/extension/core/src/test/kotlin/acl/ACLTest.kt b/extension/core/src/test/kotlin/acl/ACLTest.kt new file mode 100644 index 00000000..163fdab1 --- /dev/null +++ b/extension/core/src/test/kotlin/acl/ACLTest.kt @@ -0,0 +1,166 @@ +package io.holunda.camunda.bpm.data.acl + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.acl.transform.VariableMapTransformer +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import io.holunda.camunda.bpm.data.guard.condition.* +import org.assertj.core.api.Assertions.assertThat +import org.camunda.bpm.engine.ProcessEngineConfiguration +import org.camunda.bpm.engine.RuntimeService +import org.camunda.bpm.engine.TaskService +import org.camunda.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration +import org.camunda.bpm.engine.test.Deployment +import org.camunda.bpm.engine.test.ProcessEngineRule +import org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests +import org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.task +import org.camunda.bpm.engine.test.mock.MockExpressionManager +import org.camunda.bpm.engine.variable.VariableMap +import org.camunda.bpm.extension.mockito.CamundaMockito +import org.junit.Rule +import org.junit.Test + +@Deployment(resources = ["eventBasedSubprocess_no_transientMapping.bpmn", "eventBasedSubprocess_with_transientMapping.bpmn"]) +class TransientVariableMappingListenerTest { + + @Suppress("RedundantVisibilityModifier") + @get: Rule + public val camunda = camunda() + + @Test + fun `NO ACL signal sub-process with variables sets variables on processInstance`() { + + // given + val processInstance = camunda.runtimeService.startProcessInstanceByKey("eventBasedSubprocess_no_transientMapping") + BpmnAwareTests.assertThat(processInstance).isWaitingAt("event_wait_forever") + + // when + val variables = CamundaBpmData.builder().set(FOO, "bar").build() + camunda.runtimeService + .createSignalEvent("startSubProcess_" + processInstance.id) + .setVariables(variables) + .send() + + // then + FOO.hasValue("bar").assertFor(camunda.taskService, task().id) + FOO.hasValue("bar").assertFor(camunda.runtimeService, processInstance.id) + } + + @Test + fun `ACL signal sub-process with variables does not set variables on processInstance`() { + + // given + CamundaMockito.registerInstance("mapper", ACL_LR.getExecutionListener()) + + val processInstance = camunda.runtimeService.startProcessInstanceByKey( + "eventBasedSubprocess_with_transientMapping" + ) + BpmnAwareTests.assertThat(processInstance).isWaitingAt("event_wait_forever") + // when + // Here the magic happens: all variables are wrapped in one transient variable + val variables = ACL_LR.wrap(CamundaBpmData.builder().set(FOO, "bar").build()) + camunda.runtimeService + .createSignalEvent("startSubProcess_" + processInstance.id) + .setVariables(variables) + .send() + + // then + // global scope + FOO.notExists().assertFor(camunda.runtimeService, processInstance.id) + // local scope + FOO.hasValue("bar").assertFor(camunda.taskService, task().id) + } + + @Test + fun `ACL signal sub-process with variables passes guard sets does not set variables on process instance`() { + + // given + CamundaMockito.registerInstance("mapper", ACL_GTLR.getExecutionListener()) + + val processInstance = camunda.runtimeService.startProcessInstanceByKey( + "eventBasedSubprocess_with_transientMapping" + ) + BpmnAwareTests.assertThat(processInstance).isWaitingAt("event_wait_forever") + // when + // Here the magic happens: all variables are wrapped in one transient variable + val variables = ACL_GTLR.checkAndWrap( + CamundaBpmData.builder() + .set(FOO, "bar") + .set(BAZ, 42L) + .build() + ) + // only one transient variable inside. + assertThat(variables).containsOnlyKeys("transient_acl") + + camunda.runtimeService + .createSignalEvent("startSubProcess_" + processInstance.id) + .setVariables(variables) + .send() + + // then + // global scope + FOO.notExists().assertFor(camunda.runtimeService, processInstance.id) + // local scope + FOO.hasValue("bar").assertFor(camunda.taskService, task().id) + } + + companion object { + + private val FOO = CamundaBpmData.stringVariable("foo") + private val BAZ = CamundaBpmData.longVariable("baz") + private val BAZ_INTERNAL = CamundaBpmData.longVariable("baz__int") + + private val ACL_LR = CamundaBpmDataMapper.identityReplace("transient", true) + + /** + * This demonstrates the power of the Anti-Corruption-Layer. + * + * The warp method will check the pre-conditions and create the transient representation. + * The ACL is attached as an execution listener to the signal and verifies the pre-condition, + * and then performs a transformation of variables. + * + * The conditions are: + * - variable foo eís set + * - variable baz is set and its value is greater than 40L + * + * The transformations are: + * - foo -> foo + * - baz / 2 -> baz_internal + */ + private val ACL_GTLR = CamundaBpmDataACL.guardTransformingLocalReplace( + variableName = "transient_acl", + variablesGuard = VariablesGuard( + listOf( + BAZ.matches { it > 40L }, + FOO.exists()) + ), + variableMapTransformer = object : VariableMapTransformer { + override fun transform(variableMap: VariableMap): VariableMap { + return CamundaBpmData + .builder() + .set(BAZ_INTERNAL, BAZ.from(variableMap).get() / 2L) + .set(FOO, FOO.from(variableMap).get()) + .build() + } + } + ) + + private fun camunda(): ProcessEngineRule { + return ProcessEngineRule( + object : StandaloneInMemProcessEngineConfiguration() { + init { + history = ProcessEngineConfiguration.HISTORY_FULL + databaseSchemaUpdate = ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE + jobExecutorActivate = false + expressionManager = MockExpressionManager() + } + }.buildProcessEngine()) + } + } + +} + +fun VariableGuardCondition.assertFor(taskService: TaskService, taskId: String) = + assertThat(this.evaluate(taskService, taskId)).isEmpty() + +fun VariableGuardCondition.assertFor(runtimeService: RuntimeService, processInstanceId: String) = + assertThat(this.evaluate(runtimeService, processInstanceId)).isEmpty() diff --git a/extension/core/src/test/kotlin/acl/AntiCorruptionLayerTest.kt b/extension/core/src/test/kotlin/acl/AntiCorruptionLayerTest.kt new file mode 100644 index 00000000..f246a5cc --- /dev/null +++ b/extension/core/src/test/kotlin/acl/AntiCorruptionLayerTest.kt @@ -0,0 +1,140 @@ +package io.holunda.camunda.bpm.data.acl + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.CamundaBpmData.customVariable +import io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable +import io.holunda.camunda.bpm.data.acl.transform.IdentityVariableMapTransformer +import io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.exists +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import io.holunda.camunda.bpm.data.guard.condition.matches +import org.assertj.core.api.Assertions.assertThat +import org.camunda.bpm.engine.ProcessEngineConfiguration +import org.camunda.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration +import org.camunda.bpm.engine.impl.context.Context +import org.camunda.bpm.engine.test.mock.MockExpressionManager +import org.camunda.bpm.engine.variable.VariableMap +import org.camunda.bpm.engine.variable.value.ObjectValue +import org.camunda.bpm.extension.mockito.delegate.DelegateExecutionFake +import org.camunda.bpm.extension.mockito.delegate.DelegateTaskFake +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +class AntiCorruptionLayerTest { + + val FOO = stringVariable("foo") + val BAZ = stringVariable("baz") + + val TRANSIENT = customVariable("__transient", VariableMap::class.java) + + val MY_ACL = CamundaBpmDataACL.guardTransformingLocalReplace( + TRANSIENT.name, + VariablesGuard(listOf(exists(FOO), BAZ.matches { it.length > 2 })), + IdentityVariableMapTransformer + ) + + @Suppress("RedundantVisibilityModifier") + @get: Rule + public val expectedException: ExpectedException = ExpectedException.none() + + + @Test + fun `should wrap variables directly`() { + + val vars = CamundaBpmData.builder().set(FOO, "foo1").set(BAZ, "baz2").build() + + val wrapped = AntiCorruptionLayer.wrapAsTypedTransientVariable(TRANSIENT.name, vars) + assertThat(wrapped).containsOnlyKeys(TRANSIENT.name) + assertThat(wrapped.getValueTyped(TRANSIENT.name).isTransient).isTrue() + assertThat(TRANSIENT.from(wrapped).get()).isEqualTo(vars) + } + + @Test + fun `should wrap variables using ACL`() { + + val vars = CamundaBpmData.builder().set(FOO, "foo1").set(BAZ, "baz2").build() + + val wrapped = MY_ACL.wrap(vars) + assertThat(wrapped).containsOnlyKeys(TRANSIENT.name) + assertThat(wrapped.getValueTyped(TRANSIENT.name).isTransient).isTrue() + assertThat(TRANSIENT.from(wrapped).get()).isEqualTo(vars) + } + + @Test + fun `should check and wrap variables`() { + val vars = CamundaBpmData.builder().set(FOO, "foo1").set(BAZ, "baz2").build() + val wrapped = MY_ACL.checkAndWrap(vars) + + assertThat(wrapped).containsOnlyKeys(TRANSIENT.name) + assertThat(wrapped.getValueTyped(TRANSIENT.name).isTransient).isTrue() + assertThat(TRANSIENT.from(wrapped).get()).isEqualTo(vars) + } + + @Test + fun `should fail checking and wrapping variables`() { + expectedException.expectMessage("ACL Guard Error:\n\tExpecting variable 'baz' to match the condition, but its value 'ba' has not.") + + val vars = CamundaBpmData.builder().set(FOO, "foo1").set(BAZ, "ba").build() + MY_ACL.checkAndWrap(vars) + } + + @Test + fun `should act as execution listener`() { + + setupEngineConfiguration() + + val listener = MY_ACL.getExecutionListener() + val wrappedVars = MY_ACL.checkAndWrap( + CamundaBpmData + .builder() + .set(FOO, "foo1") + .set(BAZ, "baz2") + .build() + ) + + val fake = DelegateExecutionFake().withVariables(wrappedVars) + listener.notify(fake) + + assertThat(fake.hasVariableLocal(FOO.name)).isTrue() + assertThat(fake.hasVariableLocal(BAZ.name)).isTrue() + + } + + @Test + fun `should act as task listener`() { + + setupEngineConfiguration() + + val listener = MY_ACL.getTaskListener() + val wrappedVars = MY_ACL.checkAndWrap( + CamundaBpmData + .builder() + .set(FOO, "foo1") + .set(BAZ, "baz2") + .build() + ) + + val fake = DelegateTaskFake().withVariables(wrappedVars) + listener.notify(fake) + + assertThat(fake.hasVariableLocal(FOO.name)).isTrue() + assertThat(fake.hasVariableLocal(BAZ.name)).isTrue() + + } + + + private fun setupEngineConfiguration() { + val config = object : StandaloneInMemProcessEngineConfiguration() { + init { + history = ProcessEngineConfiguration.HISTORY_FULL + databaseSchemaUpdate = ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE + jobExecutorActivate = false + expressionManager = MockExpressionManager() + javaSerializationFormatEnabled = true + } + } + + Context.setProcessEngineConfiguration(config) + } + +} \ No newline at end of file diff --git a/extension/core/src/test/kotlin/acl/CamundaBpmDataACLTest.kt b/extension/core/src/test/kotlin/acl/CamundaBpmDataACLTest.kt new file mode 100644 index 00000000..c174de80 --- /dev/null +++ b/extension/core/src/test/kotlin/acl/CamundaBpmDataACLTest.kt @@ -0,0 +1,73 @@ +package io.holunda.camunda.bpm.data.acl + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.acl.apply.GlobalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.apply.GlobalScopeReplaceStrategyTest +import io.holunda.camunda.bpm.data.acl.apply.LocalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.transform.IdentityVariableMapTransformer +import io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards.exists +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import org.assertj.core.api.Assertions.assertThat +import org.camunda.bpm.engine.variable.VariableMap +import org.junit.Test + +class CamundaBpmDataACLTest { + + val TRANSIENT_VAR = CamundaBpmData.customVariable("__transient__", VariableMap::class.java) + val FOO = CamundaBpmData.stringVariable("foo") + + @Test + fun `should create guardTransformingLocalReplace`() { + val acl = CamundaBpmDataACL.guardTransformingLocalReplace( + TRANSIENT_VAR.name, + VariablesGuard(exists(FOO)), + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard(exists(FOO))) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(LocalScopeReplaceStrategy) + } + + @Test + fun `should create guardTransformingGlobalReplace`() { + val acl = CamundaBpmDataACL.guardTransformingGlobalReplace( + TRANSIENT_VAR.name, + VariablesGuard(exists(FOO)), + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard(exists(FOO))) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(GlobalScopeReplaceStrategy) + } + + @Test + fun `should create guardTransformingReplace global`() { + val acl = CamundaBpmDataACL.guardTransformingReplace( + TRANSIENT_VAR.name, + false, + VariablesGuard(exists(FOO)), + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard(exists(FOO))) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(GlobalScopeReplaceStrategy) + } + + @Test + fun `should create guardTransformingReplace local`() { + val acl = CamundaBpmDataACL.guardTransformingReplace( + TRANSIENT_VAR.name, + true, + VariablesGuard(exists(FOO)), + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard(exists(FOO))) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(LocalScopeReplaceStrategy) + } + +} \ No newline at end of file diff --git a/extension/core/src/test/kotlin/acl/CamundaBpmDataMapperTest.kt b/extension/core/src/test/kotlin/acl/CamundaBpmDataMapperTest.kt new file mode 100644 index 00000000..967e93a6 --- /dev/null +++ b/extension/core/src/test/kotlin/acl/CamundaBpmDataMapperTest.kt @@ -0,0 +1,114 @@ +package io.holunda.camunda.bpm.data.acl + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.acl.apply.GlobalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.apply.GlobalScopeReplaceStrategyTest +import io.holunda.camunda.bpm.data.acl.apply.LocalScopeReplaceStrategy +import io.holunda.camunda.bpm.data.acl.transform.IdentityVariableMapTransformer +import io.holunda.camunda.bpm.data.guard.VariablesGuard +import org.assertj.core.api.Assertions.assertThat +import org.camunda.bpm.engine.variable.VariableMap +import org.junit.Test + +class CamundaBpmDataMapperTest { + + val TRANSIENT_VAR = CamundaBpmData.customVariable("__transient__", VariableMap::class.java) + + @Test + fun `should create transformingLocalReplace`() { + val acl = CamundaBpmDataMapper.transformingLocalReplace( + TRANSIENT_VAR.name, + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(LocalScopeReplaceStrategy) + } + + @Test + fun `should create transformingGlobalReplace`() { + val acl = CamundaBpmDataMapper.transformingGlobalReplace( + TRANSIENT_VAR.name, + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(GlobalScopeReplaceStrategy) + } + + @Test + fun `should create transformingReplace local`() { + val acl = CamundaBpmDataMapper.transformingReplace( + TRANSIENT_VAR.name, + true, + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(LocalScopeReplaceStrategy) + } + + @Test + fun `should create transformingReplace global`() { + val acl = CamundaBpmDataMapper.transformingReplace( + TRANSIENT_VAR.name, + false, + IdentityVariableMapTransformer + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(GlobalScopeReplaceStrategy) + } + + + @Test + fun `should create identityLocalReplace`() { + val acl = CamundaBpmDataMapper.identityLocalReplace( + TRANSIENT_VAR.name + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(LocalScopeReplaceStrategy) + } + + @Test + fun `should create identityGlobalReplace`() { + val acl = CamundaBpmDataMapper.identityGlobalReplace( + TRANSIENT_VAR.name + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(GlobalScopeReplaceStrategy) + } + + @Test + fun `should create identityGlobalReplace local`() { + val acl = CamundaBpmDataMapper.identityReplace( + TRANSIENT_VAR.name, + true + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(LocalScopeReplaceStrategy) + } + + @Test + fun `should create identityGlobalReplace global`() { + val acl = CamundaBpmDataMapper.identityReplace( + TRANSIENT_VAR.name, + false + ) + assertThat(acl.precondition).isEqualTo(VariablesGuard.EMPTY) + assertThat(acl.variableMapTransformer).isEqualTo(IdentityVariableMapTransformer) + assertThat(acl.factory).isEqualTo(TRANSIENT_VAR) + assertThat(acl.valueApplicationStrategy).isEqualTo(GlobalScopeReplaceStrategy) + } + +} \ No newline at end of file diff --git a/extension/core/src/test/kotlin/acl/apply/GlobalScopeReplaceStrategyTest.kt b/extension/core/src/test/kotlin/acl/apply/GlobalScopeReplaceStrategyTest.kt new file mode 100644 index 00000000..91686f8e --- /dev/null +++ b/extension/core/src/test/kotlin/acl/apply/GlobalScopeReplaceStrategyTest.kt @@ -0,0 +1,26 @@ +package io.holunda.camunda.bpm.data.acl.apply + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable +import org.camunda.bpm.engine.delegate.DelegateExecution +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions + +class GlobalScopeReplaceStrategyTest { + + val FOO = stringVariable("foo") + + @Test + fun `should apply global`() { + val variables = CamundaBpmData.builder().set(FOO, "bar").build() + val executionMock = Mockito.mock(DelegateExecution::class.java) + + GlobalScopeReplaceStrategy.apply(variables, executionMock) + + verify(executionMock, Mockito.never()).setVariablesLocal(Mockito.any()) + verify(executionMock).setVariables(variables) + verifyNoMoreInteractions(executionMock) + } +} \ No newline at end of file diff --git a/extension/core/src/test/kotlin/acl/apply/LocalScopeReplaceStrategyTest.kt b/extension/core/src/test/kotlin/acl/apply/LocalScopeReplaceStrategyTest.kt new file mode 100644 index 00000000..be6b829e --- /dev/null +++ b/extension/core/src/test/kotlin/acl/apply/LocalScopeReplaceStrategyTest.kt @@ -0,0 +1,24 @@ +package io.holunda.camunda.bpm.data.acl.apply + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable +import org.camunda.bpm.engine.delegate.DelegateExecution +import org.junit.Test +import org.mockito.Mockito.* + +class LocalScopeReplaceStrategyTest { + + val FOO = stringVariable("foo") + + @Test + fun `should apply local`() { + val variables = CamundaBpmData.builder().set(FOO, "bar").build() + val executionMock = mock(DelegateExecution::class.java) + + LocalScopeReplaceStrategy.apply(variables, executionMock) + + verify(executionMock, never()).setVariables(any()) + verify(executionMock).setVariablesLocal(variables) + verifyNoMoreInteractions(executionMock) + } +} \ No newline at end of file diff --git a/extension/core/src/test/kotlin/acl/transform/IdentityVariableMapTransformerTest.kt b/extension/core/src/test/kotlin/acl/transform/IdentityVariableMapTransformerTest.kt new file mode 100644 index 00000000..1592acc2 --- /dev/null +++ b/extension/core/src/test/kotlin/acl/transform/IdentityVariableMapTransformerTest.kt @@ -0,0 +1,18 @@ +package io.holunda.camunda.bpm.data.acl.transform + +import io.holunda.camunda.bpm.data.CamundaBpmData +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class IdentityVariableMapTransformerTest { + + @Test + fun `should pass the input to output`() { + + val vars = CamundaBpmData.builder().build() + + assertThat(IdentityVariableMapTransformer.transform(vars)) + .isEqualTo(vars) // equals comparison + .isSameAs(vars) // == comparison + } +} \ No newline at end of file diff --git a/extension/core/src/test/kotlin/guard/CamundaBpmDataGuardsTest.kt b/extension/core/src/test/kotlin/guard/CamundaBpmDataGuardsTest.kt new file mode 100644 index 00000000..bed54891 --- /dev/null +++ b/extension/core/src/test/kotlin/guard/CamundaBpmDataGuardsTest.kt @@ -0,0 +1,186 @@ +package io.holunda.camunda.bpm.data.guard + +import io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable +import io.holunda.camunda.bpm.data.guard.condition.* +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.util.* +import java.util.function.Function + +class CamundaBpmDataGuardsTest { + + val FOO = stringVariable("foo") + + @Test + fun `should construct exists condition`() { + val condition = CamundaBpmDataGuards.exists(FOO) + assertThat(condition).isInstanceOf(VariableExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + } + + @Test + fun `should construct exists local condition`() { + val condition = CamundaBpmDataGuards.exists(FOO, true) + assertThat(condition).isInstanceOf(VariableExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + } + + @Test + fun `should construct notExists condition`() { + val condition = CamundaBpmDataGuards.notExists(FOO) + assertThat(condition).isInstanceOf(VariableNotExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + } + + @Test + fun `should construct notExists local condition`() { + val condition = CamundaBpmDataGuards.notExists(FOO, true) + assertThat(condition).isInstanceOf(VariableNotExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + } + + @Test + fun `should construct hasValue condition`() { + val condition = CamundaBpmDataGuards.hasValue(FOO, "val") + assertThat(condition).isInstanceOf(VariableValueGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + assertThat(condition.value).isEqualTo("val") + } + + @Test + fun `should construct hasValue local condition`() { + val condition = CamundaBpmDataGuards.hasValue(FOO, "valLocal", true) + assertThat(condition).isInstanceOf(VariableValueGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + assertThat(condition.value).isEqualTo("valLocal") + } + + @Test + fun `should construct hasOneOfValues condition`() { + val condition = CamundaBpmDataGuards.hasOneOfValues(FOO, setOf("val1", "val2") ) + assertThat(condition).isInstanceOf(VariableValueOneOfGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + assertThat(condition.values).containsExactlyInAnyOrder("val1", "val2") + } + + @Test + fun `should construct hasOneOfValues local condition`() { + val condition = CamundaBpmDataGuards.hasOneOfValues(FOO, setOf("valLocal1", "valLocal2"), true) + assertThat(condition).isInstanceOf(VariableValueOneOfGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + assertThat(condition.values).containsExactlyInAnyOrder("valLocal1", "valLocal2") + } + + @Test + fun `should construct matches condition`() { + val condition = CamundaBpmDataGuards.matches(FOO, Function { it == "special_val" }) + assertThat(condition).isInstanceOf(VariableMatchesGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + assertThat(condition.evaluate(Optional.of("special_val"))).isEmpty() + } + + @Test + fun `should construct matches local condition`() { + val condition = CamundaBpmDataGuards.matches(FOO, Function { it == "special_val_local" }, true) + assertThat(condition).isInstanceOf(VariableMatchesGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + assertThat(condition.evaluate(Optional.of("special_val_local"))).isEmpty() + } + + @Test + fun `kotlin should construct exists condition`() { + val condition = FOO.exists() + assertThat(condition).isInstanceOf(VariableExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + } + + @Test + fun `kotlin should construct exists local condition`() { + val condition = FOO.exists(true) + assertThat(condition).isInstanceOf(VariableExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + } + + @Test + fun `kotlin should construct notExists condition`() { + val condition = FOO.notExists() + assertThat(condition).isInstanceOf(VariableNotExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + } + + @Test + fun `kotlin should construct notExists local condition`() { + val condition = FOO.notExists(true) + assertThat(condition).isInstanceOf(VariableNotExistsGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + } + + @Test + fun `kotlin should construct hasValue condition`() { + val condition = FOO.hasValue("val") + assertThat(condition).isInstanceOf(VariableValueGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + assertThat(condition.value).isEqualTo("val") + } + + @Test + fun `kotlin should construct hasValue local condition`() { + val condition = FOO.hasValue("valLocal", true) + assertThat(condition).isInstanceOf(VariableValueGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + assertThat(condition.value).isEqualTo("valLocal") + } + + @Test + fun `kotlin should construct hasOneOfValues condition`() { + val condition = FOO.hasOneOfValues(setOf("val1", "val2") ) + assertThat(condition).isInstanceOf(VariableValueOneOfGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + assertThat(condition.values).containsExactlyInAnyOrder("val1", "val2") + } + + @Test + fun `kotlin should construct hasOneOfValues local condition`() { + val condition = FOO.hasOneOfValues(setOf("valLocal1", "valLocal2"), true) + assertThat(condition).isInstanceOf(VariableValueOneOfGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + assertThat(condition.values).containsExactlyInAnyOrder("valLocal1", "valLocal2") + } + + @Test + fun `kotlin should construct matches condition`() { + val condition = FOO.matches { it == "special_val" } + assertThat(condition).isInstanceOf(VariableMatchesGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(false) + assertThat(condition.evaluate(Optional.of("special_val"))).isEmpty() + } + + @Test + fun `kotlin should construct matches local condition`() { + val condition = FOO.matches(true){ it == "special_val_local" } + assertThat(condition).isInstanceOf(VariableMatchesGuardCondition::class.java) + assertThat(condition.variableFactory).isEqualTo(FOO) + assertThat(condition.local).isEqualTo(true) + assertThat(condition.evaluate(Optional.of("special_val_local"))).isEmpty() + } + +} \ No newline at end of file diff --git a/extension/src/test/kotlin/guard/VariableGuardConditionTest.kt b/extension/core/src/test/kotlin/guard/VariableGuardConditionTest.kt similarity index 100% rename from extension/src/test/kotlin/guard/VariableGuardConditionTest.kt rename to extension/core/src/test/kotlin/guard/VariableGuardConditionTest.kt diff --git a/extension/src/test/kotlin/guard/integration/GuardExecutionListenerTest.kt b/extension/core/src/test/kotlin/guard/integration/GuardExecutionListenerTest.kt similarity index 83% rename from extension/src/test/kotlin/guard/integration/GuardExecutionListenerTest.kt rename to extension/core/src/test/kotlin/guard/integration/GuardExecutionListenerTest.kt index 2696a046..5a5e27fb 100644 --- a/extension/src/test/kotlin/guard/integration/GuardExecutionListenerTest.kt +++ b/extension/core/src/test/kotlin/guard/integration/GuardExecutionListenerTest.kt @@ -12,6 +12,7 @@ val ORDER_REFERENCE = stringVariable("orderReference") class GuardExecutionListenerTest { + @Suppress("RedundantVisibilityModifier") @get: Rule public val thrown = ExpectedException.none() @@ -20,7 +21,7 @@ class GuardExecutionListenerTest { val delegate = DelegateExecutionFake().withId("4711").withCurrentActivityName("some") ORDER_REFERENCE.on(delegate).set("1") - val listener = MyListener2(true) + val listener = createListener(true) listener.notify(delegate) // nothing to do here @@ -32,7 +33,7 @@ class GuardExecutionListenerTest { val delegate = DelegateExecutionFake().withId("4711").withCurrentActivityName("some") ORDER_REFERENCE.on(delegate).set("2") - val listener = MyListener2(false) + val listener = createListener(false) listener.notify(delegate) // nothing to do here @@ -46,12 +47,12 @@ class GuardExecutionListenerTest { thrown.expectMessage("Guard violated by execution '${delegate.id}' in activity '${delegate.currentActivityName}'") - val listener = MyListener2(true) + val listener = createListener(true) listener.notify(delegate) // nothing to do here assertThat(true).isTrue() } - class MyListener2(throwE: Boolean = true) : AbstractGuardExecutionListener(listOf(ORDER_REFERENCE.hasValue("1")), throwE) + private fun createListener(throwE: Boolean = true) = DefaultGuardExecutionListener(listOf(ORDER_REFERENCE.hasValue("1")), throwE) } \ No newline at end of file diff --git a/extension/src/test/kotlin/guard/integration/GuardTaskListenerTest.kt b/extension/core/src/test/kotlin/guard/integration/GuardTaskListenerTest.kt similarity index 83% rename from extension/src/test/kotlin/guard/integration/GuardTaskListenerTest.kt rename to extension/core/src/test/kotlin/guard/integration/GuardTaskListenerTest.kt index bf79e6be..35d88e83 100644 --- a/extension/src/test/kotlin/guard/integration/GuardTaskListenerTest.kt +++ b/extension/core/src/test/kotlin/guard/integration/GuardTaskListenerTest.kt @@ -12,6 +12,7 @@ val ORDER_ID = stringVariable("orderID") class GuardTaskListenerTest { + @Suppress("RedundantVisibilityModifier") @get: Rule public val thrown = ExpectedException.none() @@ -20,7 +21,7 @@ class GuardTaskListenerTest { val delegateTask = DelegateTaskFake().withId("4711") ORDER_ID.on(delegateTask).set("1") - val listener = MyListener(true) + val listener = createListener(true) listener.notify(delegateTask) // nothing to do here @@ -32,7 +33,7 @@ class GuardTaskListenerTest { val delegateTask = DelegateTaskFake().withId("4711").withName("task name") ORDER_ID.on(delegateTask).set("2") - val listener = MyListener(false) + val listener = createListener(false) listener.notify(delegateTask) // nothing to do here @@ -46,12 +47,12 @@ class GuardTaskListenerTest { thrown.expectMessage("Guard violated in task '${delegateTask.name}' (taskId: '${delegateTask.id}')") - val listener = MyListener(true) + val listener = createListener(true) listener.notify(delegateTask) // nothing to do here assertThat(true).isTrue() } - class MyListener(throwE: Boolean = true) : AbstractGuardTaskListener(listOf(ORDER_ID.hasValue("1")), throwE) + private fun createListener(throwE: Boolean = true) = DefaultGuardTaskListener(listOf(ORDER_ID.hasValue("1")), throwE) } \ No newline at end of file diff --git a/extension/core/src/test/kotlin/guard/integration/GuardViolationExceptionTest.kt b/extension/core/src/test/kotlin/guard/integration/GuardViolationExceptionTest.kt new file mode 100644 index 00000000..c2211f2a --- /dev/null +++ b/extension/core/src/test/kotlin/guard/integration/GuardViolationExceptionTest.kt @@ -0,0 +1,27 @@ +package io.holunda.camunda.bpm.data.guard.integration + +import io.holunda.camunda.bpm.data.CamundaBpmData +import io.holunda.camunda.bpm.data.guard.CamundaBpmDataGuards +import io.holunda.camunda.bpm.data.guard.GuardViolation +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.util.* + +class GuardViolationExceptionTest { + + val FOO = CamundaBpmData.stringVariable("foo") + val c1 = CamundaBpmDataGuards.exists(FOO) + val c2 = CamundaBpmDataGuards.hasValue(FOO, "bar") + + @Test + fun buildMessage() { + + val expected = "reason\n\tnot exists,\n\twrong VAL" + val ex = GuardViolationException(reason = "reason", violations = listOf( + GuardViolation(c1, Optional.empty(), "not exists"), + GuardViolation(c2, Optional.of("VAL"), "wrong VAL") + )) + + assertThat(ex.message).isEqualTo(expected) + } +} \ No newline at end of file diff --git a/extension/core/src/test/resources/eventBasedSubprocess_no_transientMapping.bpmn b/extension/core/src/test/resources/eventBasedSubprocess_no_transientMapping.bpmn new file mode 100644 index 00000000..bf987e31 --- /dev/null +++ b/extension/core/src/test/resources/eventBasedSubprocess_no_transientMapping.bpmn @@ -0,0 +1,104 @@ + + + + + Flow_0aasot7 + + + + Flow_1j6581e + + + + Flow_0aasot7 + Flow_1j6581e + + + + + Flow_07p4aup + + + + + Flow_07p4aup + Flow_0bscl4e + + + Flow_0bscl4e + + + + + Signal only in running parent instance + + + + While we are waiting here ... some subprocesses will start + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extension/core/src/test/resources/eventBasedSubprocess_with_transientMapping.bpmn b/extension/core/src/test/resources/eventBasedSubprocess_with_transientMapping.bpmn new file mode 100644 index 00000000..477802b3 --- /dev/null +++ b/extension/core/src/test/resources/eventBasedSubprocess_with_transientMapping.bpmn @@ -0,0 +1,118 @@ + + + + + Flow_0aasot7 + + + + Flow_1j6581e + + + + Flow_0aasot7 + Flow_1j6581e + + + + + + + + Flow_07p4aup + + + + + Flow_07p4aup + Flow_0bscl4e + + + Flow_0bscl4e + + + + + + Signal only in running parent instance + + + While we are waiting here ... some subprocesses will start + + + + Listener to map variables + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extension/core/src/test/resources/simplelogger.properties b/extension/core/src/test/resources/simplelogger.properties new file mode 100644 index 00000000..b3fcdde1 --- /dev/null +++ b/extension/core/src/test/resources/simplelogger.properties @@ -0,0 +1,6 @@ +org.slf4j.simpleLogger.defaultLogLevel = info + +org.slf4j.simpleLogger.showShortLogName = true +org.slf4j.simpleLogger.levelInBrackets = true + +org.slf4j.simpleLogger.log.org.camunda.bpm.engine.persistence = warn diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtil.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtil.java deleted file mode 100644 index 07ccbee5..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/ValueWrapperUtil.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter; - -import org.camunda.bpm.engine.variable.value.TypedValue; - -import java.util.Date; - -import static org.camunda.bpm.engine.variable.Variables.stringValue; -import static org.camunda.bpm.engine.variable.Variables.integerValue; -import static org.camunda.bpm.engine.variable.Variables.shortValue; -import static org.camunda.bpm.engine.variable.Variables.longValue; -import static org.camunda.bpm.engine.variable.Variables.dateValue; -import static org.camunda.bpm.engine.variable.Variables.doubleValue; -import static org.camunda.bpm.engine.variable.Variables.untypedValue; -import static org.camunda.bpm.engine.variable.Variables.objectValue; -import static org.camunda.bpm.engine.variable.Variables.booleanValue; - -/** - * Static util methods. - */ -public class ValueWrapperUtil { - - /** - * Hide instantiation. - */ - private ValueWrapperUtil() { - - } - - /** - * Delivers typed value for a given type and value. - * - * @param clazz class of value. - * @param value value to encapsulate. - * @param isTransient transient flag. - * @param type of value. - * - * @return typed value. - * - * @throws IllegalArgumentException if value and clazz are incompatible. - */ - public static TypedValue getTypedValue(Class clazz, Object value, boolean isTransient) { - if (!clazz.isAssignableFrom(value.getClass())) { - throw new IllegalArgumentException("Couldn't create TypedValue for " + clazz.getSimpleName() + " from value " + value); - } - - if (String.class.equals(clazz)) { - return stringValue((String) value, isTransient); - } else if (Boolean.class.equals(clazz)) { - return booleanValue((Boolean) value, isTransient); - } else if (Integer.class.equals(clazz)) { - return integerValue((Integer) value, isTransient); - } else if (Short.class.equals(clazz)) { - return shortValue((Short) value, isTransient); - } else if (Long.class.equals(clazz)) { - return longValue((Long) value, isTransient); - } else if (Date.class.equals(clazz)) { - return dateValue((Date) value, isTransient); - } else if (Double.class.equals(clazz)) { - return doubleValue((Double) value, isTransient); - } else if (Object.class.equals(clazz)) { - return objectValue(value, isTransient).create(); - } else { - // fallback for null-type - return untypedValue(value, isTransient); - } - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/AbstractBasicReadWriteAdapter.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/AbstractBasicReadWriteAdapter.java deleted file mode 100644 index 0b7ee001..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/AbstractBasicReadWriteAdapter.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.basic; - -import io.holunda.camunda.bpm.data.adapter.AbstractReadWriteAdapter; -import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil; -import io.holunda.camunda.bpm.data.adapter.WrongVariableTypeException; -import org.camunda.bpm.engine.variable.value.TypedValue; - -/** - * Base class for all basic read-write-adapter. - * @param variable type. - */ -public abstract class AbstractBasicReadWriteAdapter extends AbstractReadWriteAdapter { - /** - * Variable type. - */ - protected final Class clazz; - - /** - * Constructs the adapter. - * @param variableName name of the variable. - * @param clazz variable type. - */ - public AbstractBasicReadWriteAdapter(String variableName, Class clazz) { - super(variableName); - this.clazz = clazz; - } - - /** - * Retrieves the value or null. - * @param value raw value. - * @return value or null. - */ - @SuppressWarnings("unchecked") - protected T getOrNull(Object value) { - - if (value == null) { - return null; - } - - if (clazz.isAssignableFrom(value.getClass())) { - return (T) value; - } - throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value of " + clazz + " from " + value); - } - - @Override - public TypedValue getTypedValue(Object value, boolean isTransient) { - return ValueWrapperUtil.getTypedValue(clazz, value, isTransient); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterRuntimeService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterRuntimeService.java deleted file mode 100644 index 25a7683a..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterRuntimeService.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.basic; - -import org.camunda.bpm.engine.RuntimeService; - -import java.util.Optional; - -/** - * Read write adapter for runtime service access. - * - * @param type of value. - */ -public class ReadWriteAdapterRuntimeService extends AbstractBasicReadWriteAdapter { - - private final RuntimeService runtimeService; - private final String executionId; - - /** - * Constructs the adapter. - * - * @param runtimeService runtime service to use. - * @param executionId id of the execution to read from and write to. - * @param variableName name of the variable. - * @param clazz class of the variable. - */ - public ReadWriteAdapterRuntimeService(RuntimeService runtimeService, String executionId, String variableName, Class clazz) { - super(variableName, clazz); - this.runtimeService = runtimeService; - this.executionId = executionId; - } - - @Override - public Optional getOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); - } - - @Override - public void set(T value, boolean isTransient) { - runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional getLocalOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); - } - - @Override - public void setLocal(T value, boolean isTransient) { - runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public void remove() { - runtimeService.removeVariable(executionId, variableName); - } - - @Override - public void removeLocal() { - runtimeService.removeVariableLocal(executionId, variableName); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterTaskService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterTaskService.java deleted file mode 100644 index 6e1dabb8..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterTaskService.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.basic; - -import org.camunda.bpm.engine.TaskService; - -import java.util.Optional; - -/** - * Read write adapter for task service access. - * - * @param type of value. - */ -public class ReadWriteAdapterTaskService extends AbstractBasicReadWriteAdapter { - - private final TaskService taskService; - private final String taskId; - - /** - * Constructs the adapter. - * - * @param taskService task service to use. - * @param taskId id of the task to read from and write to. - * @param variableName name of the variable. - * @param clazz class of the variable. - */ - public ReadWriteAdapterTaskService(TaskService taskService, String taskId, String variableName, Class clazz) { - super(variableName, clazz); - this.taskService = taskService; - this.taskId = taskId; - } - - @Override - public Optional getOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); - } - - @Override - public void set(T value, boolean isTransient) { - taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional getLocalOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); - } - - @Override - public void setLocal(T value, boolean isTransient) { - taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public void remove() { - taskService.removeVariable(taskId, variableName); - } - - @Override - public void removeLocal() { - taskService.removeVariableLocal(taskId, variableName); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableMap.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableMap.java deleted file mode 100644 index f73a7e43..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableMap.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.basic; - -import org.camunda.bpm.engine.variable.VariableMap; - -import java.util.Optional; - -/** - * Read-write adapter for variable map. - * - * @param type of value. - */ -public class ReadWriteAdapterVariableMap extends AbstractBasicReadWriteAdapter { - - private final VariableMap variableMap; - - /** - * Constructs the adapter. - * - * @param variableMap variable map to access. - * @param variableName variable to access. - * @param clazz class of variable value. - */ - public ReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class clazz) { - super(variableName, clazz); - this.variableMap = variableMap; - } - - @Override - public Optional getOptional() { - return Optional.ofNullable(getOrNull(variableMap.get(variableName))); - } - - @Override - public void set(T value, boolean isTransient) { - variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional getLocalOptional() { - throw new UnsupportedOperationException("Can't get a local variable on a variable map"); - } - - @Override - public void setLocal(T value, boolean isTransient) { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } - - @Override - public void remove() { - variableMap.remove(variableName); - } - - @Override - public void removeLocal() { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableScope.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableScope.java deleted file mode 100644 index 2a90a0e7..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/basic/ReadWriteAdapterVariableScope.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.basic; - -import org.camunda.bpm.engine.delegate.VariableScope; - -import java.util.Optional; - -/** - * Read-write adapter for variable scope. - * - * @param type of value. - */ -public class ReadWriteAdapterVariableScope extends AbstractBasicReadWriteAdapter { - - private VariableScope variableScope; - - /** - * Constructs the adapter. - * - * @param variableScope variable scope to access. - * @param variableName variable to access. - * @param clazz class of variable value. - */ - public ReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class clazz) { - super(variableName, clazz); - this.variableScope = variableScope; - } - - @Override - public void set(T value, boolean isTransient) { - variableScope.setVariable(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional getLocalOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); - } - - @Override - public void setLocal(T value, boolean isTransient) { - variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional getOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); - } - - @Override - public void remove() { - variableScope.removeVariable(variableName); - } - - @Override - public void removeLocal() { - variableScope.removeVariableLocal(variableName); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.java deleted file mode 100644 index 1c60f406..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.list; - -import io.holunda.camunda.bpm.data.adapter.AbstractReadWriteAdapter; -import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil; -import io.holunda.camunda.bpm.data.adapter.WrongVariableTypeException; -import org.camunda.bpm.engine.variable.value.TypedValue; - -import java.util.Collections; -import java.util.List; - -/** - * Base class for all list read-write adapter. - * - * @param member type. - */ -public abstract class AbstractListReadWriteAdapter extends AbstractReadWriteAdapter> { - - /** - * Member class. - */ - protected final Class memberClazz; - - /** - * Constructs the adapter. - * - * @param variableName name of variable. - * @param memberClazz member class. - */ - public AbstractListReadWriteAdapter(String variableName, Class memberClazz) { - super(variableName); - this.memberClazz = memberClazz; - } - - /** - * Read the value of null. - * - * @param value raw value. - * - * @return list or null. - */ - @SuppressWarnings("unchecked") - protected List getOrNull(Object value) { - if (value == null) { - return null; - } - - if (List.class.isAssignableFrom(value.getClass())) { - List valueAsList = (List) value; - if (valueAsList.isEmpty()) { - return Collections.emptyList(); - } else { - if (memberClazz.isAssignableFrom(valueAsList.iterator().next().getClass())) { - return (List) valueAsList; - } else { - throw new WrongVariableTypeException("Error reading " + variableName + ": Wrong list type detected, expected " + memberClazz.getName() + ", but was not found in " + valueAsList); - } - } - } - - throw new WrongVariableTypeException("Error reading " + variableName + ": Couldn't read value of type List from " + value); - } - - @Override - public TypedValue getTypedValue(Object value, boolean isTransient) { - return ValueWrapperUtil.getTypedValue(List.class, value, isTransient); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterRuntimeService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterRuntimeService.java deleted file mode 100644 index a316820f..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterRuntimeService.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.list; - -import org.camunda.bpm.engine.RuntimeService; - -import java.util.List; -import java.util.Optional; - -/** - * Read write adapter for runtime service access. - * - * @param type of value. - */ -public class ListReadWriteAdapterRuntimeService extends AbstractListReadWriteAdapter { - - private final RuntimeService runtimeService; - private final String executionId; - - /** - * Constructs the adapter. - * - * @param runtimeService runtime service to use. - * @param executionId id of the execution to read from and write to. - * @param variableName name of the variable. - * @param memberClazz class of the variable. - */ - public ListReadWriteAdapterRuntimeService(RuntimeService runtimeService, String executionId, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.runtimeService = runtimeService; - this.executionId = executionId; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); - } - - @Override - public void set(List value, boolean isTransient) { - runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); - } - - @Override - public void setLocal(List value, boolean isTransient) { - runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); - } - @Override - public void remove() { - runtimeService.removeVariable(executionId, variableName); - } - - @Override - public void removeLocal() { - runtimeService.removeVariableLocal(executionId, variableName); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterTaskService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterTaskService.java deleted file mode 100644 index 892e102a..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterTaskService.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.list; - -import org.camunda.bpm.engine.TaskService; - -import java.util.List; -import java.util.Optional; - -/** - * Read write adapter for task service access. - * - * @param type of value. - */ -public class ListReadWriteAdapterTaskService extends AbstractListReadWriteAdapter { - - private final TaskService taskService; - private final String taskId; - - /** - * Constructs the adapter. - * - * @param taskService task service to use. - * @param taskId id of the task to read from and write to. - * @param variableName name of the variable. - * @param memberClazz class of the variable. - */ - public ListReadWriteAdapterTaskService(TaskService taskService, String taskId, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.taskService = taskService; - this.taskId = taskId; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); - } - - @Override - public void set(List value, boolean isTransient) { - taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); - } - - @Override - public void setLocal(List value, boolean isTransient) { - taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); - } - @Override - public void remove() { - taskService.removeVariable(taskId, variableName); - } - - @Override - public void removeLocal() { - taskService.removeVariableLocal(taskId, variableName); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableMap.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableMap.java deleted file mode 100644 index 16e48a53..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableMap.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.list; - -import org.camunda.bpm.engine.variable.VariableMap; - -import java.util.List; -import java.util.Optional; - -/** - * Read-write adapter for variable map. - * - * @param type of value. - */ -public class ListReadWriteAdapterVariableMap extends AbstractListReadWriteAdapter { - - private final VariableMap variableMap; - - /** - * Constructs the adapter. - * - * @param variableMap variable map to access. - * @param variableName variable to access. - * @param memberClazz class of variable value. - */ - public ListReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.variableMap = variableMap; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(variableMap.get(variableName))); - } - - @Override - public void set(List value, boolean isTransient) { - variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - throw new UnsupportedOperationException("Can't get a local variable on a variable map"); - } - - @Override - public void setLocal(List value, boolean isTransient) { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } - - @Override - public void remove() { - variableMap.remove(variableName); - } - - @Override - public void removeLocal() { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableScope.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableScope.java deleted file mode 100644 index fb46bbe3..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/list/ListReadWriteAdapterVariableScope.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.list; - -import org.camunda.bpm.engine.delegate.VariableScope; - -import java.util.List; -import java.util.Optional; - -/** - * Read-write adapter for variable scope. - * - * @param type of value. - */ -public class ListReadWriteAdapterVariableScope extends AbstractListReadWriteAdapter { - - private VariableScope variableScope; - - /** - * Constructs the adapter. - * - * @param variableScope variable scope to access. - * @param variableName variable to access. - * @param memberClazz class of member variable value. - */ - public ListReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.variableScope = variableScope; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); - } - - @Override - public void set(List value, boolean isTransient) { - variableScope.setVariable(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); - } - - @Override - public void setLocal(List value, boolean isTransient) { - variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); - } - - @Override - public void remove() { - variableScope.removeVariable(variableName); - } - - @Override - public void removeLocal() { - variableScope.removeVariableLocal(variableName); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterRuntimeService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterRuntimeService.java deleted file mode 100644 index 7806a46d..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterRuntimeService.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.map; - -import org.camunda.bpm.engine.RuntimeService; - -import java.util.Map; -import java.util.Optional; - -/** - * Read write adapter for runtime service access. - * - * @param type of key. - * @param type of value. - */ -public class MapReadWriteAdapterRuntimeService extends AbstractMapReadWriteAdapter { - - private final RuntimeService runtimeService; - private final String executionId; - - /** - * Constructs the adapter. - * - * @param runtimeService runtime service to use. - * @param executionId id of the execution to read from and write to. - * @param variableName name of the variable. - * @param keyClazz class of the key variable. - * @param valueClazz class of the value variable. - */ - public MapReadWriteAdapterRuntimeService( - RuntimeService runtimeService, String executionId, String variableName, Class keyClazz, Class valueClazz) { - super(variableName, keyClazz, valueClazz); - this.runtimeService = runtimeService; - this.executionId = executionId; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); - } - - @Override - public void set(Map value, boolean isTransient) { - runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); - } - - @Override - public void setLocal(Map value, boolean isTransient) { - runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public void remove() { - runtimeService.removeVariable(executionId, variableName); - } - - @Override - public void removeLocal() { - runtimeService.removeVariableLocal(executionId, variableName); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterTaskService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterTaskService.java deleted file mode 100644 index 5cd5f926..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterTaskService.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.map; - -import org.camunda.bpm.engine.TaskService; - -import java.util.Map; -import java.util.Optional; - -/** - * Read write adapter for task service access. - * - * @param type of key. - * @param type of value. - */ -public class MapReadWriteAdapterTaskService extends AbstractMapReadWriteAdapter { - - private final TaskService taskService; - private final String taskId; - - /** - * Constructs the adapter. - * - * @param taskService task service to use. - * @param taskId id of the task to read from and write to. - * @param variableName name of the variable. - * @param keyClazz class of the key of variable. - * @param valueClazz class of variable. - */ - public MapReadWriteAdapterTaskService( - TaskService taskService, String taskId, String variableName, Class keyClazz, Class valueClazz) { - super(variableName, keyClazz, valueClazz); - this.taskService = taskService; - this.taskId = taskId; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); - } - - @Override - public void set(Map value, boolean isTransient) { - taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); - } - - @Override - public void setLocal(Map value, boolean isTransient) { - taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); - } - @Override - public void remove() { - taskService.removeVariable(taskId, variableName); - } - - @Override - public void removeLocal() { - taskService.removeVariableLocal(taskId, variableName); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableMap.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableMap.java deleted file mode 100644 index 13edf5b9..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableMap.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.map; - -import org.camunda.bpm.engine.variable.VariableMap; - -import java.util.Map; -import java.util.Optional; - -/** - * Read-write adapter for variable map. - * - * @param type of key. - * @param type of value. - */ -public class MapReadWriteAdapterVariableMap extends AbstractMapReadWriteAdapter { - - private final VariableMap variableMap; - - /** - * Constructs the adapter. - * - * @param variableMap variable map to access. - * @param variableName variable to access. - * @param keyClazz class of variable key. - * @param valueClazz class of variable value. - */ - public MapReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class keyClazz, Class valueClazz) { - super(variableName, keyClazz, valueClazz); - this.variableMap = variableMap; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(variableMap.get(variableName))); - } - - @Override - public void set(Map value, boolean isTransient) { - variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - throw new UnsupportedOperationException("Can't get a local variable on a variable map"); - } - - @Override - public void setLocal(Map value, boolean isTransient) { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } - - @Override - public void remove() { - variableMap.remove(variableName); - } - - @Override - public void removeLocal() { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableScope.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableScope.java deleted file mode 100644 index 78f442b9..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/map/MapReadWriteAdapterVariableScope.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.map; - -import org.camunda.bpm.engine.delegate.VariableScope; - -import java.util.Map; -import java.util.Optional; - -/** - * Read-write adapter for variable scope. - * - * @param type of key. - * @param type of value. - */ -public class MapReadWriteAdapterVariableScope extends AbstractMapReadWriteAdapter { - - private VariableScope variableScope; - - /** - * Constructs the adapter. - * - * @param variableScope variable scope to access. - * @param variableName variable to access. - * @param keyClazz class of variable key. - * @param valueClazz class of variable value. - */ - public MapReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class keyClazz, Class valueClazz) { - super(variableName, keyClazz, valueClazz); - this.variableScope = variableScope; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); - } - - @Override - public void set(Map value, boolean isTransient) { - variableScope.setVariable(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); - } - - @Override - public void setLocal(Map value, boolean isTransient) { - variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); - } - @Override - public void remove() { - variableScope.removeVariable(variableName); - } - - @Override - public void removeLocal() { - variableScope.removeVariableLocal(variableName); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterRuntimeService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterRuntimeService.java deleted file mode 100644 index 6b73061f..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterRuntimeService.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.set; - -import org.camunda.bpm.engine.RuntimeService; - -import java.util.Optional; -import java.util.Set; - -/** - * Read write adapter for runtime service access. - * - * @param type of value. - */ -public class SetReadWriteAdapterRuntimeService extends AbstractSetReadWriteAdapter { - - private final RuntimeService runtimeService; - private final String executionId; - - /** - * Constructs the adapter. - * - * @param runtimeService runtime service to use. - * @param executionId id of the execution to read from and write to. - * @param variableName name of the variable. - * @param memberClazz class of the variable. - */ - public SetReadWriteAdapterRuntimeService(RuntimeService runtimeService, String executionId, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.runtimeService = runtimeService; - this.executionId = executionId; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))); - } - - @Override - public void set(Set value, boolean isTransient) { - runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(runtimeService.getVariableLocal(executionId, variableName))); - } - - @Override - public void setLocal(Set value, boolean isTransient) { - runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public void remove() { - runtimeService.removeVariable(executionId, variableName); - } - - @Override - public void removeLocal() { - runtimeService.removeVariableLocal(executionId, variableName); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterTaskService.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterTaskService.java deleted file mode 100644 index feaa6eb5..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterTaskService.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.set; - -import org.camunda.bpm.engine.TaskService; - -import java.util.Optional; -import java.util.Set; - -/** - * Read write adapter for task service access. - * - * @param type of value. - */ -public class SetReadWriteAdapterTaskService extends AbstractSetReadWriteAdapter { - - private final TaskService taskService; - private final String taskId; - - /** - * Constructs the adapter. - * - * @param taskService task service to use. - * @param taskId id of the task to read from and write to. - * @param variableName name of the variable. - * @param memberClazz class of the variable. - */ - public SetReadWriteAdapterTaskService(TaskService taskService, String taskId, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.taskService = taskService; - this.taskId = taskId; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))); - } - - @Override - public void set(Set value, boolean isTransient) { - taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))); - } - - @Override - public void setLocal(Set value, boolean isTransient) { - taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)); - } - @Override - public void remove() { - taskService.removeVariable(taskId, variableName); - } - - @Override - public void removeLocal() { - taskService.removeVariableLocal(taskId, variableName); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableMap.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableMap.java deleted file mode 100644 index 47cd63b6..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableMap.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.set; - -import org.camunda.bpm.engine.variable.VariableMap; - -import java.util.Optional; -import java.util.Set; - -/** - * Read-write adapter for variable map. - * - * @param type of value. - */ -public class SetReadWriteAdapterVariableMap extends AbstractSetReadWriteAdapter { - - private final VariableMap variableMap; - - /** - * Constructs the adapter. - * - * @param variableMap variable map to access. - * @param variableName variable to access. - * @param memberClazz class of variable value. - */ - public SetReadWriteAdapterVariableMap(VariableMap variableMap, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.variableMap = variableMap; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(variableMap.get(variableName))); - } - - @Override - public void set(Set value, boolean isTransient) { - variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - throw new UnsupportedOperationException("Can't get a local variable on a variable map"); - } - - @Override - public void setLocal(Set value, boolean isTransient) { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } - - @Override - public void remove() { - variableMap.remove(variableName); - } - - @Override - public void removeLocal() { - throw new UnsupportedOperationException("Can't set a local variable on a variable map"); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableScope.java b/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableScope.java deleted file mode 100644 index 8d4c695b..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/adapter/set/SetReadWriteAdapterVariableScope.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.holunda.camunda.bpm.data.adapter.set; - -import org.camunda.bpm.engine.delegate.VariableScope; - -import java.util.Optional; -import java.util.Set; - -/** - * Read-write adapter for variable scope. - * - * @param type of value. - */ -public class SetReadWriteAdapterVariableScope extends AbstractSetReadWriteAdapter { - - private VariableScope variableScope; - - /** - * Constructs the adapter. - * - * @param variableScope variable scope to access. - * @param variableName variable to access. - * @param memberClazz class of member variable value. - */ - public SetReadWriteAdapterVariableScope(VariableScope variableScope, String variableName, Class memberClazz) { - super(variableName, memberClazz); - this.variableScope = variableScope; - } - - @Override - public Optional> getOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))); - } - - @Override - public void set(Set value, boolean isTransient) { - variableScope.setVariable(variableName, getTypedValue(value, isTransient)); - } - - @Override - public Optional> getLocalOptional() { - return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))); - } - - @Override - public void setLocal(Set value, boolean isTransient) { - variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)); - } - - @Override - public void remove() { - variableScope.removeVariable(variableName); - } - - @Override - public void removeLocal() { - variableScope.removeVariableLocal(variableName); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/ProcessExecutionVariableBuilder.java b/extension/src/main/java/io/holunda/camunda/bpm/data/builder/ProcessExecutionVariableBuilder.java deleted file mode 100644 index 38038339..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/ProcessExecutionVariableBuilder.java +++ /dev/null @@ -1,159 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.RuntimeService; -import org.camunda.bpm.engine.variable.VariableMap; - -import java.util.function.Function; - -/** - * Process execution builder allowing for fluent variable setting. - */ -public class ProcessExecutionVariableBuilder { - - private final RuntimeService runtimeService; - private final String executionId; - - /** - * Creates a builder working on task. - */ - public ProcessExecutionVariableBuilder(RuntimeService runtimeService, String executionId) { - this.runtimeService = runtimeService; - this.executionId = executionId; - } - - /** - * Returns the resulting variables. - * @return variables. - */ - public VariableMap variables() { - return this.runtimeService.getVariablesTyped(this.executionId); - } - - /** - * Returns the resulting local variables. - * @return local variables. - */ - public VariableMap variablesLocal() { - return this.runtimeService.getVariablesLocalTyped(this.executionId); - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder set(VariableFactory factory, T value) { - return this.set(factory, value, false); - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder set(VariableFactory factory, T value, boolean isTransient) { - factory.on(this.runtimeService, this.executionId).set(value, isTransient); - return this; - } - - /** - * Sets the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder setLocal(VariableFactory factory, T value) { - return this.setLocal(factory, value, false); - } - - /** - * Sets the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder setLocal(VariableFactory factory, T value, boolean isTransient) { - factory.on(this.runtimeService, this.executionId).setLocal(value, isTransient); - return this; - } - - /** - * Removes the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder remove(VariableFactory factory) { - factory.on(this.runtimeService, this.executionId).remove(); - return this; - } - - /** - * Removes the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder removeLocal(VariableFactory factory) { - factory.on(this.runtimeService, this.executionId).removeLocal(); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder update(VariableFactory factory, Function valueProcessor, boolean isTransient) { - factory.on(this.runtimeService, this.executionId).update(valueProcessor, isTransient); - return this; - } - - /** - * Update the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder updateLocal(VariableFactory factory, Function valueProcessor, boolean isTransient) { - factory.on(this.runtimeService, this.executionId).updateLocal(valueProcessor, isTransient); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder update(VariableFactory factory, Function valueProcessor) { - return this.update(factory, valueProcessor, false); - } - - /** - * Update the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param value type. - * @return fluent builder. - */ - public ProcessExecutionVariableBuilder updateLocal(VariableFactory factory, Function valueProcessor) { - return this.updateLocal(factory, valueProcessor, false); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/UserTaskVariableBuilder.java b/extension/src/main/java/io/holunda/camunda/bpm/data/builder/UserTaskVariableBuilder.java deleted file mode 100644 index 0f9a1056..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/UserTaskVariableBuilder.java +++ /dev/null @@ -1,159 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.TaskService; -import org.camunda.bpm.engine.variable.VariableMap; - -import java.util.function.Function; - -/** - * User task builder allowing for fluent variable setting. - */ -public class UserTaskVariableBuilder { - - private final TaskService taskService; - private final String taskId; - - /** - * Creates a builder working on a user task. - */ - public UserTaskVariableBuilder(TaskService taskService, String taskId) { - this.taskService = taskService; - this.taskId = taskId; - } - - /** - * Returns the resulting variables. - * @return variables. - */ - public VariableMap variables() { - return this.taskService.getVariablesTyped(this.taskId); - } - - /** - * Returns the resulting local variables. - * @return local variables. - */ - public VariableMap variablesLocal() { - return this.taskService.getVariablesLocalTyped(this.taskId); - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder set(VariableFactory factory, T value) { - return this.set(factory, value, false); - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder set(VariableFactory factory, T value, boolean isTransient) { - factory.on(this.taskService, this.taskId).set(value, isTransient); - return this; - } - - /** - * Sets the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder setLocal(VariableFactory factory, T value) { - return this.setLocal(factory, value, false); - } - - /** - * Sets the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder setLocal(VariableFactory factory, T value, boolean isTransient) { - factory.on(this.taskService, this.taskId).setLocal(value, isTransient); - return this; - } - - /** - * Removes the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder remove(VariableFactory factory) { - factory.on(this.taskService, this.taskId).remove(); - return this; - } - - /** - * Removes the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder removeLocal(VariableFactory factory) { - factory.on(this.taskService, this.taskId).removeLocal(); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder update(VariableFactory factory, Function valueProcessor, boolean isTransient) { - factory.on(this.taskService, this.taskId).update(valueProcessor, isTransient); - return this; - } - - /** - * Update the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder updateLocal(VariableFactory factory, Function valueProcessor, boolean isTransient) { - factory.on(this.taskService, this.taskId).updateLocal(valueProcessor, isTransient); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder update(VariableFactory factory, Function valueProcessor) { - return this.update(factory, valueProcessor, false); - } - - /** - * Update the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param value type. - * @return fluent builder. - */ - public UserTaskVariableBuilder updateLocal(VariableFactory factory, Function valueProcessor) { - return this.updateLocal(factory, valueProcessor, false); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilder.java b/extension/src/main/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilder.java deleted file mode 100644 index 8483c06d..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilder.java +++ /dev/null @@ -1,99 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.variable.VariableMap; - -import java.util.function.Function; - -import static org.camunda.bpm.engine.variable.Variables.createVariables; - -/** - * Variable map builder allowing for fluent variable setting. - */ -public class VariableMapBuilder { - - private final VariableMap variables; - - /** - * Creates a builder with empty variables. - */ - public VariableMapBuilder() { - this(createVariables()); - } - - /** - * Creates a builder with provided variable map. - * @param variables variables to work on. - */ - public VariableMapBuilder(VariableMap variables) { - this.variables = variables; - } - - /** - * Returns the resulting variables. - * @return variables. - */ - public VariableMap build() { - return this.variables; - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param value type. - * @return fluent builder. - */ - public VariableMapBuilder set(VariableFactory factory, T value) { - return this.set(factory, value, false); - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value value to set. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public VariableMapBuilder set(VariableFactory factory, T value, boolean isTransient) { - factory.on(this.variables).set(value, isTransient); - return this; - } - - /** - * Removes the local value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param value type. - * @return fluent builder. - */ - public VariableMapBuilder remove(VariableFactory factory) { - factory.on(this.variables).remove(); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param isTransient transient flag. - * @param value type. - * @return fluent builder. - */ - public VariableMapBuilder update(VariableFactory factory, Function valueProcessor, boolean isTransient) { - factory.on(this.variables).update(valueProcessor, isTransient); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param value type. - * @return fluent builder. - */ - public VariableMapBuilder update(VariableFactory factory, Function valueProcessor) { - return this.update(factory, valueProcessor, false); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/VariableScopeBuilder.java b/extension/src/main/java/io/holunda/camunda/bpm/data/builder/VariableScopeBuilder.java deleted file mode 100644 index 3e1e1178..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/builder/VariableScopeBuilder.java +++ /dev/null @@ -1,172 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.delegate.VariableScope; - -import java.util.function.Function; - -/** - * Variable scope builder allowing for fluent variable setting. - */ -public class VariableScopeBuilder { - - private final VariableScope scope; - - /** - * Creates a builder with provided variable map. - *

The provided variables are modified by reference.

- * - * @param variables variables to work on. - */ - public VariableScopeBuilder(VariableScope variables) { - this.scope = variables; - } - - /** - * Returns the resulting variables. - * - * @return variables. - */ - public VariableScope build() { - return this.scope; - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param value value to set. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder set(VariableFactory factory, T value) { - return this.set(factory, value, false); - } - - /** - * Sets the value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param value value to set. - * @param isTransient transient flag. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder set(VariableFactory factory, T value, boolean isTransient) { - factory.on(this.scope).set(value, isTransient); - return this; - } - - /** - * Sets the local value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param value value to set. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder setLocal(VariableFactory factory, T value) { - return this.setLocal(factory, value, false); - } - - /** - * Sets the local value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param value value to set. - * @param isTransient transient flag. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder setLocal(VariableFactory factory, T value, boolean isTransient) { - factory.on(this.scope).setLocal(value, isTransient); - return this; - } - - /** - * Removes the local value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder remove(VariableFactory factory) { - factory.on(this.scope).remove(); - return this; - } - - /** - * Removes the local value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder removeLocal(VariableFactory factory) { - factory.on(this.scope).removeLocal(); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param isTransient transient flag. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder update(VariableFactory factory, Function valueProcessor, boolean isTransient) { - factory.on(this.scope).update(valueProcessor, isTransient); - return this; - } - - /** - * Update the local value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param isTransient transient flag. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder updateLocal(VariableFactory factory, Function valueProcessor, boolean isTransient) { - factory.on(this.scope).update(valueProcessor, isTransient); - return this; - } - - /** - * Updates the value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder update(VariableFactory factory, Function valueProcessor) { - return this.update(factory, valueProcessor, false); - } - - /** - * Update the local value for the provided variable and returns the builder (fluently). - * - * @param factory variable factory. - * @param valueProcessor processor for the value. - * @param value type. - * - * @return fluent builder. - */ - public VariableScopeBuilder updateLocal(VariableFactory factory, Function valueProcessor) { - return this.updateLocal(factory, valueProcessor, false); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/RuntimeServiceAdapterBuilder.java b/extension/src/main/java/io/holunda/camunda/bpm/data/factory/RuntimeServiceAdapterBuilder.java deleted file mode 100644 index 985f5ad5..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/RuntimeServiceAdapterBuilder.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.holunda.camunda.bpm.data.factory; - - -import io.holunda.camunda.bpm.data.adapter.ReadAdapter; -import io.holunda.camunda.bpm.data.adapter.basic.ReadWriteAdapterRuntimeService; -import io.holunda.camunda.bpm.data.adapter.WriteAdapter; -import org.camunda.bpm.engine.RuntimeService; - -/** - * Creates a builder to encapsulate the runtime service access. - * - * @param type of builder. - */ -public class RuntimeServiceAdapterBuilder { - - private final RuntimeService runtimeService; - private final BasicVariableFactory basicVariableFactory; - - /** - * Constructs the builder. - * - * @param basicVariableFactory variable factory to use. - * @param runtimeService task service to build adapter with. - */ - public RuntimeServiceAdapterBuilder(BasicVariableFactory basicVariableFactory, RuntimeService runtimeService) { - this.runtimeService = runtimeService; - this.basicVariableFactory = basicVariableFactory; - } - - /** - * Creates a write adapter on execution. - * - * @param executionId id identifying execution. - * - * @return write adapter - */ - public WriteAdapter on(String executionId) { - return new ReadWriteAdapterRuntimeService<>(runtimeService, executionId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); - } - - /** - * Creates a read adapter on execution. - * - * @param executionId id identifying execution. - * - * @return read adapter. - */ - public ReadAdapter from(String executionId) { - return new ReadWriteAdapterRuntimeService<>(runtimeService, executionId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); - } -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/TaskServiceAdapterBuilder.java b/extension/src/main/java/io/holunda/camunda/bpm/data/factory/TaskServiceAdapterBuilder.java deleted file mode 100644 index 5ed3958f..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/TaskServiceAdapterBuilder.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.holunda.camunda.bpm.data.factory; - -import io.holunda.camunda.bpm.data.adapter.ReadAdapter; -import io.holunda.camunda.bpm.data.adapter.basic.ReadWriteAdapterTaskService; -import io.holunda.camunda.bpm.data.adapter.WriteAdapter; -import org.camunda.bpm.engine.TaskService; - -/** - * Creates a builder to encapsulate the task service access. - * - * @param type of builder. - */ -public class TaskServiceAdapterBuilder { - - private final TaskService taskService; - private final BasicVariableFactory basicVariableFactory; - - /** - * Constructs the builder. - * @param basicVariableFactory variable factory to use. - * @param taskService task service to build adapter with. - */ - public TaskServiceAdapterBuilder(BasicVariableFactory basicVariableFactory, TaskService taskService) { - this.taskService = taskService; - this.basicVariableFactory = basicVariableFactory; - } - - /** - * Creates a write adapter on task. - * - * @param taskId id identifying task. - * - * @return write adapter - */ - public WriteAdapter on(String taskId) { - return new ReadWriteAdapterTaskService<>(taskService, taskId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); - } - - /** - * Creates a read adapter on task. - * - * @param taskId id identifying task. - * - * @return read adapter. - */ - public ReadAdapter from(String taskId) { - return new ReadWriteAdapterTaskService<>(taskService, taskId, basicVariableFactory.getName(), basicVariableFactory.getVariableClass()); - } - -} diff --git a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/VariableFactory.java b/extension/src/main/java/io/holunda/camunda/bpm/data/factory/VariableFactory.java deleted file mode 100644 index d97a341d..00000000 --- a/extension/src/main/java/io/holunda/camunda/bpm/data/factory/VariableFactory.java +++ /dev/null @@ -1,98 +0,0 @@ -package io.holunda.camunda.bpm.data.factory; - -import io.holunda.camunda.bpm.data.adapter.ReadAdapter; -import io.holunda.camunda.bpm.data.adapter.WriteAdapter; -import org.camunda.bpm.engine.RuntimeService; -import org.camunda.bpm.engine.TaskService; -import org.camunda.bpm.engine.delegate.VariableScope; -import org.camunda.bpm.engine.variable.VariableMap; - -/** - * Typed variable factory. - * - * @param type of the factory. - */ -public interface VariableFactory { - /** - * Creates a write adapter for variable scope. - * - * @param variableScope underlying scope to work on. - * - * @return write adapter. - */ - WriteAdapter on(VariableScope variableScope); - - /** - * Creates a read adapter on variable scope. - * - * @param variableScope underlying scope to work on. - * - * @return read adapter. - */ - ReadAdapter from(VariableScope variableScope); - - /** - * Creates a write adapter for variable map. - * - * @param variableMap underlying scope to work on. - * - * @return write adapter. - */ - WriteAdapter on(VariableMap variableMap); - - /** - * Creates a read adapter on variable scope. - * - * @param variableMap underlying map to work on. - * - * @return read adapter. - */ - ReadAdapter from(VariableMap variableMap); - - /** - * Creates a write adapter on execution. - * - * @param runtimeService underlying runtime service to work on. - * @param executionId id identifying execution. - * - * @return write adapter - */ - WriteAdapter on(RuntimeService runtimeService, String executionId); - - /** - * Creates a read adapter on execution. - * - * @param runtimeService underlying runtime service to work on. - * @param executionId id identifying execution. - * - * @return read adapter. - */ - ReadAdapter from(RuntimeService runtimeService, String executionId); - - /** - * Creates a write adapter on task. - * - * @param taskService underlying runtime service to work on. - * @param taskId id identifying task. - * - * @return write adapter - */ - WriteAdapter on(TaskService taskService, String taskId); - - /** - * Creates a read adapter on task. - * - * @param taskService underlying runtime service to work on. - * @param taskId id identifying task. - * - * @return read adapter. - */ - ReadAdapter from(TaskService taskService, String taskId); - - /** - * Retrieves the variable name. - * - * @return name of the variable. - */ - String getName(); -} diff --git a/extension/src/main/kotlin/Root.kt b/extension/src/main/kotlin/Root.kt deleted file mode 100644 index ca38431b..00000000 --- a/extension/src/main/kotlin/Root.kt +++ /dev/null @@ -1 +0,0 @@ -package io.holunda.camunda.bpm.data \ No newline at end of file diff --git a/extension/src/main/kotlin/guard/VariablesGuard.kt b/extension/src/main/kotlin/guard/VariablesGuard.kt deleted file mode 100644 index ff810b28..00000000 --- a/extension/src/main/kotlin/guard/VariablesGuard.kt +++ /dev/null @@ -1,74 +0,0 @@ -package io.holunda.camunda.bpm.data.guard - -import io.holunda.camunda.bpm.data.guard.condition.VariableGuardCondition -import org.camunda.bpm.engine.RuntimeService -import org.camunda.bpm.engine.TaskService -import org.camunda.bpm.engine.delegate.VariableScope -import org.camunda.bpm.engine.variable.VariableMap - -/** - * Guard on a set of variables. - * @param variableConditions a list of conditions to add to the guard. - */ -class VariablesGuard( - private val variableConditions: List> -) { - - /** - * Constructs a guard with exactly one condition. - * @param condition condition to add to gurad. - */ - constructor(condition: VariableGuardCondition<*>) : this(listOf(condition)) - - /** - * Fluent builer to create a new guard from existing one adding one additional condition. - * @param condition to add to existing guard. - */ - fun fromExisting(condition: VariableGuardCondition<*>) = VariablesGuard(variableConditions.plus(condition)) - - /** - * Evaluates the contained conditions on variables from given variable map. - * @param variableMap variable map to work on. - * @return list of violations if any. - */ - fun evaluate(variableMap: VariableMap): List> = - variableConditions.flatMap { it.evaluate(variableMap) } - - /** - * Evaluates the contained conditions on variables from given variable scope. - * @param variableScope variable scope to work on. - * @return list of violations if any. - */ - fun evaluate(variableScope: VariableScope): List> = - variableConditions.flatMap { it.evaluate(variableScope) } - - /** - * Evaluates the contained conditions on variables retrieved from task service. - * @param taskService task service to access the task. - * @param taskId task id. - * @return list of violations if any. - */ - fun evaluate(taskService: TaskService, taskId: String): List> = - variableConditions.flatMap { it.evaluate(taskService, taskId) } - - /** - * Evaluates the contained conditions on variables retrieved from runtime service. - * @param runtimeService runtime service to access the execution. - * @param executionId execution id. - * @return list of violations if any. - */ - fun evaluate(runtimeService: RuntimeService, executionId: String): List> = - variableConditions.flatMap { it.evaluate(runtimeService, executionId) } - - /** - * Retrieves a list of local variables addressed by this guard. - * @return variable factories extracted from condition with scope local. - */ - fun getLocalVariables() = variableConditions.filter { it.local }.map { it.variableFactory } - - /** - * Retrieves a list of variables addressed by this guard. - * @return variable factories extracted from condition with scope global. - */ - fun getVariables() = variableConditions.filter { !it.local }.map { it.variableFactory } -} diff --git a/extension/src/main/kotlin/guard/condition/VariableGuardCondition.kt b/extension/src/main/kotlin/guard/condition/VariableGuardCondition.kt deleted file mode 100644 index 491182cf..00000000 --- a/extension/src/main/kotlin/guard/condition/VariableGuardCondition.kt +++ /dev/null @@ -1,75 +0,0 @@ -package io.holunda.camunda.bpm.data.guard.condition - -import io.holunda.camunda.bpm.data.factory.VariableFactory -import io.holunda.camunda.bpm.data.guard.GuardViolation -import org.camunda.bpm.engine.RuntimeService -import org.camunda.bpm.engine.TaskService -import org.camunda.bpm.engine.delegate.VariableScope -import org.camunda.bpm.engine.variable.VariableMap -import java.util.* - -/** - * Abstract guard condition. - * @since 0.0.6 - * @param T variable type. - * @param variableFactory factory to work on. - * @param local flag indicating the variable scope (global/local). Defaults to global. - *

- * This class is intended to be subclassed by developers of new variable guards. - *

- */ -abstract class VariableGuardCondition( - internal val variableFactory: VariableFactory, - internal val local: Boolean = false -) { - - /** - * Label for messages indicating the variable scope (local or global, which is a default). - */ - val localLabel: String by lazy { if (local) " local" else "" } - - /** - * Evaluate the condition on a value option. - * @param option optional value for the variable, contaning the value or nothing. - * @return list of guard violations. - */ - internal open fun evaluate(option: Optional): List> = emptyList() - - /** - * Evaluate the condition on a value retrieved from the variable map. - * @param variableMap variables to run the evaluation on. - * @return list of guard violations - */ - fun evaluate(variableMap: VariableMap): List> { - return evaluate(if (local) variableFactory.from(variableMap).localOptional else variableFactory.from(variableMap).optional) - } - - /** - * Evaluate the condition on a value retrieved from the variable map. - * @param variableScope variable scope (e.g. delegate execution or delegate task) to run the evaluation on. - * @return list of guard violations - */ - fun evaluate(variableScope: VariableScope): List> { - return evaluate(if (local) variableFactory.from(variableScope).localOptional else variableFactory.from(variableScope).optional) - } - - /** - * Evaluate the condition on a value retrieved from the task service. - * @param taskService to retrieve the task from. - * @param taskId id of the task to work on. - * @return list of guard violations - */ - fun evaluate(taskService: TaskService, taskId: String): List> { - return evaluate(if (local) variableFactory.from(taskService, taskId).localOptional else variableFactory.from(taskService, taskId).optional) - } - - /** - * Evaluate the condition on a value retrieved from the runtime service. - * @param runtimeService to retrieve the execution from. - * @param executionId id of the execution to work on. - * @return list of guard violations - */ - fun evaluate(runtimeService: RuntimeService, executionId: String): List> { - return evaluate(if (local) variableFactory.from(runtimeService, executionId).localOptional else variableFactory.from(runtimeService, executionId).optional) - } -} diff --git a/extension/src/main/kotlin/guard/condition/VariableValueGuardCondition.kt b/extension/src/main/kotlin/guard/condition/VariableValueGuardCondition.kt deleted file mode 100644 index cffa3662..00000000 --- a/extension/src/main/kotlin/guard/condition/VariableValueGuardCondition.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.holunda.camunda.bpm.data.guard.condition - -import io.holunda.camunda.bpm.data.factory.VariableFactory -import io.holunda.camunda.bpm.data.guard.GuardViolation -import java.util.* - -/** - * Condition to check if the variable has provided value. - * @param variableFactory factory to work on. - * @param value set of values to compare with. - * @param local flag indicating if local or global scope is required. - */ -class VariableValueGuardCondition( - variableFactory: VariableFactory, - private val value: T, - local: Boolean = false -) : VariableGuardCondition(variableFactory, local) { - - private val existsCondition = VariableExistsGuardCondition(variableFactory, local) - - override fun evaluate(option: Optional): List> { - val violations = existsCondition.evaluate(option).toMutableList() - if (option.get() != value) { - violations.add( - GuardViolation( - condition = this, - option = option, - message = "Expecting$localLabel variable '${variableFactory.name}' to have value '$value', but it was '${option.get()}'." - ) - ) - } - return violations - } -} - -/** - * Creation extension for the condition. - * @param value value to check for. - * @param local if the variable should be local. - * @return instance of [VariableValueGuardCondition] on current factory. - */ -fun VariableFactory.hasValue(value: T, local: Boolean = false) = VariableValueGuardCondition(this, value, local) - diff --git a/extension/src/main/kotlin/guard/condition/VariableValueOneOfGuardCondition.kt b/extension/src/main/kotlin/guard/condition/VariableValueOneOfGuardCondition.kt deleted file mode 100644 index cdcfb676..00000000 --- a/extension/src/main/kotlin/guard/condition/VariableValueOneOfGuardCondition.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.holunda.camunda.bpm.data.guard.condition - -import io.holunda.camunda.bpm.data.factory.VariableFactory -import io.holunda.camunda.bpm.data.guard.GuardViolation -import java.util.* - -/** - * Condition to check if the variable has on of the provided values. - * @param variableFactory factory to work on. - * @param values set of values to compare with. - * @param local flag indicating if local or global scope is required. - */ -class VariableValueOneOfGuardCondition( - variableFactory: VariableFactory, - private val values: Set, - local: Boolean = false -) : VariableGuardCondition(variableFactory, local) { - - private val existsCondition = VariableExistsGuardCondition(variableFactory, local) - private val valueConditions = values.map { VariableValueGuardCondition(variableFactory, it, local) } - - override fun evaluate(option: Optional): List> { - val violations = existsCondition.evaluate(option).toMutableList() - if (valueConditions.none { it.evaluate(option).isEmpty() }) { - violations.add( - GuardViolation( - condition = this, - option = option, - message = "Expecting$localLabel variable '${variableFactory.name}' to be one of [${values.joinToString("', '", "'", "'")}], but it was '${option.get()}'." - ) - ) - } - return violations - } -} - -/** - * Creation extension for the condition. - * @param local is the variable should be local. - * @param values set of values which are allowed. - * @return instance of [VariableValueOneOfGuardCondition] on current factory. - */ -fun VariableFactory.hasOneOfValues(values: Set, local: Boolean = false) = VariableValueOneOfGuardCondition(this, values, local) diff --git a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/ProcessExecutionVariableBuilderTest.java b/extension/src/test/java/io/holunda/camunda/bpm/data/builder/ProcessExecutionVariableBuilderTest.java deleted file mode 100644 index 751ae45c..00000000 --- a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/ProcessExecutionVariableBuilderTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.CamundaBpmData; -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.RuntimeService; -import org.camunda.bpm.engine.variable.Variables; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import java.util.UUID; - -import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ProcessExecutionVariableBuilderTest { - - private static final VariableFactory STRING = stringVariable("myString"); - private RuntimeService runtimeService = Mockito.mock(RuntimeService.class); - private String executionId; - private String value = "value"; - - @Before - public void mockExecution() { - this.executionId = UUID.randomUUID().toString(); - when(runtimeService.getVariable(this.executionId, STRING.getName())).thenReturn(value); - when(runtimeService.getVariableLocal(this.executionId, STRING.getName())).thenReturn(value); - } - - @After - public void after() { - Mockito.reset(runtimeService); - } - - @Test - public void testSet() { - CamundaBpmData - .builder(runtimeService, executionId) - .set(STRING, "value") - .variablesLocal(); - verify(runtimeService).setVariable(this.executionId, STRING.getName(), Variables.stringValue("value")); - } - - @Test - public void testSetLocal() { - CamundaBpmData - .builder(runtimeService, executionId) - .setLocal(STRING, "value") - .variablesLocal(); - verify(runtimeService).setVariableLocal(this.executionId, STRING.getName(), Variables.stringValue("value")); - } - - @Test - public void testRemove() { - CamundaBpmData - .builder(runtimeService, executionId) - .remove(STRING) - .variables(); - verify(runtimeService).removeVariable(this.executionId, STRING.getName()); - } - - @Test - public void testRemoveLocal() { - CamundaBpmData - .builder(runtimeService, executionId) - .removeLocal(STRING) - .variables(); - verify(runtimeService).removeVariableLocal(this.executionId, STRING.getName()); - } - - @Test - public void testUpdate() { - CamundaBpmData - .builder(runtimeService, executionId) - .update(STRING, String::toUpperCase); - verify(runtimeService).getVariable(this.executionId, STRING.getName()); - verify(runtimeService).setVariable(this.executionId, STRING.getName(), Variables.stringValue("VALUE")); - } - - @Test - public void testUpdateLocal() { - CamundaBpmData - .builder(runtimeService, executionId) - .updateLocal(STRING, String::toUpperCase); - verify(runtimeService).getVariableLocal(this.executionId, STRING.getName()); - verify(runtimeService).setVariableLocal(this.executionId, STRING.getName(), Variables.stringValue("VALUE")); - } - -} diff --git a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/UserTaskVariableBuilderTest.java b/extension/src/test/java/io/holunda/camunda/bpm/data/builder/UserTaskVariableBuilderTest.java deleted file mode 100644 index d9ff7ed8..00000000 --- a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/UserTaskVariableBuilderTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.CamundaBpmData; -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.TaskService; -import org.camunda.bpm.engine.variable.Variables; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import java.util.UUID; - -import static io.holunda.camunda.bpm.data.CamundaBpmData.stringVariable; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class UserTaskVariableBuilderTest { - - private static final VariableFactory STRING = stringVariable("myString"); - private TaskService taskService = Mockito.mock(TaskService.class); - private String taskId; - private String value = "value"; - - @Before - public void mockExecution() { - this.taskId = UUID.randomUUID().toString(); - when(taskService.getVariable(this.taskId, STRING.getName())).thenReturn(value); - when(taskService.getVariableLocal(this.taskId, STRING.getName())).thenReturn(value); - } - - @After - public void after() { - Mockito.reset(taskService); - } - - @Test - public void testSet() { - CamundaBpmData - .builder(taskService, taskId) - .set(STRING, "value") - .variablesLocal(); - verify(taskService).setVariable(this.taskId, STRING.getName(), Variables.stringValue("value")); - } - - @Test - public void testSetLocal() { - CamundaBpmData - .builder(taskService, taskId) - .setLocal(STRING, "value") - .variablesLocal(); - verify(taskService).setVariableLocal(this.taskId, STRING.getName(), Variables.stringValue("value")); - } - - @Test - public void testRemove() { - CamundaBpmData - .builder(taskService, taskId) - .remove(STRING) - .variables(); - verify(taskService).removeVariable(this.taskId, STRING.getName()); - } - - @Test - public void testRemoveLocal() { - CamundaBpmData - .builder(taskService, taskId) - .removeLocal(STRING) - .variables(); - verify(taskService).removeVariableLocal(this.taskId, STRING.getName()); - } - - @Test - public void testUpdate() { - CamundaBpmData - .builder(taskService, taskId) - .update(STRING, String::toUpperCase); - verify(taskService).getVariable(this.taskId, STRING.getName()); - verify(taskService).setVariable(this.taskId, STRING.getName(), Variables.stringValue("VALUE")); - } - - @Test - public void testUpdateLocal() { - CamundaBpmData - .builder(taskService, taskId) - .updateLocal(STRING, String::toUpperCase); - verify(taskService).getVariableLocal(this.taskId, STRING.getName()); - verify(taskService).setVariableLocal(this.taskId, STRING.getName(), Variables.stringValue("VALUE")); - } - -} diff --git a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilderTest.java b/extension/src/test/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilderTest.java deleted file mode 100644 index a3890ebc..00000000 --- a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/VariableMapBuilderTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.CamundaBpmData; -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.variable.VariableMap; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.camunda.bpm.engine.variable.Variables.createVariables; - -public class VariableMapBuilderTest { - - private static final VariableFactory STRING = CamundaBpmData.stringVariable("myString"); - - @Test - public void testSet() { - VariableMap newVariables = CamundaBpmData - .builder() - .set(STRING, "value") - .build(); - assertThat(newVariables.get(STRING.getName())).isEqualTo("value"); - } - - @Test - public void testRemove() { - VariableMap variables = createVariables(); - STRING.on(variables).set("value"); - VariableMap newVariables = CamundaBpmData - .builder(variables) - .remove(STRING) - .build(); - assertThat(newVariables).isEmpty(); - } - - @Test - public void testUpdate() { - VariableMap variables = createVariables(); - STRING.on(variables).set("value"); - VariableMap newVariables = CamundaBpmData - .builder(variables) - .update(STRING, String::toUpperCase) - .build(); - assertThat(newVariables.get(STRING.getName())).isEqualTo("VALUE"); - } - -} diff --git a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/VariableScopeBuilderTest.java b/extension/src/test/java/io/holunda/camunda/bpm/data/builder/VariableScopeBuilderTest.java deleted file mode 100644 index 5a5e3fed..00000000 --- a/extension/src/test/java/io/holunda/camunda/bpm/data/builder/VariableScopeBuilderTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package io.holunda.camunda.bpm.data.builder; - -import io.holunda.camunda.bpm.data.CamundaBpmData; -import io.holunda.camunda.bpm.data.factory.VariableFactory; -import org.camunda.bpm.engine.delegate.VariableScope; -import org.camunda.bpm.extension.mockito.delegate.DelegateExecutionFake; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class VariableScopeBuilderTest { - - private static final VariableFactory STRING = CamundaBpmData.stringVariable("myString"); - - @Test - public void testSet() { - DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); - VariableScope newVariables = CamundaBpmData - .builder(execution) - .set(STRING, "value") - .build(); - assertThat(newVariables.getVariable(STRING.getName())).isEqualTo("value"); - } - - @Test - public void testSetLocal() { - DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); - VariableScope newVariables = CamundaBpmData - .builder(execution) - .setLocal(STRING, "value") - .build(); - assertThat(newVariables.getVariableLocal(STRING.getName())).isEqualTo("value"); - } - - @Test - public void testRemove() { - DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); - STRING.on(execution).set("value"); - VariableScope newVariables = CamundaBpmData - .builder(execution) - .remove(STRING) - .build(); - assertThat(newVariables.getVariableNames()).isEmpty(); - } - - @Test - public void testRemoveLocal() { - DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); - STRING.on(execution).setLocal("value"); - VariableScope newVariables = CamundaBpmData - .builder(execution) - .removeLocal(STRING) - .build(); - assertThat(newVariables.getVariableNames()).isEmpty(); - } - - @Test - public void testUpdate() { - DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); - STRING.on(execution).set("value"); - VariableScope newVariables = CamundaBpmData - .builder(execution) - .update(STRING, String::toUpperCase) - .build(); - assertThat(newVariables.getVariable(STRING.getName())).isEqualTo("VALUE"); - } - - @Test - public void testUpdateLocal() { - DelegateExecutionFake execution = DelegateExecutionFake.of().withId("4711"); - STRING.on(execution).setLocal("value"); - VariableScope newVariables = CamundaBpmData - .builder(execution) - .updateLocal(STRING, String::toUpperCase) - .build(); - assertThat(newVariables.getVariable(STRING.getName())).isEqualTo("VALUE"); - } - -} diff --git a/mockito/pom.xml b/extension/test/pom.xml similarity index 83% rename from mockito/pom.xml rename to extension/test/pom.xml index eab0a991..efc3f1be 100644 --- a/mockito/pom.xml +++ b/extension/test/pom.xml @@ -6,22 +6,24 @@ io.holunda.data camunda-bpm-data-parent - 0.0.6 + 1.0.0 + ../.. - camunda-bpm-data-mockito + camunda-bpm-data-test ${project.artifactId} jar false + 1.6.0 io.holunda.data - camunda-bpm-data-kotlin + camunda-bpm-data ${project.version} @@ -33,7 +35,22 @@ com.nhaarman mockito-kotlin - 1.6.0 + ${mockito-kotlin.version} + + + + org.mockito + mockito-core + + + org.jetbrains.kotlin + kotlin-stdlib + + + org.jetbrains.kotlin + kotlin-reflect + + @@ -59,16 +76,8 @@ org.jetbrains.kotlin kotlin-reflect - - io.github.microutils - kotlin-logging - - - org.jetbrains.kotlin - kotlin-stdlib - - - + + org.slf4j slf4j-simple diff --git a/mockito/src/main/kotlin/CamundaBpmDataMockito.kt b/extension/test/src/main/kotlin/CamundaBpmDataMockito.kt similarity index 75% rename from mockito/src/main/kotlin/CamundaBpmDataMockito.kt rename to extension/test/src/main/kotlin/CamundaBpmDataMockito.kt index 6169070d..eb5c6f62 100644 --- a/mockito/src/main/kotlin/CamundaBpmDataMockito.kt +++ b/extension/test/src/main/kotlin/CamundaBpmDataMockito.kt @@ -4,7 +4,6 @@ import org.camunda.bpm.engine.RuntimeService import org.camunda.bpm.engine.TaskService import org.camunda.bpm.engine.variable.VariableMap - /** * Collection of fluent mock builder factory methods. */ @@ -16,8 +15,7 @@ object CamundaBpmDataMockito { * @return fluent builder. */ @JvmStatic - fun taskServiceVariableMockBuilder(taskService: TaskService) - = TaskServiceVariableMockBuilder(taskService = taskService) + fun taskServiceVariableMockBuilder(taskService: TaskService) = TaskServiceVariableMockBuilder(taskService = taskService) /** * Constructs a task service variable mock builder. @@ -27,8 +25,7 @@ object CamundaBpmDataMockito { * @return fluent builder. */ @JvmStatic - fun taskServiceVariableMockBuilder(taskService: TaskService, variables: VariableMap, localVariables: VariableMap) - = TaskServiceVariableMockBuilder(taskService = taskService, variables = variables, localVariables = localVariables) + fun taskServiceVariableMockBuilder(taskService: TaskService, variables: VariableMap, localVariables: VariableMap) = TaskServiceVariableMockBuilder(taskService = taskService, variables = variables, localVariables = localVariables) /** @@ -37,8 +34,7 @@ object CamundaBpmDataMockito { * @return verifier to simplify assertions. */ @JvmStatic - fun taskServiceMockVerifier(taskService: TaskService) - = TaskServiceMockVerifier(taskService) + fun taskServiceMockVerifier(taskService: TaskService) = TaskServiceMockVerifier(taskService) /** * Constructs a runtime service variable mock builder. @@ -46,8 +42,7 @@ object CamundaBpmDataMockito { * @return fluent builder. */ @JvmStatic - fun runtimeServiceVariableMockBuilder(runtimeService: RuntimeService) - = RuntimeServiceVariableMockBuilder(runtimeService = runtimeService) + fun runtimeServiceVariableMockBuilder(runtimeService: RuntimeService) = RuntimeServiceVariableMockBuilder(runtimeService = runtimeService) /** * Constructs a runtime service variable mock builder. @@ -57,8 +52,7 @@ object CamundaBpmDataMockito { * @return fluent builder. */ @JvmStatic - fun runtimeServiceVariableMockBuilder(runtimeService: RuntimeService, variables: VariableMap, localVariables: VariableMap) - = RuntimeServiceVariableMockBuilder(runtimeService = runtimeService, variables = variables, localVariables = localVariables) + fun runtimeServiceVariableMockBuilder(runtimeService: RuntimeService, variables: VariableMap, localVariables: VariableMap) = RuntimeServiceVariableMockBuilder(runtimeService = runtimeService, variables = variables, localVariables = localVariables) /** * Constructs a verifier for runtime service mock. @@ -66,6 +60,5 @@ object CamundaBpmDataMockito { * @return verifier to simplify assertions. */ @JvmStatic - fun runtimeServiceMockVerifier(runtimeService: RuntimeService) - = RuntimeServiceMockVerifier(runtimeService) + fun runtimeServiceMockVerifier(runtimeService: RuntimeService) = RuntimeServiceMockVerifier(runtimeService) } \ No newline at end of file diff --git a/mockito/src/main/kotlin/RuntimeServiceMockVerifier.kt b/extension/test/src/main/kotlin/RuntimeServiceMockVerifier.kt similarity index 98% rename from mockito/src/main/kotlin/RuntimeServiceMockVerifier.kt rename to extension/test/src/main/kotlin/RuntimeServiceMockVerifier.kt index dfce92e5..4563393c 100644 --- a/mockito/src/main/kotlin/RuntimeServiceMockVerifier.kt +++ b/extension/test/src/main/kotlin/RuntimeServiceMockVerifier.kt @@ -4,7 +4,6 @@ import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.verifyNoMoreInteractions import io.holunda.camunda.bpm.data.factory.VariableFactory import org.camunda.bpm.engine.RuntimeService -import org.camunda.bpm.engine.variable.VariableMap /** * Verifier for a mocked runtime service. diff --git a/mockito/src/main/kotlin/RuntimeServiceVariableMockBuilder.kt b/extension/test/src/main/kotlin/RuntimeServiceVariableMockBuilder.kt similarity index 100% rename from mockito/src/main/kotlin/RuntimeServiceVariableMockBuilder.kt rename to extension/test/src/main/kotlin/RuntimeServiceVariableMockBuilder.kt diff --git a/mockito/src/main/kotlin/TaskServiceMockVerifier.kt b/extension/test/src/main/kotlin/TaskServiceMockVerifier.kt similarity index 100% rename from mockito/src/main/kotlin/TaskServiceMockVerifier.kt rename to extension/test/src/main/kotlin/TaskServiceMockVerifier.kt diff --git a/mockito/src/main/kotlin/TaskServiceVariableMockBuilder.kt b/extension/test/src/main/kotlin/TaskServiceVariableMockBuilder.kt similarity index 100% rename from mockito/src/main/kotlin/TaskServiceVariableMockBuilder.kt rename to extension/test/src/main/kotlin/TaskServiceVariableMockBuilder.kt diff --git a/mockito/src/test/kotlin/RuntimeServiceMockingTest.kt b/extension/test/src/test/kotlin/RuntimeServiceMockingTest.kt similarity index 100% rename from mockito/src/test/kotlin/RuntimeServiceMockingTest.kt rename to extension/test/src/test/kotlin/RuntimeServiceMockingTest.kt diff --git a/mockito/src/test/kotlin/RuntimeServiceVerifierTest.kt b/extension/test/src/test/kotlin/RuntimeServiceVerifierTest.kt similarity index 100% rename from mockito/src/test/kotlin/RuntimeServiceVerifierTest.kt rename to extension/test/src/test/kotlin/RuntimeServiceVerifierTest.kt diff --git a/mockito/src/test/kotlin/TaskServiceMockingTest.kt b/extension/test/src/test/kotlin/TaskServiceMockingTest.kt similarity index 100% rename from mockito/src/test/kotlin/TaskServiceMockingTest.kt rename to extension/test/src/test/kotlin/TaskServiceMockingTest.kt diff --git a/mockito/src/test/kotlin/TaskServiceVerifierTest.kt b/extension/test/src/test/kotlin/TaskServiceVerifierTest.kt similarity index 100% rename from mockito/src/test/kotlin/TaskServiceVerifierTest.kt rename to extension/test/src/test/kotlin/TaskServiceVerifierTest.kt diff --git a/pom.xml b/pom.xml index 98d2068c..b36e999d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.holunda.data camunda-bpm-data-parent - 0.0.6 + 1.0.0 ${project.artifactId} Camunda BPM Data https://github.com/holunda-io/camunda-bpm-data/ @@ -27,6 +27,7 @@ 3.4.0 2.4.5 1.8.0 + 5.0.0 0.18.2 1.3.61 @@ -45,9 +46,8 @@
- extension - extension-kotlin - mockito + extension/core + extension/test @@ -117,6 +117,18 @@ + + org.camunda.bpm.springboot + camunda-bpm-spring-boot-starter-test + ${camunda-spring-boot.version} + test + + + org.camunda.bpm.assert + camunda-bpm-assert + ${camunda-assert.version} + test + @@ -135,6 +147,17 @@ camunda-engine provided + + org.camunda.spin + camunda-spin-core + provided + + + org.camunda.spin + camunda-spin-dataformat-json-jackson + provided + + @@ -154,7 +177,6 @@ assertj-core test - @@ -735,6 +757,9 @@ Jan Galinski + + Developer + Holisticon AG https://holisticon.de