From f21e9bc625306475f064fc5e916251dd1519137c Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Wed, 28 Jun 2023 11:00:30 +0200 Subject: [PATCH] Always fetch a variable value when returning it after a creation or update + add support for fetching specific case instance and plan item instance variables --- .../flowable/cmmn/api/CmmnRuntimeService.java | 21 +++++ .../engine/impl/cmd/GetLocalVariablesCmd.java | 21 ++++- .../cmmn/engine/impl/cmd/GetVariablesCmd.java | 23 ++++- .../impl/runtime/CmmnRuntimeServiceImpl.java | 15 ++- .../cmmn/test/runtime/VariablesTest.java | 55 +++++++++++ .../runtime/caze/BaseVariableResource.java | 94 ++++++++++++------- ...aseInstanceVariableCollectionResource.java | 7 +- .../CaseInstanceVariableDataResource.java | 3 +- .../caze/CaseInstanceVariableResource.java | 2 +- .../PlanItemInstanceVariableDataResource.java | 3 +- ...temInstanceVariableCollectionResource.java | 3 +- .../task/TaskVariableBaseResource.java | 16 +++- .../task/TaskVariableCollectionResource.java | 11 ++- .../CaseInstanceVariableResourceTest.java | 2 +- .../BaseExecutionVariableResource.java | 35 ++++--- .../BaseVariableCollectionResource.java | 33 +++++-- .../ExecutionVariableCollectionResource.java | 10 +- .../ExecutionVariableDataResource.java | 4 + .../process/ExecutionVariableResource.java | 6 +- ...essInstanceVariableCollectionResource.java | 14 ++- .../ProcessInstanceVariableDataResource.java | 5 + .../ProcessInstanceVariableResource.java | 6 +- .../task/TaskVariableBaseResource.java | 9 +- .../task/TaskVariableCollectionResource.java | 11 ++- .../ProcessInstanceVariableResourceTest.java | 2 +- 25 files changed, 312 insertions(+), 99 deletions(-) diff --git a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/CmmnRuntimeService.java b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/CmmnRuntimeService.java index 57711c20328..06d8de12cce 100644 --- a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/CmmnRuntimeService.java +++ b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/CmmnRuntimeService.java @@ -88,6 +88,16 @@ public interface CmmnRuntimeService { * when no case instance is found for the given caseInstanceId. */ Map getVariables(String caseInstanceId); + + /** + * The variable values for all given variableNames. + * + * @param caseInstanceId id of execution, cannot be null. + * @param variableNames the collection of variable names that should be retrieved. + * @return the variables or an empty map if no such variables are found. + * @throws FlowableObjectNotFoundException when no case instance is found for the given caseInstanceId. + */ + Map getVariables(String caseInstanceId, Collection variableNames); /** * All variables visible from the given case instance scope. @@ -111,6 +121,17 @@ public interface CmmnRuntimeService { */ Map getLocalVariables(String planItemInstanceId); + /** + * All variable values for all given variableNames that are defined in the plan item instance scope, + * without taking outer scopes into account. + * + * @param planItemInstanceId id of plan item instance, cannot be null. + * @param variableNames the collection of variable names that should be retrieved. + * @return the variables or an empty map if no such variables are found. + * @throws FlowableObjectNotFoundException when no plan item instance is found for the given planItemInstanceId. + */ + Map getLocalVariables(String planItemInstanceId, Collection variableNames); + /** * All variable values that are defined in the plan item instance scope, without taking outer scopes into account. * diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetLocalVariablesCmd.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetLocalVariablesCmd.java index 41bcef39fae..640ecda2f50 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetLocalVariablesCmd.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetLocalVariablesCmd.java @@ -12,6 +12,7 @@ */ package org.flowable.cmmn.engine.impl.cmd; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,9 +31,11 @@ public class GetLocalVariablesCmd implements Command> { protected String planItemInstanceId; - - public GetLocalVariablesCmd(String planItemInstanceId) { + protected Collection variableNames; + + public GetLocalVariablesCmd(String planItemInstanceId, Collection variableNames) { this.planItemInstanceId = planItemInstanceId; + this.variableNames = variableNames; } @Override @@ -42,8 +45,18 @@ public Map execute(CommandContext commandContext) { } CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext); - List variableInstanceEntities = cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService() - .findVariableInstanceBySubScopeIdAndScopeType(planItemInstanceId, ScopeTypes.CMMN); + List variableInstanceEntities; + if (variableNames == null || variableNames.isEmpty()) { + variableInstanceEntities = cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService() + .findVariableInstanceBySubScopeIdAndScopeType(planItemInstanceId, ScopeTypes.CMMN); + } else { + variableInstanceEntities = cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService() + .createInternalVariableInstanceQuery() + .subScopeId(planItemInstanceId) + .scopeType(ScopeTypes.CMMN) + .names(variableNames) + .list(); + } Map variables = new HashMap<>(variableInstanceEntities.size()); for (VariableInstanceEntity variableInstanceEntity : variableInstanceEntities) { variables.put(variableInstanceEntity.getName(), variableInstanceEntity.getValue()); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetVariablesCmd.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetVariablesCmd.java index 1c726bffe7b..a5419b03a65 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetVariablesCmd.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/GetVariablesCmd.java @@ -12,6 +12,7 @@ */ package org.flowable.cmmn.engine.impl.cmd; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,9 +31,11 @@ public class GetVariablesCmd implements Command> { protected String caseInstanceId; - - public GetVariablesCmd(String caseInstanceId) { + protected Collection variableNames; + + public GetVariablesCmd(String caseInstanceId, Collection variableNames) { this.caseInstanceId = caseInstanceId; + this.variableNames = variableNames; } @Override @@ -42,8 +45,20 @@ public Map execute(CommandContext commandContext) { } CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext); - List variableInstanceEntities = cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService() - .findVariableInstanceByScopeIdAndScopeType(caseInstanceId, ScopeTypes.CMMN); + List variableInstanceEntities; + + if (variableNames == null || variableNames.isEmpty()) { + variableInstanceEntities = cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService() + .findVariableInstanceByScopeIdAndScopeType(caseInstanceId, ScopeTypes.CMMN); + } else { + variableInstanceEntities = cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService() + .createInternalVariableInstanceQuery() + .scopeId(caseInstanceId) + .withoutSubScopeId() + .scopeType(ScopeTypes.CMMN) + .names(variableNames) + .list(); + } Map variables = new HashMap<>(variableInstanceEntities.size()); for (VariableInstanceEntity variableInstanceEntity : variableInstanceEntities) { variables.put(variableInstanceEntity.getName(), variableInstanceEntity.getValue()); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CmmnRuntimeServiceImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CmmnRuntimeServiceImpl.java index b8ac2d2da01..d2f458a2497 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CmmnRuntimeServiceImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CmmnRuntimeServiceImpl.java @@ -13,6 +13,7 @@ package org.flowable.cmmn.engine.impl.runtime; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -202,9 +203,14 @@ public void completeUserEventListenerInstance(String userEventListenerInstanceId @Override public Map getVariables(String caseInstanceId) { - return commandExecutor.execute(new GetVariablesCmd(caseInstanceId)); + return commandExecutor.execute(new GetVariablesCmd(caseInstanceId, Collections.emptyList())); } + @Override + public Map getVariables(String caseInstanceId, Collection variableNames) { + return commandExecutor.execute(new GetVariablesCmd(caseInstanceId, variableNames)); + } + @Override public Map getVariableInstances(String caseInstanceId) { return commandExecutor.execute(new GetCaseVariableInstancesCmd(caseInstanceId)); @@ -212,7 +218,12 @@ public Map getVariableInstances(String caseInstanceId) @Override public Map getLocalVariables(String planItemInstanceId) { - return commandExecutor.execute(new GetLocalVariablesCmd(planItemInstanceId)); + return commandExecutor.execute(new GetLocalVariablesCmd(planItemInstanceId, Collections.emptyList())); + } + + @Override + public Map getLocalVariables(String planItemInstanceId, Collection variableNames) { + return commandExecutor.execute(new GetLocalVariablesCmd(planItemInstanceId, variableNames)); } @Override diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/VariablesTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/VariablesTest.java index 310f5464656..c133aae26a6 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/VariablesTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/VariablesTest.java @@ -14,9 +14,11 @@ import static java.util.stream.Collectors.toMap; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -102,6 +104,30 @@ public void testGetVariables() { assertThat(variableInstance).isNull(); } + @Test + @CmmnDeployment(resources = "org/flowable/cmmn/test/runtime/oneHumanTaskCase.cmmn") + public void testGetSpecificVariablesOnly() { + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("oneHumanTaskCase") + .variable("stringVar", "Hello World") + .variable("intVar", 42) + .variable("doubleVar", 10.5) + .start(); + + assertThat(cmmnRuntimeService.getVariables(caseInstance.getId())) + .containsOnly( + entry("stringVar", "Hello World"), + entry("intVar", 42), + entry("doubleVar", 10.5) + ); + + assertThat(cmmnRuntimeService.getVariables(caseInstance.getId(), Arrays.asList("stringVar", "doubleVar", "dummyVar"))) + .containsOnly( + entry("stringVar", "Hello World"), + entry("doubleVar", 10.5) + ); + } + @Test @CmmnDeployment public void testGetLocalVariables() { @@ -148,6 +174,35 @@ public void testGetLocalVariables() { assertThat(variableInstance.getTypeName()).isEqualTo("integer"); } + @Test + @CmmnDeployment(resources = "org/flowable/cmmn/test/runtime/oneHumanTaskCase.cmmn") + public void testGetSpecificLocalVariables() { + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("oneHumanTaskCase") + .variable("stringVar", "Hello World") + .variable("intVar", 42) + .variable("doubleVar", 10.5) + .start(); + + PlanItemInstance planItemInstance = cmmnRuntimeService.createPlanItemInstanceQuery().singleResult(); + cmmnRuntimeService.setLocalVariable(planItemInstance.getId(), "stringVar", "Changed value"); + cmmnRuntimeService.setLocalVariable(planItemInstance.getId(), "intVar", 21); + cmmnRuntimeService.setLocalVariable(planItemInstance.getId(), "doubleVar", 12.6); + + assertThat(cmmnRuntimeService.getLocalVariables(planItemInstance.getId())) + .containsOnly( + entry("stringVar", "Changed value"), + entry("intVar", 21), + entry("doubleVar", 12.6) + ); + + assertThat(cmmnRuntimeService.getLocalVariables(planItemInstance.getId(), Arrays.asList("stringVar", "doubleVar", "dummyVar"))) + .containsOnly( + entry("stringVar", "Changed value"), + entry("doubleVar", 12.6) + ); + } + @Test @CmmnDeployment public void testSetVariables() { diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseVariableResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseVariableResource.java index 5e1674ffb4e..0351592b7db 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseVariableResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseVariableResource.java @@ -80,8 +80,7 @@ protected PlanItemInstance getPlanItemInstanceFromRequest(String planItemInstanc return planItemInstance; } - public RestVariable getVariableFromRequest(CaseInstance caseInstance, String variableName, int variableType, boolean includeBinary) { - Object value = null; + public RestVariable getVariableFromRequest(CaseInstance caseInstance, String variableName, boolean includeBinary) { if (caseInstance == null) { throw new FlowableObjectNotFoundException("Could not find a case instance", CaseInstance.class); @@ -91,19 +90,10 @@ public RestVariable getVariableFromRequest(CaseInstance caseInstance, String var restApiInterceptor.accessCaseInstanceVariable(caseInstance, variableName); } - value = runtimeService.getVariable(caseInstance.getId(), variableName); - - if (value == null) { - throw new FlowableObjectNotFoundException("Case instance '" + caseInstance.getId() + "' doesn't have a variable with name: '" + variableName + "'.", VariableInstance.class); - } else { - //we use null for the scope, because the extraction from request does not require the scope - return constructRestVariable(variableName, value, caseInstance.getId(), variableType, includeBinary, null); - } + return getVariableFromRequestWithoutAccessCheck(caseInstance.getId(), variableName, CmmnRestResponseFactory.VARIABLE_CASE, includeBinary); } - public RestVariable getVariableFromRequest(PlanItemInstance planItemInstance, String variableName, int variableType, boolean includeBinary) { - Object value = null; - + public RestVariable getVariableFromRequest(PlanItemInstance planItemInstance, String variableName, boolean includeBinary) { if (planItemInstance == null) { throw new FlowableObjectNotFoundException("Could not find a plan item instance", CaseInstance.class); } @@ -111,26 +101,43 @@ public RestVariable getVariableFromRequest(PlanItemInstance planItemInstance, St if (restApiInterceptor != null) { restApiInterceptor.accessPlanItemInstanceVariable(planItemInstance, variableName); } + return getVariableFromRequestWithoutAccessCheck(planItemInstance.getId(), variableName, CmmnRestResponseFactory.VARIABLE_PLAN_ITEM, includeBinary); + } - value = runtimeService.getLocalVariable(planItemInstance.getId(), variableName); + protected RestVariable getVariableFromRequestWithoutAccessCheck(String instanceId, String variableName, int variableType, boolean includeBinary) { + Object value = null; - if (value == null) { - throw new FlowableObjectNotFoundException( - "Plan item instance '" + planItemInstance.getId() + "' doesn't have a variable with name: '" + variableName + "'.", - VariableInstance.class); + if (variableType == CmmnRestResponseFactory.VARIABLE_PLAN_ITEM) { + value = runtimeService.getLocalVariable(instanceId, variableName); + } else if (variableType == CmmnRestResponseFactory.VARIABLE_CASE) { + value = runtimeService.getVariable(instanceId, variableName); } else { - //we use null for the scope, because the extraction from request does not require the scope - return constructRestVariable(variableName, value, planItemInstance.getId(), variableType, includeBinary, null); + throw new FlowableIllegalArgumentException("Unknown variable type " + variableType); } + + if (value == null) { + if (variableType == CmmnRestResponseFactory.VARIABLE_PLAN_ITEM) { + throw new FlowableObjectNotFoundException( + "Plan item instance '" + instanceId + "' doesn't have a variable with name: '" + variableName + "'.", + VariableInstance.class); + } else { + throw new FlowableObjectNotFoundException( + "Case instance '" + instanceId + "' doesn't have a variable with name: '" + variableName + "'.", + VariableInstance.class); + } + } + + //we use null for the scope, because the extraction from request does not require the scope + return constructRestVariable(variableName, value, instanceId, variableType, includeBinary, null); } - protected byte[] getVariableDataByteArray(CaseInstance caseInstance, String variableName, int variableType, HttpServletResponse response) { - RestVariable variable = getVariableFromRequest(caseInstance, variableName, variableType, true); + protected byte[] getVariableDataByteArray(CaseInstance caseInstance, String variableName, HttpServletResponse response) { + RestVariable variable = getVariableFromRequest(caseInstance, variableName, true); return restVariableDataToRestResponse(variable, response); } - protected byte[] getVariableDataByteArray(PlanItemInstance planItemInstance, String variableName, int variableType, HttpServletResponse response) { - RestVariable variable = getVariableFromRequest(planItemInstance, variableName, variableType, true); + protected byte[] getVariableDataByteArray(PlanItemInstance planItemInstance, String variableName, HttpServletResponse response) { + RestVariable variable = getVariableFromRequest(planItemInstance, variableName, true); return restVariableDataToRestResponse(variable, response); } @@ -163,22 +170,24 @@ protected RestVariable constructRestVariable(String variableName, Object value, return restResponseFactory.createRestVariable(variableName, value, scope, caseInstanceId, variableType, includeBinary); } - protected List processCaseVariables(CaseInstance caseInstance, int variableType) { + protected List processCaseVariables(CaseInstance caseInstance) { // Check if it's a valid execution to get the variables for - List variables = addVariables(caseInstance, variableType); + List variables = addVariables(caseInstance); // Get unique variables from map List result = new ArrayList<>(variables); return result; } - protected Object createVariable(CaseInstance caseInstance, int variableType, HttpServletRequest request, HttpServletResponse response) { - return createVariable(caseInstance.getId(), variableType, request, response, RestVariableScope.GLOBAL, createVariableInterceptor(caseInstance)); + protected Object createVariable(CaseInstance caseInstance, HttpServletRequest request, HttpServletResponse response) { + return createVariable(caseInstance.getId(), CmmnRestResponseFactory.VARIABLE_CASE, request, response, RestVariableScope.GLOBAL, + createVariableInterceptor(caseInstance)); } - protected Object createVariable(PlanItemInstance planItemInstance, int variableType, HttpServletRequest request, HttpServletResponse response) { - return createVariable(planItemInstance.getId(), variableType, request, response, RestVariableScope.LOCAL, createVariableInterceptor(planItemInstance)); + protected Object createVariable(PlanItemInstance planItemInstance, HttpServletRequest request, HttpServletResponse response) { + return createVariable(planItemInstance.getId(), CmmnRestResponseFactory.VARIABLE_PLAN_ITEM, request, response, RestVariableScope.LOCAL, + createVariableInterceptor(planItemInstance)); } protected Object createVariable(String instanceId, int variableType, HttpServletRequest request, HttpServletResponse response, RestVariableScope scope, @@ -216,15 +225,23 @@ protected Object createVariable(String instanceId, int variableType, HttpServlet Object actualVariableValue = restResponseFactory.getVariableValue(var); variablesToSet.put(var.getName(), actualVariableValue); - resultVariables.add(restResponseFactory.createRestVariable(var.getName(), actualVariableValue, scope, instanceId, variableType, false)); } if (!variablesToSet.isEmpty()) { variableInterceptor.createVariables(variablesToSet); + Map setVariables; if (variableType == CmmnRestResponseFactory.VARIABLE_PLAN_ITEM || scope == RestVariableScope.LOCAL) { runtimeService.setLocalVariables(instanceId, variablesToSet); + setVariables = runtimeService.getLocalVariables(instanceId, variablesToSet.keySet()); } else { runtimeService.setVariables(instanceId, variablesToSet); + setVariables = runtimeService.getVariables(instanceId, variablesToSet.keySet()); + } + + for (RestVariable inputVariable : inputVariables) { + String variableName = inputVariable.getName(); + Object variableValue = setVariables.get(variableName); + resultVariables.add(restResponseFactory.createRestVariable(variableName, variableValue, scope, instanceId, variableType, false)); } } } @@ -232,12 +249,12 @@ protected Object createVariable(String instanceId, int variableType, HttpServlet return result; } - protected List addVariables(CaseInstance caseInstance, int variableType) { + protected List addVariables(CaseInstance caseInstance) { Map rawVariables = runtimeService.getVariables(caseInstance.getId()); if (restApiInterceptor != null) { rawVariables = restApiInterceptor.accessCaseInstanceVariables(caseInstance, rawVariables); } - return restResponseFactory.createRestVariables(rawVariables, caseInstance.getId(), variableType); + return restResponseFactory.createRestVariables(rawVariables, caseInstance.getId(), CmmnRestResponseFactory.VARIABLE_CASE); } public void deleteAllVariables(CaseInstance caseInstance, HttpServletResponse response) { @@ -259,7 +276,10 @@ protected RestVariable setSimpleVariable(RestVariable restVariable, String insta setVariable(instanceId, restVariable.getName(), actualVariableValue, scope, isNew, variableInterceptor); - return constructRestVariable(restVariable.getName(), actualVariableValue, instanceId, variableType, false, scope); + RestVariable variable = getVariableFromRequestWithoutAccessCheck(instanceId, restVariable.getName(), variableType, false); + // We are setting the scope because the fetched variable does not have it + variable.setVariableScope(scope); + return variable; } protected RestVariable setBinaryVariable(MultipartHttpServletRequest request, String instanceId, int responseVariableType, boolean isNew, @@ -332,8 +352,10 @@ protected RestVariable setBinaryVariable(MultipartHttpServletRequest request, St throw new FlowableContentNotSupportedException("Serialized objects are not allowed"); } - - return restResponseFactory.createBinaryRestVariable(variableName, scope, variableType, instanceId, responseVariableType); + RestVariable restVariable = getVariableFromRequestWithoutAccessCheck(instanceId, variableName, responseVariableType, false); + // We are setting the scope because the fetched variable does not have it + restVariable.setVariableScope(scope); + return restVariable; } catch (IOException ioe) { throw new FlowableIllegalArgumentException("Could not process multipart content", ioe); } catch (ClassNotFoundException ioe) { diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableCollectionResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableCollectionResource.java index bd28a7e5e63..6bb63e1d8a2 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableCollectionResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableCollectionResource.java @@ -19,7 +19,6 @@ import javax.servlet.http.HttpServletResponse; import org.flowable.cmmn.api.runtime.CaseInstance; -import org.flowable.cmmn.rest.service.api.CmmnRestResponseFactory; import org.flowable.cmmn.rest.service.api.engine.variable.RestVariable; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -54,7 +53,7 @@ public class CaseInstanceVariableCollectionResource extends BaseVariableResource public List getVariables(@ApiParam(name = "caseInstanceId") @PathVariable String caseInstanceId, HttpServletRequest request) { CaseInstance caseInstance = getCaseInstanceFromRequest(caseInstanceId); - return processCaseVariables(caseInstance, CmmnRestResponseFactory.VARIABLE_CASE); + return processCaseVariables(caseInstance); } @ApiOperation(value = "Update a multiple/single (non)binary variable on a case instance", tags = { "Case Instance Variables" }, nickname = "createOrUpdateCaseVariable", @@ -84,7 +83,7 @@ public List getVariables(@ApiParam(name = "caseInstanceId") @PathV public Object createOrUpdateExecutionVariable(@ApiParam(name = "caseInstanceId") @PathVariable String caseInstanceId, HttpServletRequest request, HttpServletResponse response) { CaseInstance caseInstance = getCaseInstanceFromRequestWithoutAccessCheck(caseInstanceId); - return createVariable(caseInstance, CmmnRestResponseFactory.VARIABLE_CASE, request, response); + return createVariable(caseInstance, request, response); } @ApiOperation(value = "Create variables or new binary variable on a case instance", tags = { "Case Instance Variables" }, nickname = "createCaseInstanceVariable", @@ -114,7 +113,7 @@ public Object createOrUpdateExecutionVariable(@ApiParam(name = "caseInstanceId") @PostMapping(value = "/cmmn-runtime/case-instances/{caseInstanceId}/variables", produces = "application/json", consumes = {"application/json", "multipart/form-data", "text/plain"}) public Object createExecutionVariable(@ApiParam(name = "caseInstanceId") @PathVariable String caseInstanceId, HttpServletRequest request, HttpServletResponse response) { CaseInstance caseInstance = getCaseInstanceFromRequestWithoutAccessCheck(caseInstanceId); - return createVariable(caseInstance, CmmnRestResponseFactory.VARIABLE_CASE, request, response); + return createVariable(caseInstance, request, response); } @ApiOperation(value = "Delete all variables", tags = { "Case Instance Variables" }, nickname = "deleteCaseVariable") diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableDataResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableDataResource.java index f0b1f16f697..39b3487249a 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableDataResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableDataResource.java @@ -17,7 +17,6 @@ import javax.servlet.http.HttpServletResponse; import org.flowable.cmmn.api.runtime.CaseInstance; -import org.flowable.cmmn.rest.service.api.CmmnRestResponseFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -50,6 +49,6 @@ public byte[] getVariableData(@ApiParam(name = "caseInstanceId") @PathVariable(" HttpServletRequest request, HttpServletResponse response) { CaseInstance caseInstance = getCaseInstanceFromRequestWithoutAccessCheck(caseInstanceId); - return getVariableDataByteArray(caseInstance, variableName, CmmnRestResponseFactory.VARIABLE_CASE, response); + return getVariableDataByteArray(caseInstance, variableName, response); } } diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableResource.java index 86ee2b4e99e..50af4ab4a4f 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableResource.java @@ -65,7 +65,7 @@ public RestVariable getVariable(@ApiParam(name = "caseInstanceId") @PathVariable @RequestParam(value = "scope", required = false) String scope, HttpServletRequest request) { CaseInstance caseInstance = getCaseInstanceFromRequestWithoutAccessCheck(caseInstanceId); - return getVariableFromRequest(caseInstance, variableName, CmmnRestResponseFactory.VARIABLE_CASE, false); + return getVariableFromRequest(caseInstance, variableName, false); } @ApiOperation(value = "Update a single variable on a case instance", tags = { "Case Instance Variables" }, nickname = "updateCaseInstanceVariable", diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/PlanItemInstanceVariableDataResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/PlanItemInstanceVariableDataResource.java index f5e8d7e7e5d..f67a4748433 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/PlanItemInstanceVariableDataResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/PlanItemInstanceVariableDataResource.java @@ -17,7 +17,6 @@ import javax.servlet.http.HttpServletResponse; import org.flowable.cmmn.api.runtime.PlanItemInstance; -import org.flowable.cmmn.rest.service.api.CmmnRestResponseFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -51,6 +50,6 @@ public byte[] getVariableData(@ApiParam(name = "planItemInstanceId") @PathVariab HttpServletRequest request, HttpServletResponse response) { PlanItemInstance planItemInstance = getPlanItemInstanceFromRequest(planItemInstanceId); - return getVariableDataByteArray(planItemInstance, variableName, CmmnRestResponseFactory.VARIABLE_PLAN_ITEM, response); + return getVariableDataByteArray(planItemInstance, variableName, response); } } diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/planitem/PlanItemInstanceVariableCollectionResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/planitem/PlanItemInstanceVariableCollectionResource.java index 9ba4a1cf25f..f9647294fe9 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/planitem/PlanItemInstanceVariableCollectionResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/planitem/PlanItemInstanceVariableCollectionResource.java @@ -18,7 +18,6 @@ import org.flowable.cmmn.api.runtime.PlanItemInstance; import org.flowable.cmmn.engine.CmmnEngineConfiguration; -import org.flowable.cmmn.rest.service.api.CmmnRestResponseFactory; import org.flowable.cmmn.rest.service.api.runtime.caze.BaseVariableResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; @@ -74,7 +73,7 @@ public Object createPlanItemInstanceVariable(@ApiParam(name = "planItemInstanceI HttpServletRequest request, HttpServletResponse response) { PlanItemInstance planItem = getPlanItemInstanceFromRequest(planItemInstanceId); - return createVariable(planItem, CmmnRestResponseFactory.VARIABLE_PLAN_ITEM, request, response); + return createVariable(planItem, request, response); } } diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableBaseResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableBaseResource.java index caa916ebb06..517997cd349 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableBaseResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableBaseResource.java @@ -57,13 +57,19 @@ protected void postConstruct() { public RestVariable getVariableFromRequest(String taskId, String variableName, String scope, boolean includeBinary) { Task task = getTaskFromRequestWithoutAccessCheck(taskId); - - boolean variableFound = false; - Object value = null; + RestVariableScope variableScope = RestVariable.getScopeFromString(scope); if (restApiInterceptor != null) { restApiInterceptor.accessTaskVariable(task, variableName); } + return getVariableFromRequestWithoutAccessCheck(task, variableName, variableScope, includeBinary); + } + + public RestVariable getVariableFromRequestWithoutAccessCheck(Task task, String variableName, RestVariableScope variableScope, boolean includeBinary) { + + String taskId = task.getId(); + boolean variableFound = false; + Object value = null; if (variableScope == null) { // First, check local variables (which have precedence when no scope is supplied) @@ -186,7 +192,7 @@ protected RestVariable setBinaryVariable(MultipartHttpServletRequest request, Ta throw new FlowableContentNotSupportedException("Serialized objects are not allowed"); } - return restResponseFactory.createBinaryRestVariable(variableName, scope, variableType, task.getId(), CmmnRestResponseFactory.VARIABLE_TASK); + return getVariableFromRequestWithoutAccessCheck(task, variableName, scope, false); } catch (IOException ioe) { throw new FlowableIllegalArgumentException("Error getting binary variable", ioe); @@ -210,7 +216,7 @@ protected RestVariable setSimpleVariable(RestVariable restVariable, Task task, b Object actualVariableValue = restResponseFactory.getVariableValue(restVariable); setVariable(task, restVariable.getName(), actualVariableValue, scope, isNew); - return restResponseFactory.createRestVariable(restVariable.getName(), actualVariableValue, scope, task.getId(), CmmnRestResponseFactory.VARIABLE_TASK, false); + return getVariableFromRequestWithoutAccessCheck(task, restVariable.getName(), scope, false); } protected void setVariable(Task task, String name, Object value, RestVariableScope scope, boolean isNew) { diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableCollectionResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableCollectionResource.java index 7fd248b9e02..673d9018624 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableCollectionResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableCollectionResource.java @@ -175,25 +175,34 @@ public Object createTaskVariable(@ApiParam(name = "taskId") @PathVariable String Object actualVariableValue = restResponseFactory.getVariableValue(var); variablesToSet.put(var.getName(), actualVariableValue); - resultVariables.add(restResponseFactory.createRestVariable(var.getName(), actualVariableValue, varScope, task.getId(), CmmnRestResponseFactory.VARIABLE_TASK, false)); } if (!variablesToSet.isEmpty()) { if (restApiInterceptor != null) { restApiInterceptor.createTaskVariables(task, variablesToSet, sharedScope); } + + Map setVariables; if (sharedScope == RestVariableScope.LOCAL) { taskService.setVariablesLocal(task.getId(), variablesToSet); + setVariables = taskService.getVariablesLocal(task.getId(), variablesToSet.keySet()); } else { if (task.getScopeId() != null) { // Explicitly set on case, setting non-local // variables on task will override local-variables if exists runtimeService.setVariables(task.getScopeId(), variablesToSet); + setVariables = runtimeService.getVariables(task.getScopeId(), variablesToSet.keySet()); } else { // Standalone task, no global variables possible throw new FlowableIllegalArgumentException("Cannot set global variables on task '" + task.getId() + "', task is not part of process."); } } + + for (RestVariable inputVariable : inputVariables) { + String variableName = inputVariable.getName(); + Object variableValue = setVariables.get(variableName); + resultVariables.add(restResponseFactory.createRestVariable(variableName, variableValue, varScope, task.getId(), CmmnRestResponseFactory.VARIABLE_TASK, false)); + } } } diff --git a/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceVariableResourceTest.java b/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceVariableResourceTest.java index 981e04a329b..b412aeac82c 100644 --- a/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceVariableResourceTest.java +++ b/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceVariableResourceTest.java @@ -316,7 +316,7 @@ public void testUpdateInstantProcessVariable() throws Exception { assertThatJson(responseNode) .when(Option.IGNORING_EXTRA_FIELDS) .isEqualTo("{" - + " value: '2019-12-13T12:32:45.583345Z'" + + " value: '2019-12-13T12:32:45.583Z'" + "}"); } diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseExecutionVariableResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseExecutionVariableResource.java index 6c5a2fcc131..9b54c456f9e 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseExecutionVariableResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseExecutionVariableResource.java @@ -59,6 +59,12 @@ public class BaseExecutionVariableResource { protected boolean isSerializableVariableAllowed; + protected final int variableType; + + public BaseExecutionVariableResource(int variableType) { + this.variableType = variableType; + } + @PostConstruct protected void postConstruct() { isSerializableVariableAllowed = env.getProperty("rest.variables.allow.serializable", Boolean.class, true); @@ -93,7 +99,7 @@ protected byte[] getVariableDataByteArray(Execution execution, String variableNa } } - protected RestVariable setBinaryVariable(MultipartHttpServletRequest request, Execution execution, int responseVariableType, boolean isNew) { + protected RestVariable setBinaryVariable(MultipartHttpServletRequest request, Execution execution, boolean isNew) { // Validate input and set defaults if (request.getFileMap().size() == 0) { @@ -163,11 +169,10 @@ protected RestVariable setBinaryVariable(MultipartHttpServletRequest request, Ex throw new FlowableContentNotSupportedException("Serialized objects are not allowed"); } - if (responseVariableType == RestResponseFactory.VARIABLE_PROCESS) { - return restResponseFactory.createBinaryRestVariable(variableName, scope, variableType, null, null, execution.getId()); - } else { - return restResponseFactory.createBinaryRestVariable(variableName, scope, variableType, null, execution.getId(), null); - } + RestVariable variable = getVariableFromRequestWithoutAccessCheck(execution, variableName, scope, false); + // We are setting the scope because the fetched variable does not have it + variable.setVariableScope(scope); + return variable; } catch (IOException ioe) { throw new FlowableIllegalArgumentException("Could not process multipart content", ioe); @@ -191,7 +196,10 @@ protected RestVariable setSimpleVariable(RestVariable restVariable, Execution ex Object actualVariableValue = restResponseFactory.getVariableValue(restVariable); setVariable(execution, restVariable.getName(), actualVariableValue, scope, isNew); - return constructRestVariable(restVariable.getName(), actualVariableValue, scope, execution.getId(), false); + RestVariable variable = getVariableFromRequestWithoutAccessCheck(execution, restVariable.getName(), scope, false); + // We are setting the scope because the fetched variable does not always have it + variable.setVariableScope(scope); + return variable; } protected void setVariable(Execution execution, String name, Object value, RestVariableScope scope, boolean isNew) { @@ -243,9 +251,6 @@ protected boolean hasVariableOnScope(Execution execution, String variableName, R public RestVariable getVariableFromRequest(Execution execution, String variableName, String scope, boolean includeBinary) { - boolean variableFound = false; - Object value = null; - if (execution == null) { throw new FlowableObjectNotFoundException("Could not find an execution", Execution.class); } @@ -255,6 +260,14 @@ public RestVariable getVariableFromRequest(Execution execution, String variableN restApiInterceptor.accessExecutionVariable(execution, variableName, scope); } + return getVariableFromRequestWithoutAccessCheck(execution, variableName, variableScope, includeBinary); + } + + public RestVariable getVariableFromRequestWithoutAccessCheck(Execution execution, String variableName, RestVariableScope variableScope, boolean includeBinary) { + + boolean variableFound = false; + Object value = null; + if (variableScope == null) { // First, check local variables (which have precedence when no scope // is supplied) @@ -292,7 +305,7 @@ public RestVariable getVariableFromRequest(Execution execution, String variableN protected RestVariable constructRestVariable(String variableName, Object value, RestVariableScope variableScope, String executionId, boolean includeBinary) { - return restResponseFactory.createRestVariable(variableName, value, variableScope, executionId, RestResponseFactory.VARIABLE_EXECUTION, includeBinary); + return restResponseFactory.createRestVariable(variableName, value, variableScope, executionId, variableType, includeBinary); } protected Execution getExecutionFromRequestWithoutAccessCheck(String executionId) { diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseVariableCollectionResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseVariableCollectionResource.java index 617c75c8c70..62da0e1530e 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseVariableCollectionResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseVariableCollectionResource.java @@ -41,7 +41,11 @@ public class BaseVariableCollectionResource extends BaseExecutionVariableResourc @Autowired protected ObjectMapper objectMapper; - protected List processVariables(Execution execution, String scope, int variableType) { + public BaseVariableCollectionResource(int variableType) { + super(variableType); + } + + protected List processVariables(Execution execution, String scope) { Map variableMap = new HashMap<>(); // Check if it's a valid execution to get the variables for @@ -49,14 +53,14 @@ protected List processVariables(Execution execution, String scope, if (variableScope == null) { // Use both local and global variables - addLocalVariables(execution, variableType, variableMap); - addGlobalVariables(execution, variableType, variableMap); + addLocalVariables(execution, variableMap); + addGlobalVariables(execution, variableMap); } else if (variableScope == RestVariableScope.GLOBAL) { - addGlobalVariables(execution, variableType, variableMap); + addGlobalVariables(execution, variableMap); } else if (variableScope == RestVariableScope.LOCAL) { - addLocalVariables(execution, variableType, variableMap); + addLocalVariables(execution, variableMap); } if (restApiInterceptor != null) { @@ -78,11 +82,11 @@ public void deleteAllLocalVariables(Execution execution, HttpServletResponse res response.setStatus(HttpStatus.NO_CONTENT.value()); } - protected Object createExecutionVariable(Execution execution, boolean override, int variableType, HttpServletRequest request, HttpServletResponse response) { + protected Object createExecutionVariable(Execution execution, boolean override, HttpServletRequest request, HttpServletResponse response) { Object result = null; if (request instanceof MultipartHttpServletRequest) { - result = setBinaryVariable((MultipartHttpServletRequest) request, execution, variableType, true); + result = setBinaryVariable((MultipartHttpServletRequest) request, execution, true); } else { List inputVariables = new ArrayList<>(); @@ -131,7 +135,6 @@ protected Object createExecutionVariable(Execution execution, boolean override, Object actualVariableValue = restResponseFactory.getVariableValue(var); variablesToSet.put(var.getName(), actualVariableValue); - resultVariables.add(restResponseFactory.createRestVariable(var.getName(), actualVariableValue, varScope, execution.getId(), variableType, false)); } if (!variablesToSet.isEmpty()) { @@ -139,26 +142,36 @@ protected Object createExecutionVariable(Execution execution, boolean override, restApiInterceptor.createExecutionVariables(execution, variablesToSet, sharedScope); } + Map setVariables; if (sharedScope == RestVariableScope.LOCAL) { runtimeService.setVariablesLocal(execution.getId(), variablesToSet); + setVariables = runtimeService.getVariablesLocal(execution.getId(), variablesToSet.keySet()); } else { if (execution.getParentId() != null) { // Explicitly set on parent, setting non-local variables // on execution itself will override local-variables if // exists runtimeService.setVariables(execution.getParentId(), variablesToSet); + setVariables = runtimeService.getVariables(execution.getParentId(), variablesToSet.keySet()); } else { // Standalone task, no global variables possible throw new FlowableIllegalArgumentException("Cannot set global variables on execution '" + execution.getId() + "', task is not part of process."); } } + + for (RestVariable inputVariable : inputVariables) { + String variableName = inputVariable.getName(); + Object variableValue = setVariables.get(variableName); + resultVariables.add(restResponseFactory.createRestVariable(variableName, variableValue, varScope, execution.getId(), variableType, false)); + } + } } response.setStatus(HttpStatus.CREATED.value()); return result; } - protected void addGlobalVariables(Execution execution, int variableType, Map variableMap) { + protected void addGlobalVariables(Execution execution, Map variableMap) { Map rawVariables = runtimeService.getVariables(execution.getId()); List globalVariables = restResponseFactory.createRestVariables(rawVariables, execution.getId(), variableType, RestVariableScope.GLOBAL); @@ -172,7 +185,7 @@ protected void addGlobalVariables(Execution execution, int variableType, Map variableMap) { + protected void addLocalVariables(Execution execution, Map variableMap) { Map rawLocalvariables = runtimeService.getVariablesLocal(execution.getId()); List localVariables = restResponseFactory.createRestVariables(rawLocalvariables, execution.getId(), variableType, RestVariableScope.LOCAL); diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableCollectionResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableCollectionResource.java index 9f1b746f923..21760695636 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableCollectionResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableCollectionResource.java @@ -45,6 +45,10 @@ @Api(tags = { "Executions" }, description = "Manage Executions", authorizations = { @Authorization(value = "basicAuth") }) public class ExecutionVariableCollectionResource extends BaseVariableCollectionResource { + public ExecutionVariableCollectionResource() { + super(RestResponseFactory.VARIABLE_EXECUTION); + } + @ApiOperation(value = "List variables for an execution", tags = { "Executions" }, nickname = "listExecutionVariables") @ApiResponses(value = { @ApiResponse(code = 200, message = "Indicates the execution was found and variables are returned."), @@ -54,7 +58,7 @@ public class ExecutionVariableCollectionResource extends BaseVariableCollectionR public List getVariables(@ApiParam(name = "executionId") @PathVariable String executionId, @RequestParam(value = "scope", required = false) String scope, HttpServletRequest request) { Execution execution = getExecutionFromRequestWithoutAccessCheck(executionId); - return processVariables(execution, scope, RestResponseFactory.VARIABLE_EXECUTION); + return processVariables(execution, scope); } // FIXME OASv3 to solve Multiple Endpoint issue @@ -81,7 +85,7 @@ public List getVariables(@ApiParam(name = "executionId") @PathVari public Object createOrUpdateExecutionVariable(@ApiParam(name = "executionId") @PathVariable String executionId, HttpServletRequest request, HttpServletResponse response) { Execution execution = getExecutionFromRequestWithoutAccessCheck(executionId); - return createExecutionVariable(execution, true, RestResponseFactory.VARIABLE_EXECUTION, request, response); + return createExecutionVariable(execution, true, request, response); } // FIXME OASv3 to solve Multiple Endpoint issue @@ -110,7 +114,7 @@ public Object createOrUpdateExecutionVariable(@ApiParam(name = "executionId") @P public Object createExecutionVariable(@ApiParam(name = "executionId") @PathVariable String executionId, HttpServletRequest request, HttpServletResponse response) { Execution execution = getExecutionFromRequestWithoutAccessCheck(executionId); - return createExecutionVariable(execution, false, RestResponseFactory.VARIABLE_EXECUTION, request, response); + return createExecutionVariable(execution, false, request, response); } @ApiOperation(value = "Delete all variables for an execution", tags = { "Executions" }) diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableDataResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableDataResource.java index dad938285db..5ab13a7edfa 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableDataResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableDataResource.java @@ -45,6 +45,10 @@ @Api(tags = { "Executions" }, description = "Manage Executions", authorizations = { @Authorization(value = "basicAuth") }) public class ExecutionVariableDataResource extends BaseExecutionVariableResource { + public ExecutionVariableDataResource() { + super(RestResponseFactory.VARIABLE_EXECUTION); + } + @ApiOperation(value = "Get the binary data for an execution", tags = { "Executions" }, nickname = "getExecutionVariableData") @ApiResponses(value = { @ApiResponse(code = 200, message = "Indicates the execution was found and the requested variables are returned."), diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableResource.java index 9895bbaadb4..9a674844dc9 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableResource.java @@ -57,6 +57,10 @@ public class ExecutionVariableResource extends BaseExecutionVariableResource { @Autowired protected ObjectMapper objectMapper; + public ExecutionVariableResource() { + super(RestResponseFactory.VARIABLE_EXECUTION); + } + @ApiOperation(value = "Get a variable for an execution", tags = { "Executions" }, nickname = "getExecutionVariable") @ApiResponses(value = { @ApiResponse(code = 200, message = "Indicates both the execution and variable were found and variable is returned."), @@ -100,7 +104,7 @@ public RestVariable updateVariable(@ApiParam(name = "executionId") @PathVariable RestVariable result = null; if (request instanceof MultipartHttpServletRequest) { - result = setBinaryVariable((MultipartHttpServletRequest) request, execution, RestResponseFactory.VARIABLE_EXECUTION, false); + result = setBinaryVariable((MultipartHttpServletRequest) request, execution, false); if (!result.getName().equals(variableName)) { throw new FlowableIllegalArgumentException("Variable name in the body should be equal to the name used in the requested URL."); diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableCollectionResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableCollectionResource.java index 527cb58bf2f..6f96d18c008 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableCollectionResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableCollectionResource.java @@ -47,6 +47,10 @@ @Api(tags = { "Process Instance Variables" }, description = "Manage Process Instances Variables", authorizations = { @Authorization(value = "basicAuth") }) public class ProcessInstanceVariableCollectionResource extends BaseVariableCollectionResource { + public ProcessInstanceVariableCollectionResource() { + super(RestResponseFactory.VARIABLE_PROCESS); + } + @ApiOperation(value = "List variables for a process instance", nickname="listProcessInstanceVariables", tags = {"Process Instance Variables" }, notes = "In case the variable is a binary variable or serializable, the valueUrl points to an URL to fetch the raw value. If it’s a plain variable, the value is present in the response. Note that only local scoped variables are returned, as there is no global scope for process-instance variables.") @ApiResponses(value = { @@ -57,7 +61,7 @@ public class ProcessInstanceVariableCollectionResource extends BaseVariableColle public List getVariables(@ApiParam(name = "processInstanceId") @PathVariable String processInstanceId, @RequestParam(value = "scope", required = false) String scope, HttpServletRequest request) { Execution execution = getExecutionFromRequestWithoutAccessCheck(processInstanceId); - return processVariables(execution, scope, RestResponseFactory.VARIABLE_PROCESS); + return processVariables(execution, scope); } // FIXME OASv3 to solve Multiple Endpoint issue @@ -88,7 +92,7 @@ public List getVariables(@ApiParam(name = "processInstanceId") @Pa public Object createOrUpdateExecutionVariable(@ApiParam(name = "processInstanceId") @PathVariable String processInstanceId, HttpServletRequest request, HttpServletResponse response) { Execution execution = getExecutionFromRequestWithoutAccessCheck(processInstanceId); - return createExecutionVariable(execution, true, RestResponseFactory.VARIABLE_PROCESS, request, response); + return createExecutionVariable(execution, true, request, response); } // FIXME OASv3 to solve Multiple Endpoint issue @@ -119,7 +123,7 @@ public Object createOrUpdateExecutionVariable(@ApiParam(name = "processInstanceI public Object createExecutionVariable(@ApiParam(name = "processInstanceId") @PathVariable String processInstanceId, HttpServletRequest request, HttpServletResponse response) { Execution execution = getExecutionFromRequestWithoutAccessCheck(processInstanceId); - return createExecutionVariable(execution, false, RestResponseFactory.VARIABLE_PROCESS, request, response); + return createExecutionVariable(execution, false, request, response); } // FIXME Documentation @@ -135,14 +139,14 @@ public void deleteLocalVariables(@ApiParam(name = "processInstanceId") @PathVari } @Override - protected void addGlobalVariables(Execution execution, int variableType, Map variableMap) { + protected void addGlobalVariables(Execution execution, Map variableMap) { // no global variables } // For process instance there's only one scope. Using the local variables // method for that @Override - protected void addLocalVariables(Execution execution, int variableType, Map variableMap) { + protected void addLocalVariables(Execution execution, Map variableMap) { Map rawVariables = runtimeService.getVariables(execution.getId()); List globalVariables = restResponseFactory.createRestVariables(rawVariables, execution.getId(), variableType, RestVariableScope.LOCAL); diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableDataResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableDataResource.java index aa73bb04f3e..a6ce5da3a65 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableDataResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableDataResource.java @@ -17,6 +17,7 @@ import javax.servlet.http.HttpServletResponse; import org.flowable.engine.runtime.Execution; +import org.flowable.rest.service.api.RestResponseFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -37,6 +38,10 @@ @Api(tags = { "Process Instance Variables" }, description = "Manage Process Instances Variables", authorizations = { @Authorization(value = "basicAuth") }) public class ProcessInstanceVariableDataResource extends BaseExecutionVariableResource { + public ProcessInstanceVariableDataResource() { + super(RestResponseFactory.VARIABLE_PROCESS); + } + @ApiOperation(value = "Get the binary data for a variable", tags = { "Process Instance Variables" }, nickname = "getProcessInstanceVariableData") @ApiResponses(value = { @ApiResponse(code = 200, message = "Indicates the process instance was found and the requested variables are returned."), diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableResource.java index def121c92ee..fea3295fdd6 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableResource.java @@ -57,6 +57,10 @@ public class ProcessInstanceVariableResource extends BaseExecutionVariableResour @Autowired protected ObjectMapper objectMapper; + public ProcessInstanceVariableResource() { + super(RestResponseFactory.VARIABLE_PROCESS); + } + @ApiOperation(value = "Get a variable for a process instance", tags = { "Process Instance Variables" }, nickname = "getProcessInstanceVariable") @ApiResponses(value = { @ApiResponse(code = 200, message = "Indicates both the process instance and variable were found and variable is returned."), @@ -98,7 +102,7 @@ public RestVariable updateVariable(@ApiParam(name = "processInstanceId") @PathVa RestVariable result = null; if (request instanceof MultipartHttpServletRequest) { - result = setBinaryVariable((MultipartHttpServletRequest) request, execution, RestResponseFactory.VARIABLE_PROCESS, false); + result = setBinaryVariable((MultipartHttpServletRequest) request, execution, false); if (!result.getName().equals(variableName)) { throw new FlowableIllegalArgumentException("Variable name in the body should be equal to the name used in the requested URL."); diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableBaseResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableBaseResource.java index c2246716051..67160bfc0f9 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableBaseResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableBaseResource.java @@ -60,7 +60,12 @@ public RestVariable getVariableFromRequest(String taskId, String variableName, S if (restApiInterceptor != null) { restApiInterceptor.accessTaskVariable(task, variableName); } + return getVariableFromRequestWithoutAccessCheck(task, variableName, scope, includeBinary); + } + + public RestVariable getVariableFromRequestWithoutAccessCheck(Task task, String variableName, String scope, boolean includeBinary) { + String taskId = task.getId(); boolean variableFound = false; Object value = null; RestVariableScope variableScope = RestVariable.getScopeFromString(scope); @@ -186,7 +191,7 @@ protected RestVariable setBinaryVariable(MultipartHttpServletRequest request, Ta throw new FlowableContentNotSupportedException("Serialized objects are not allowed"); } - return restResponseFactory.createBinaryRestVariable(variableName, scope, variableType, task.getId(), null, null); + return getVariableFromRequestWithoutAccessCheck(task, variableName, scope.name(), false); } catch (IOException ioe) { throw new FlowableIllegalArgumentException("Error getting binary variable", ioe); @@ -210,7 +215,7 @@ protected RestVariable setSimpleVariable(RestVariable restVariable, Task task, b Object actualVariableValue = restResponseFactory.getVariableValue(restVariable); setVariable(task, restVariable.getName(), actualVariableValue, scope, isNew); - return restResponseFactory.createRestVariable(restVariable.getName(), actualVariableValue, scope, task.getId(), RestResponseFactory.VARIABLE_TASK, false); + return getVariableFromRequestWithoutAccessCheck(task, restVariable.getName(), scope.name(), false); } protected void setVariable(Task task, String name, Object value, RestVariableScope scope, boolean isNew) { diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableCollectionResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableCollectionResource.java index b870369942a..9aaba76cca1 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableCollectionResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableCollectionResource.java @@ -174,26 +174,35 @@ public Object createTaskVariable(@ApiParam(name = "taskId") @PathVariable String Object actualVariableValue = restResponseFactory.getVariableValue(var); variablesToSet.put(var.getName(), actualVariableValue); - resultVariables.add(restResponseFactory.createRestVariable(var.getName(), actualVariableValue, varScope, task.getId(), RestResponseFactory.VARIABLE_TASK, false)); } if (!variablesToSet.isEmpty()) { if (restApiInterceptor != null) { restApiInterceptor.createTaskVariables(task, variablesToSet, sharedScope); } + + Map setVariables; if (sharedScope == RestVariableScope.LOCAL) { taskService.setVariablesLocal(task.getId(), variablesToSet); + setVariables = taskService.getVariablesLocal(task.getId(), variablesToSet.keySet()); } else { if (task.getExecutionId() != null) { // Explicitly set on execution, setting non-local // variables on task will override local-variables if // exists runtimeService.setVariables(task.getExecutionId(), variablesToSet); + setVariables = runtimeService.getVariables(task.getExecutionId(), variablesToSet.keySet()); } else { // Standalone task, no global variables possible throw new FlowableIllegalArgumentException("Cannot set global variables on task '" + task.getId() + "', task is not part of process."); } } + + for (RestVariable inputVariable : inputVariables) { + String variableName = inputVariable.getName(); + Object variableValue = setVariables.get(variableName); + resultVariables.add(restResponseFactory.createRestVariable(variableName, variableValue, varScope, task.getId(), RestResponseFactory.VARIABLE_TASK, false)); + } } } diff --git a/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceVariableResourceTest.java b/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceVariableResourceTest.java index 1ffbfcf1af3..a5c20d44291 100644 --- a/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceVariableResourceTest.java +++ b/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceVariableResourceTest.java @@ -342,7 +342,7 @@ public void testUpdateInstantProcessVariable() throws Exception { assertThatJson(responseNode) .when(Option.IGNORING_EXTRA_FIELDS) .isEqualTo("{" - + " value: '2019-12-13T12:32:45.583345Z'" + + " value: '2019-12-13T12:32:45.583Z'" + "}"); }