提交 2221c21a 编写于 作者: R Ryan Dawson 提交者: salaboy

provide a way to copy process vars into task (#2116)

* provide a way to copy process vars into task

* tests passing now

* add test at new api level

* will let updatebot handle api version change

* rebase and port to new test approach

* remove unused imports as per codacy
上级 0dc8956c
......@@ -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());
}
}
}
......@@ -263,11 +263,8 @@ public class ProcessRuntimeImpl implements ProcessRuntime {
processInstance(getVariablesPayload.getProcessInstanceId());
Map<String, org.activiti.engine.impl.persistence.entity.VariableInstance> 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
......
......@@ -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;
}
......
......@@ -134,7 +134,6 @@ public class TaskRuntimeImpl implements TaskRuntime {
if (getTasksPayload.getParentTaskId() != null) {
taskQuery = taskQuery.taskParentTaskId(getTasksPayload.getParentTaskId());
}
List<Task> 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<VariableInstance> 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) {
......
......@@ -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;
}
......
......@@ -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);
}
......
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());
}
}
}
......@@ -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;
}
......
......@@ -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<String,Object> 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<VariableInstance> variables){
for (VariableInstance variable : variables){
......
<?xml version="1.0" encoding="UTF-8"?>
<definitions
targetNamespace="Examples"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:activiti="http://activiti.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath">
<process id="twoTaskProcess">
<startEvent id="startevent1" name="Start"></startEvent>
<parallelGateway id="parallelgateway1" name="Parallel Gateway"></parallelGateway>
<endEvent id="endevent1" name="End"></endEvent>
<userTask id="usertask1" name="User Task"></userTask>
<userTask id="usertask2" name="User Task"></userTask>
<parallelGateway id="parallelgateway2" name="Parallel Gateway"></parallelGateway>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="parallelgateway1"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="parallelgateway1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow3" sourceRef="parallelgateway1" targetRef="usertask2"></sequenceFlow>
<sequenceFlow id="flow4" sourceRef="usertask1" targetRef="parallelgateway2"></sequenceFlow>
<sequenceFlow id="flow5" sourceRef="usertask2" targetRef="parallelgateway2"></sequenceFlow>
<userTask id="usertask3" name="User Task"></userTask>
<sequenceFlow id="flow6" sourceRef="parallelgateway2" targetRef="usertask3"></sequenceFlow>
<sequenceFlow id="flow7" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
</process>
</definitions>
\ No newline at end of file
......@@ -41,6 +41,7 @@ public class ActivitiProperties {
private List<String> customMybatisMappers;
private List<String> 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;
}
}
......@@ -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()));
......
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<ProcessDefinition> 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<String,Object> 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"));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<definitions
targetNamespace="Examples"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:activiti="http://activiti.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath">
<process id="twoTaskProcess">
<startEvent id="startevent1" name="Start"></startEvent>
<parallelGateway id="parallelgateway1" name="Parallel Gateway"></parallelGateway>
<endEvent id="endevent1" name="End"></endEvent>
<userTask id="usertask1" name="User Task" activiti:candidateUsers="salaboy"></userTask>
<userTask id="usertask2" name="User Task" activiti:candidateUsers="garth"></userTask>
<parallelGateway id="parallelgateway2" name="Parallel Gateway"></parallelGateway>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="parallelgateway1"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="parallelgateway1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow3" sourceRef="parallelgateway1" targetRef="usertask2"></sequenceFlow>
<sequenceFlow id="flow4" sourceRef="usertask1" targetRef="parallelgateway2"></sequenceFlow>
<sequenceFlow id="flow5" sourceRef="usertask2" targetRef="parallelgateway2"></sequenceFlow>
<userTask id="usertask3" name="User Task"></userTask>
<sequenceFlow id="flow6" sourceRef="parallelgateway2" targetRef="usertask3"></sequenceFlow>
<sequenceFlow id="flow7" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
</process>
</definitions>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册