diff --git a/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessAdminRuntimeImpl.java b/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessAdminRuntimeImpl.java index a2f1973cf60c7bcaf5de474d33f71fbb43cb8d45..ee38b940388707bd8a4a94c085067022cd07921a 100644 --- a/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessAdminRuntimeImpl.java +++ b/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessAdminRuntimeImpl.java @@ -207,23 +207,14 @@ public class ProcessAdminRuntimeImpl implements ProcessAdminRuntime { @Override public void setVariables(SetProcessVariablesPayload setProcessVariablesPayload) { - if (setProcessVariablesPayload.isLocalOnly()) { - runtimeService.setVariablesLocal(setProcessVariablesPayload.getProcessInstanceId(), - setProcessVariablesPayload.getVariables()); - } else { - runtimeService.setVariables(setProcessVariablesPayload.getProcessInstanceId(), + runtimeService.setVariables(setProcessVariablesPayload.getProcessInstanceId(), setProcessVariablesPayload.getVariables()); - } + } @Override public void removeVariables(RemoveProcessVariablesPayload removeProcessVariablesPayload) { - if (removeProcessVariablesPayload.isLocalOnly()) { - runtimeService.removeVariablesLocal(removeProcessVariablesPayload.getProcessInstanceId(), - removeProcessVariablesPayload.getVariableNames()); - } else { - runtimeService.removeVariables(removeProcessVariablesPayload.getProcessInstanceId(), + runtimeService.removeVariables(removeProcessVariablesPayload.getProcessInstanceId(), removeProcessVariablesPayload.getVariableNames()); - } } } diff --git a/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessRuntimeImpl.java b/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessRuntimeImpl.java index 6f94a7e3599c4539f5150dafc01b206686a8b21f..22d97821a6a99a2bedece501af35009b46233044 100644 --- a/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessRuntimeImpl.java +++ b/activiti-api-impl/activiti-api-process-runtime-impl/src/main/java/org/activiti/runtime/api/impl/ProcessRuntimeImpl.java @@ -263,11 +263,8 @@ public class ProcessRuntimeImpl implements ProcessRuntime { processInstance(getVariablesPayload.getProcessInstanceId()); Map variables; - if (getVariablesPayload.isLocalOnly()) { - variables = runtimeService.getVariableInstancesLocal(getVariablesPayload.getProcessInstanceId()); - } else { - variables = runtimeService.getVariableInstances(getVariablesPayload.getProcessInstanceId()); - } + variables = runtimeService.getVariableInstances(getVariablesPayload.getProcessInstanceId()); + return variableInstanceConverter.from(variables.values()); } @@ -277,13 +274,9 @@ public class ProcessRuntimeImpl implements ProcessRuntime { if (!securityPoliciesManager.canWrite(processInstance.getProcessDefinitionKey())) { throw new ActivitiForbiddenException("Operation not permitted for " + processInstance.getProcessDefinitionKey() + " due security policy violation"); } - if (removeProcessVariablesPayload.isLocalOnly()) { - runtimeService.removeVariablesLocal(removeProcessVariablesPayload.getProcessInstanceId(), - removeProcessVariablesPayload.getVariableNames()); - } else { - runtimeService.removeVariables(removeProcessVariablesPayload.getProcessInstanceId(), + runtimeService.removeVariables(removeProcessVariablesPayload.getProcessInstanceId(), removeProcessVariablesPayload.getVariableNames()); - } + } @Override @@ -292,13 +285,9 @@ public class ProcessRuntimeImpl implements ProcessRuntime { if (!securityPoliciesManager.canWrite(processInstance.getProcessDefinitionKey())) { throw new ActivitiForbiddenException("Operation not permitted for " + processInstance.getProcessDefinitionKey() + " due security policy violation"); } - if (setProcessVariablesPayload.isLocalOnly()) { - runtimeService.setVariablesLocal(setProcessVariablesPayload.getProcessInstanceId(), - setProcessVariablesPayload.getVariables()); - } else { - runtimeService.setVariables(setProcessVariablesPayload.getProcessInstanceId(), + runtimeService.setVariables(setProcessVariablesPayload.getProcessInstanceId(), setProcessVariablesPayload.getVariables()); - } + } @Override diff --git a/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskAdminRuntimeImpl.java b/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskAdminRuntimeImpl.java index 9146256f2c7eb9d752df9afd07f6101f4f89fa45..9c5ad50132e976a1472547199074fc3847e78915 100644 --- a/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskAdminRuntimeImpl.java +++ b/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskAdminRuntimeImpl.java @@ -100,13 +100,9 @@ public class TaskAdminRuntimeImpl implements TaskAdminRuntime { @Override public void setVariables(SetTaskVariablesPayload setTaskVariablesPayload) { - if (setTaskVariablesPayload.isLocalOnly()) { - taskService.setVariablesLocal(setTaskVariablesPayload.getTaskId(), + taskService.setVariablesLocal(setTaskVariablesPayload.getTaskId(), setTaskVariablesPayload.getVariables()); - } else { - taskService.setVariables(setTaskVariablesPayload.getTaskId(), - setTaskVariablesPayload.getVariables()); - } + } @Override @@ -119,7 +115,7 @@ public class TaskAdminRuntimeImpl implements TaskAdminRuntime { task.getName(), Task.TaskStatus.COMPLETED); taskService.complete(completeTaskPayload.getTaskId(), - completeTaskPayload.getVariables()); + completeTaskPayload.getVariables(),true); return competedTaskData; } diff --git a/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskRuntimeImpl.java b/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskRuntimeImpl.java index 89d059483f30a1fd3fd3af8909e5f1de94458269..bceae34f4e9d4e6f40c4cc9bd5d63cb6e7237986 100644 --- a/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskRuntimeImpl.java +++ b/activiti-api-impl/activiti-api-task-runtime-impl/src/main/java/org/activiti/runtime/api/impl/TaskRuntimeImpl.java @@ -134,7 +134,6 @@ public class TaskRuntimeImpl implements TaskRuntime { if (getTasksPayload.getParentTaskId() != null) { taskQuery = taskQuery.taskParentTaskId(getTasksPayload.getParentTaskId()); } - List tasks = taskConverter.from(taskQuery.listPage(pageable.getStartIndex(), pageable.getMaxItems())); return new PageImpl<>(tasks, @@ -143,11 +142,7 @@ public class TaskRuntimeImpl implements TaskRuntime { @Override public List variables(GetTaskVariablesPayload getTaskVariablesPayload) { - if (getTaskVariablesPayload.isLocalOnly()) { - return variableInstanceConverter.from(taskService.getVariableInstancesLocal(getTaskVariablesPayload.getTaskId()).values()); - } else { - return variableInstanceConverter.from(taskService.getVariableInstances(getTaskVariablesPayload.getTaskId()).values()); - } + return variableInstanceConverter.from(taskService.getVariableInstancesLocal(getTaskVariablesPayload.getTaskId()).values()); } @Override @@ -172,7 +167,7 @@ public class TaskRuntimeImpl implements TaskRuntime { task.getName(), Task.TaskStatus.COMPLETED); taskService.complete(completeTaskPayload.getTaskId(), - completeTaskPayload.getVariables()); + completeTaskPayload.getVariables(),true); return competedTaskData; } @@ -312,13 +307,8 @@ public class TaskRuntimeImpl implements TaskRuntime { @Override public void setVariables(SetTaskVariablesPayload setTaskVariablesPayload) { - if (setTaskVariablesPayload.isLocalOnly()) { - taskService.setVariablesLocal(setTaskVariablesPayload.getTaskId(), + taskService.setVariablesLocal(setTaskVariablesPayload.getTaskId(), setTaskVariablesPayload.getVariables()); - } else { - taskService.setVariables(setTaskVariablesPayload.getTaskId(), - setTaskVariablesPayload.getVariables()); - } } private org.activiti.engine.task.Task getInternalTask(String taskId) { diff --git a/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java b/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java index 6f75d36a513cc26cbd72e481d2c611a7c8eb6ab1..c64c65d4e636edc48b4c2184ffb86afd4a14812b 100755 --- a/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java +++ b/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java @@ -201,6 +201,8 @@ public abstract class ProcessEngineConfiguration { protected boolean enableProcessDefinitionInfoCache = false; protected ActivitiEngineAgendaFactory engineAgendaFactory; + protected boolean copyVariablesToLocalForTasks = false; + /** use one of the static createXxxx methods instead */ protected ProcessEngineConfiguration() { } @@ -742,6 +744,15 @@ public abstract class ProcessEngineConfiguration { return this; } + public ProcessEngineConfiguration setCopyVariablesToLocalForTasks(boolean copyVariablesToLocalForTasks) { + this.copyVariablesToLocalForTasks = copyVariablesToLocalForTasks; + return this; + } + + public boolean isCopyVariablesToLocalForTasks(){ + return copyVariablesToLocalForTasks; + } + public void setEngineAgendaFactory(ActivitiEngineAgendaFactory engineAgendaFactory) { this.engineAgendaFactory = engineAgendaFactory; } diff --git a/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java b/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java index c8017505879f8e734a9d07afd8fde81d3611c3fc..d90e7537842f922242e31b691a666e0ad7dc76dd 100755 --- a/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java +++ b/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java @@ -29,6 +29,7 @@ import org.activiti.engine.delegate.event.ActivitiEventDispatcher; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder; import org.activiti.engine.impl.bpmn.helper.SkipExpressionUtil; +import org.activiti.engine.impl.bpmn.helper.TaskVariableCopier; import org.activiti.engine.impl.calendar.BusinessCalendar; import org.activiti.engine.impl.calendar.DueDateBusinessCalendar; import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; @@ -193,9 +194,14 @@ public class UserTaskActivityBehavior extends TaskActivityBehavior { } } } - + + taskEntityManager.insert(task, (ExecutionEntity) execution); - + + if(commandContext.getProcessEngineConfiguration().isCopyVariablesToLocalForTasks()) { + TaskVariableCopier.copyVariablesIntoTaskLocal(task); + } + boolean skipUserTask = false; if (StringUtils.isNotEmpty(activeTaskSkipExpression)) { Expression skipExpression = expressionManager.createExpression(activeTaskSkipExpression); @@ -226,7 +232,7 @@ public class UserTaskActivityBehavior extends TaskActivityBehavior { taskEntityManager.deleteTask(task, null, false, false); leave(execution); } - + } public void trigger(DelegateExecution execution, String signalName, Object signalData) { @@ -238,7 +244,6 @@ public class UserTaskActivityBehavior extends TaskActivityBehavior { throw new ActivitiException("UserTask should not be signalled before complete"); } } - leave(execution); } diff --git a/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/TaskVariableCopier.java b/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/TaskVariableCopier.java new file mode 100644 index 0000000000000000000000000000000000000000..c2d140d509731267b10bea5daf184e8c917ad771 --- /dev/null +++ b/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/TaskVariableCopier.java @@ -0,0 +1,25 @@ +package org.activiti.engine.impl.bpmn.helper; + +import org.activiti.engine.impl.persistence.entity.TaskEntity; + +public class TaskVariableCopier { + + public static void copyVariablesIntoTaskLocal(TaskEntity task){ + + //TODO: would like to filter which variables copy much as with subProcesses + + task.setVariablesLocal(task.getVariables()); + + + } + + public static void copyVariablesOutFromTaskLocal(TaskEntity task){ + + //TODO: would like to filter which variables copy much as with subProcesses + + //provided not a standalone task + if(task.getProcessInstance()!=null) { + task.getProcessInstance().setVariables(task.getVariablesLocal()); + } + } +} diff --git a/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/CompleteTaskCmd.java b/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/CompleteTaskCmd.java index 2636e608bb0892dedaf72895c9f632c4b1da4fc9..df0f9f8fa309c02b0cf8a9c9729705eaa8e8e891 100644 --- a/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/CompleteTaskCmd.java +++ b/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/CompleteTaskCmd.java @@ -15,6 +15,7 @@ package org.activiti.engine.impl.cmd; import java.util.Map; import org.activiti.engine.compatibility.Activiti5CompatibilityHandler; +import org.activiti.engine.impl.bpmn.helper.TaskVariableCopier; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.impl.util.Activiti5Util; @@ -72,6 +73,10 @@ public class CompleteTaskCmd extends AbstractCompleteTaskCmd { } } + if(commandContext.getProcessEngineConfiguration().isCopyVariablesToLocalForTasks()){ + TaskVariableCopier.copyVariablesOutFromTaskLocal(task); + } + executeTaskComplete(commandContext, task, variables, localScope); return null; } diff --git a/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java b/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java index 129ad81f684956a273dde903ebbd24a2438b7d34..0dc7e3eb32fd89027f35eb861a2092c29b37671d 100644 --- a/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java +++ b/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java @@ -172,6 +172,38 @@ public class TaskVariablesTest extends PluggableActivitiTestCase { checkVariable(taskList1.get(0).getId(), "taskVar1" , "sayHello1", variables); checkVariable(taskList2.get(1).getId(), "taskVar4" , "sayHello4", variables); } + + @Deployment + public void testGetVariablesCopiedIntoTasks(){ + //variables not automatically copied into tasks at engine level unless we turn this on + processEngineConfiguration.setCopyVariablesToLocalForTasks(true); + + Map startVariables = new HashMap<>(); + startVariables.put("start1","start1"); + startVariables.put("start2","start2"); + + ProcessInstance processInstance1 = runtimeService.startProcessInstanceByKey("twoTaskProcess",startVariables); + Task userTask1 = taskService.createTaskQuery().taskDefinitionKey("usertask1").singleResult(); + Task userTask2 = taskService.createTaskQuery().taskDefinitionKey("usertask2").singleResult(); + + //both should have the process variables copied into their local + assertEquals(startVariables,taskService.getVariablesLocal(userTask1.getId())); + assertEquals(startVariables,taskService.getVariablesLocal(userTask2.getId())); + + + //if one modifies, the other should not see the modification + taskService.setVariableLocal(userTask1.getId(),"start1","modifiedstart1"); + + assertEquals(taskService.getVariablesLocal(userTask2.getId()),startVariables); + taskService.complete(userTask1.getId()); + + //after completion the process variable should be updated but only that one and not task2's local variable + assertEquals("modifiedstart1",runtimeService.getVariable(processInstance1.getId(),"start1")); + assertEquals("start2", runtimeService.getVariable(processInstance1.getId(),"start2")); + assertEquals(startVariables,taskService.getVariablesLocal(userTask2.getId())); + + processEngineConfiguration.setCopyVariablesToLocalForTasks(false); + } private void checkVariable(String taskId, String name, String value, List variables){ for (VariableInstance variable : variables){ diff --git a/activiti-engine/src/test/resources/org/activiti/engine/test/api/task/TaskVariablesTest.testGetVariablesCopiedIntoTasks.bpmn20.xml b/activiti-engine/src/test/resources/org/activiti/engine/test/api/task/TaskVariablesTest.testGetVariablesCopiedIntoTasks.bpmn20.xml new file mode 100644 index 0000000000000000000000000000000000000000..11114b2e38b25b9c36c3e84c726a8a9973acd2fe --- /dev/null +++ b/activiti-engine/src/test/resources/org/activiti/engine/test/api/task/TaskVariablesTest.testGetVariablesCopiedIntoTasks.bpmn20.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ActivitiProperties.java b/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ActivitiProperties.java index f561fc98b145c61405610c2ba80b23e714b97dd3..9e444951a304d363126f708d28813512512f6eb8 100644 --- a/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ActivitiProperties.java +++ b/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ActivitiProperties.java @@ -41,6 +41,7 @@ public class ActivitiProperties { private List customMybatisMappers; private List customMybatisXMLMappers; private boolean useStrongUuids = true; + private boolean copyVariablesToLocalForTasks = true; public boolean isAsyncExecutorActivate() { return asyncExecutorActivate; @@ -195,5 +196,12 @@ public class ActivitiProperties { public void setUseStrongUuids(boolean useStrongUuids) { this.useStrongUuids = useStrongUuids; } - + + public boolean isCopyVariablesToLocalForTasks() { + return copyVariablesToLocalForTasks; + } + + public void setCopyVariablesToLocalForTasks(boolean copyVariablesToLocalForTasks) { + this.copyVariablesToLocalForTasks = copyVariablesToLocalForTasks; + } } diff --git a/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ProcessEngineAutoConfiguration.java b/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ProcessEngineAutoConfiguration.java index 4264ff3b1800732a665de515825e85867e4af3f6..6e50c510d4de6c919369f29183770f26599e7552 100644 --- a/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ProcessEngineAutoConfiguration.java +++ b/activiti-spring-boot-starter/src/main/java/org/activiti/spring/boot/ProcessEngineAutoConfiguration.java @@ -81,6 +81,7 @@ public class ProcessEngineAutoConfiguration extends AbstractProcessEngineAutoCon } conf.setHistoryLevel(activitiProperties.getHistoryLevel()); + conf.setCopyVariablesToLocalForTasks(activitiProperties.isCopyVariablesToLocalForTasks()); if (activitiProperties.getCustomMybatisMappers() != null) { conf.setCustomMybatisMappers(getCustomMybatisMapperClasses(activitiProperties.getCustomMybatisMappers())); diff --git a/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/tasks/TaskVariablesLocalCopiesTest.java b/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/tasks/TaskVariablesLocalCopiesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e4ca02d976fb640b919ab4836b2301a9a90f3683 --- /dev/null +++ b/activiti-spring-boot-starter/src/test/java/org/activiti/spring/boot/tasks/TaskVariablesLocalCopiesTest.java @@ -0,0 +1,150 @@ +package org.activiti.spring.boot.tasks; + +import org.activiti.api.process.model.ProcessDefinition; +import org.activiti.api.process.model.ProcessInstance; +import org.activiti.api.process.model.builders.ProcessPayloadBuilder; +import org.activiti.api.process.runtime.ProcessRuntime; +import org.activiti.api.process.runtime.conf.ProcessRuntimeConfiguration; +import org.activiti.api.runtime.shared.query.Page; +import org.activiti.api.runtime.shared.query.Pageable; +import org.activiti.api.task.model.Task; +import org.activiti.api.task.model.builders.TaskPayloadBuilder; +import org.activiti.api.task.runtime.TaskRuntime; +import org.activiti.spring.boot.security.util.SecurityUtil; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) +public class TaskVariablesLocalCopiesTest { + + private static final String TWOTASK_PROCESS = "twoTaskProcess"; + + @Autowired + private ProcessRuntime processRuntime; + + @Autowired + private TaskRuntime taskRuntime; + + @Autowired + private SecurityUtil securityUtil; + + @Test + public void shouldGetConfiguration() { + securityUtil.logInAs("salaboy"); + //when + ProcessRuntimeConfiguration configuration = processRuntime.configuration(); + + //then + assertThat(configuration).isNotNull(); + } + + @Test + public void shouldGetAvailableProcessDefinitionForTheGivenUser() { + securityUtil.logInAs("salaboy"); + //when + Page processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0, + 50)); + //then + assertThat(processDefinitionPage.getContent()).isNotNull(); + assertThat(processDefinitionPage.getContent()) + .extracting(ProcessDefinition::getKey) + .contains(TWOTASK_PROCESS); + } + + @Test + public void processInstanceVariablesCopiedIntoTasksByDefault() { + + securityUtil.logInAs("salaboy"); + + Map startVariables = new HashMap<>(); + startVariables.put("start1","start1"); + startVariables.put("start2","start2"); + + //when + ProcessInstance twoTaskInstance = processRuntime.start(ProcessPayloadBuilder.start() + .withProcessDefinitionKey(TWOTASK_PROCESS) + .withVariables(startVariables) + .build()); + + assertThat(processRuntime.variables(ProcessPayloadBuilder.variables().withProcessInstance(twoTaskInstance).build())) + .extracting("name", "value") + .containsExactly( + tuple("start1", "start1"), + tuple("start2", "start2")); + + + //both tasks should have the process variables + Task task1 = taskRuntime.tasks(Pageable.of(0, 10),TaskPayloadBuilder.tasks().build()).getContent().get(0); + assertThat(taskRuntime.variables(TaskPayloadBuilder.variables().withTaskId(task1.getId()).build())) + .extracting("name", "value") + .containsExactly( + tuple("start1", "start1"), + tuple("start2", "start2")); + + securityUtil.logInAs("garth"); + + Task task2 = taskRuntime.tasks(Pageable.of(0, 10),TaskPayloadBuilder.tasks().build()).getContent().get(0); + assertThat(taskRuntime.variables(TaskPayloadBuilder.variables().withTaskId(task2.getId()).build())) + .extracting("name", "value") + .containsExactly( + tuple("start1", "start1"), + tuple("start2", "start2")); + + + securityUtil.logInAs("salaboy"); + + //if one modifies, the other should not see the modification + taskRuntime.setVariables(TaskPayloadBuilder.setVariables().withTaskId(task1.getId()).withVariables(Collections.singletonMap("start1","modifiedstart1")).build()); + + //the task where it was modified should reflect the modification + assertThat(taskRuntime.variables(TaskPayloadBuilder.variables().withTaskId(task1.getId()).build())) + .extracting("name", "value") + .containsExactly( + tuple("start1", "modifiedstart1"), + tuple("start2", "start2")); + + securityUtil.logInAs("garth"); + + //other does not see + assertThat(taskRuntime.variables(TaskPayloadBuilder.variables().withTaskId(task2.getId()).build())) + .extracting("name", "value") + .containsExactly( + tuple("start1", "start1"), + tuple("start2", "start2")); + + securityUtil.logInAs("salaboy"); + //complete and change var again + taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(task1.getId()).build()); + taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task1.getId()).withVariable("start1","modagainstart1").build()); + + //after completion the process variable should be updated but only the one that was modified + assertThat(processRuntime.variables(ProcessPayloadBuilder.variables().withProcessInstance(twoTaskInstance).build())) + .extracting("name", "value") + .containsExactly( + tuple("start1", "modagainstart1"), + tuple("start2", "start2")); + + securityUtil.logInAs("garth"); + //and task2 should not see the change + assertThat(taskRuntime.variables(TaskPayloadBuilder.variables().withTaskId(task2.getId()).build())) + .extracting("name", "value") + .containsExactly( + tuple("start1", "start1"), + tuple("start2", "start2")); + + } + + +} diff --git a/activiti-spring-boot-starter/src/test/resources/processes/two-usertask-parallel.bpmn20.xml b/activiti-spring-boot-starter/src/test/resources/processes/two-usertask-parallel.bpmn20.xml new file mode 100644 index 0000000000000000000000000000000000000000..1b2285a4cb41f1d504d78995ae2c5ee6a26ba377 --- /dev/null +++ b/activiti-spring-boot-starter/src/test/resources/processes/two-usertask-parallel.bpmn20.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file