diff --git a/activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java b/activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java index 3458de709e098fbd1e871d68cfa18cfa05752513..304d031c73e7aa4005f0953120b0c3d3c3fe2155 100755 --- a/activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java +++ b/activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java @@ -52,9 +52,6 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - - */ public class UserTaskActivityBehavior extends TaskActivityBehavior { private static final long serialVersionUID = 1L; @@ -255,7 +252,7 @@ public class UserTaskActivityBehavior extends TaskActivityBehavior { protected Map calculateOutBoundVariables(DelegateExecution execution, Map taskVariables) { CommandContext commandContext = Context.getCommandContext(); - if(commandContext.getProcessEngineConfiguration().isCopyVariablesToLocalForTasks()){ + if (commandContext.getProcessEngineConfiguration().isCopyVariablesToLocalForTasks()) { return taskVariables; } return emptyMap(); @@ -294,6 +291,7 @@ public class UserTaskActivityBehavior extends TaskActivityBehavior { Map outboundVariables = calculateOutBoundVariables(execution, taskVariables); processInstanceEntity.setVariables(outboundVariables); + execution.setVariablesLocal(outboundVariables); } } diff --git a/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/RuntimeTestConfiguration.java b/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/RuntimeTestConfiguration.java index d46c345bded386c269460ae5a1844821195e3f3c..c81741b5150a36eeb6686202cdc70ad623a9fadb 100644 --- a/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/RuntimeTestConfiguration.java +++ b/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/RuntimeTestConfiguration.java @@ -162,6 +162,14 @@ public class RuntimeTestConfiguration { }; } + @Bean(name = "value-processor.process") + public Connector valueProcessorConnector() { + return integrationContext -> { + integrationContext.addOutBoundVariable("providedValue",integrationContext.getInBoundVariable("input")); + return integrationContext; + }; + } + @Bean(name = "Tag Image Connector.tagImageActionName") public Connector tagImageActionName() { return integrationContext -> { diff --git a/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/tasks/TaskRuntimeVariableMappingIT.java b/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/tasks/TaskRuntimeVariableMappingIT.java index c9a9209c504e5e5486c1e1ed6e12c9b66c33d64f..603d4b042c698f040132f50dfa30835e92025cd8 100644 --- a/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/tasks/TaskRuntimeVariableMappingIT.java +++ b/activiti-core/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/tasks/TaskRuntimeVariableMappingIT.java @@ -15,8 +15,10 @@ */ package org.activiti.spring.boot.tasks; +import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; +import static org.awaitility.Awaitility.await; import java.util.Date; import java.util.HashMap; @@ -27,6 +29,7 @@ import org.activiti.api.process.model.ProcessInstance; import org.activiti.api.task.model.Task; import org.activiti.common.util.DateFormatterProvider; import org.activiti.spring.boot.process.ProcessBaseRuntime; +import org.activiti.spring.boot.security.util.SecurityUtil; import org.activiti.spring.boot.test.util.ProcessCleanUpUtil; import org.activiti.spring.boot.test.util.TaskCleanUpUtil; import org.junit.jupiter.api.AfterEach; @@ -49,6 +52,9 @@ public class TaskRuntimeVariableMappingIT { private static final String TASK_MAP_ALL_PREVALENCE = "taskVariableMappingSendAllPrevalence"; + @Autowired + private SecurityUtil securityUtil; + @Autowired private TaskBaseRuntime taskBaseRuntime; @@ -459,4 +465,56 @@ public class TaskRuntimeVariableMappingIT { assertThat(tasks).hasSize(1); return tasks.get(0); } + + @Test + public void should_supportVariableMappingAfterLoopingBack() { + //given + final ProcessInstance processInstance = processBaseRuntime.startProcessWithProcessDefinitionKey("Process_N4qkN051N"); + List tasks = taskBaseRuntime.getTasksByProcessInstanceId(processInstance.getId()); + assertThat(tasks) + .extracting(Task::getName) + .containsExactly("Enter values"); + + //when the task completes with a variable value causing a loop back + taskBaseRuntime.completeTask(tasks.get(0), singletonMap("formInput", "provided-it1")); + + //then process loops back to the first task + waitForTaskOnProcessInstance(processInstance, "Enter values"); + List variables = processBaseRuntime.getVariables(processInstance); + assertThat(variables) + .extracting( + VariableInstance::getName, + VariableInstance::getValue + ).containsExactly( + tuple("providedValue", "provided-it1") + ); + + //when the task completes with a variable value not causing a loop back + tasks = taskBaseRuntime.getTasksByProcessInstanceId( + processInstance.getId()); + taskBaseRuntime.completeTask(tasks.get(0), + singletonMap("formInput", "go")); + + //then the process reaches the next task + waitForTaskOnProcessInstance(processInstance, "Wait"); + variables = processBaseRuntime.getVariables(processInstance); + assertThat(variables) + .extracting( + VariableInstance::getName, + VariableInstance::getValue + ).containsExactly( + tuple("providedValue", "go") + ); + + } + + private void waitForTaskOnProcessInstance(ProcessInstance processInstance, String taskName) { + await().untilAsserted(() -> { + securityUtil.logInAs("user"); + assertThat(taskBaseRuntime.getTasksByProcessInstanceId(processInstance.getId())) + .extracting(Task::getName) + .containsExactly(taskName); + }); + } + } diff --git a/activiti-core/activiti-spring-boot-starter/src/test/resources/processes/variable-mapping-with-loop-extensions.json b/activiti-core/activiti-spring-boot-starter/src/test/resources/processes/variable-mapping-with-loop-extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..d1e6726ea2cdf9c267cfa0333d0830a198f88014 --- /dev/null +++ b/activiti-core/activiti-spring-boot-starter/src/test/resources/processes/variable-mapping-with-loop-extensions.json @@ -0,0 +1,50 @@ +{ + "id": "process-fdee92a0-5a2b-48be-8696-245eff49aa07", + "type": "PROCESS", + "name": "variable-mapping-with-loop", + "extensions": { + "Process_N4qkN051N": { + "constants": {}, + "mappings": { + "Task_0od1320": { + "outputs": { + "providedValue": { + "type": "variable", + "value": "providedValue" + } + }, + "inputs": { + "input": { + "type": "variable", + "value": "providedValue" + } + } + }, + "Task_125yjke": { + "outputs": { + "providedValue": { + "type": "variable", + "value": "formInput" + } + } + } + }, + "properties": { + "e974d84d-aa76-4acb-903d-97582fe89861": { + "id": "e974d84d-aa76-4acb-903d-97582fe89861", + "name": "providedValue", + "type": "string", + "value": "", + "required": false + } + }, + "assignments": { + "Task_125yjke": { + "type": "identity", + "assignment": "assignee", + "id": "Task_125yjke" + } + } + } + } +} diff --git a/activiti-core/activiti-spring-boot-starter/src/test/resources/processes/variable-mapping-with-loop.bpmn20.xml b/activiti-core/activiti-spring-boot-starter/src/test/resources/processes/variable-mapping-with-loop.bpmn20.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd438dab9c2f1b250d026b99745457128562cc0a --- /dev/null +++ b/activiti-core/activiti-spring-boot-starter/src/test/resources/processes/variable-mapping-with-loop.bpmn20.xml @@ -0,0 +1,89 @@ + + + + + + SequenceFlow_1anr2ek + + + + SequenceFlow_1anr2ek + SequenceFlow_0g8zsg1 + SequenceFlow_0urignn + + + + SequenceFlow_03x97kf + SequenceFlow_1xda66c + SequenceFlow_0g8zsg1 + + + + SequenceFlow_1b0cog0 + + + ${(providedValue eq "go")} + + + + SequenceFlow_0urignn + SequenceFlow_03x97kf + + + SequenceFlow_1xda66c + SequenceFlow_1b0cog0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +